xref: /rk3399_ARM-atf/drivers/nxp/clk/s32cc/s32cc_clk_drv.c (revision 2710bdadc4cefd45bb7056c7e4c1e20dd1dfddc4)
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;
2729f8a952SGhennadi Procopciuc 	uintptr_t periphdfs_base;
289dbca85dSGhennadi Procopciuc 	uintptr_t cgm0_base;
297004f678SGhennadi Procopciuc 	uintptr_t cgm1_base;
308a4f840bSGhennadi Procopciuc 	uintptr_t cgm5_base;
3118c2b137SGhennadi Procopciuc 	uintptr_t ddrpll_base;
328a4f840bSGhennadi Procopciuc 	uintptr_t mc_me;
338a4f840bSGhennadi Procopciuc 	uintptr_t mc_rgm;
348a4f840bSGhennadi Procopciuc 	uintptr_t rdc;
358ab34357SGhennadi Procopciuc };
368ab34357SGhennadi Procopciuc 
372fb25509SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
382fb25509SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
392fb25509SGhennadi Procopciuc 			   unsigned int *depth);
402fb25509SGhennadi Procopciuc static int get_module_rate(const struct s32cc_clk_obj *module,
412fb25509SGhennadi Procopciuc 			   const struct s32cc_clk_drv *drv,
422fb25509SGhennadi Procopciuc 			   unsigned long *rate,
432fb25509SGhennadi Procopciuc 			   unsigned int depth);
442fb25509SGhennadi Procopciuc 
45d9373519SGhennadi Procopciuc static int update_stack_depth(unsigned int *depth)
46d9373519SGhennadi Procopciuc {
47d9373519SGhennadi Procopciuc 	if (*depth == 0U) {
48d9373519SGhennadi Procopciuc 		return -ENOMEM;
49d9373519SGhennadi Procopciuc 	}
50d9373519SGhennadi Procopciuc 
51d9373519SGhennadi Procopciuc 	(*depth)--;
52d9373519SGhennadi Procopciuc 	return 0;
53d9373519SGhennadi Procopciuc }
543a580e9eSGhennadi Procopciuc 
558ab34357SGhennadi Procopciuc static struct s32cc_clk_drv *get_drv(void)
568ab34357SGhennadi Procopciuc {
578ab34357SGhennadi Procopciuc 	static struct s32cc_clk_drv driver = {
588ab34357SGhennadi Procopciuc 		.fxosc_base = FXOSC_BASE_ADDR,
59b5101c45SGhennadi Procopciuc 		.armpll_base = ARMPLL_BASE_ADDR,
608653352aSGhennadi Procopciuc 		.periphpll_base = PERIPHPLL_BASE_ADDR,
614cd04c50SGhennadi Procopciuc 		.armdfs_base = ARM_DFS_BASE_ADDR,
6229f8a952SGhennadi Procopciuc 		.periphdfs_base = PERIPH_DFS_BASE_ADDR,
639dbca85dSGhennadi Procopciuc 		.cgm0_base = CGM0_BASE_ADDR,
647004f678SGhennadi Procopciuc 		.cgm1_base = CGM1_BASE_ADDR,
658a4f840bSGhennadi Procopciuc 		.cgm5_base = MC_CGM5_BASE_ADDR,
6618c2b137SGhennadi Procopciuc 		.ddrpll_base = DDRPLL_BASE_ADDR,
678a4f840bSGhennadi Procopciuc 		.mc_me = MC_ME_BASE_ADDR,
688a4f840bSGhennadi Procopciuc 		.mc_rgm = MC_RGM_BASE_ADDR,
698a4f840bSGhennadi Procopciuc 		.rdc = RDC_BASE_ADDR,
708ab34357SGhennadi Procopciuc 	};
718ab34357SGhennadi Procopciuc 
728ab34357SGhennadi Procopciuc 	return &driver;
738ab34357SGhennadi Procopciuc }
748ab34357SGhennadi Procopciuc 
755300040bSGhennadi Procopciuc static int enable_module(struct s32cc_clk_obj *module,
765300040bSGhennadi Procopciuc 			 const struct s32cc_clk_drv *drv,
775300040bSGhennadi Procopciuc 			 unsigned int depth);
788ab34357SGhennadi Procopciuc 
7996e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_clk_parent(const struct s32cc_clk_obj *module)
8096e069cbSGhennadi Procopciuc {
8196e069cbSGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
8296e069cbSGhennadi Procopciuc 
8396e069cbSGhennadi Procopciuc 	if (clk->module != NULL) {
8496e069cbSGhennadi Procopciuc 		return clk->module;
8596e069cbSGhennadi Procopciuc 	}
8696e069cbSGhennadi Procopciuc 
8796e069cbSGhennadi Procopciuc 	if (clk->pclock != NULL) {
8896e069cbSGhennadi Procopciuc 		return &clk->pclock->desc;
8996e069cbSGhennadi Procopciuc 	}
9096e069cbSGhennadi Procopciuc 
9196e069cbSGhennadi Procopciuc 	return NULL;
9296e069cbSGhennadi Procopciuc }
9396e069cbSGhennadi Procopciuc 
94b5101c45SGhennadi Procopciuc static int get_base_addr(enum s32cc_clk_source id, const struct s32cc_clk_drv *drv,
95b5101c45SGhennadi Procopciuc 			 uintptr_t *base)
96b5101c45SGhennadi Procopciuc {
97b5101c45SGhennadi Procopciuc 	int ret = 0;
98b5101c45SGhennadi Procopciuc 
99b5101c45SGhennadi Procopciuc 	switch (id) {
100b5101c45SGhennadi Procopciuc 	case S32CC_FXOSC:
101b5101c45SGhennadi Procopciuc 		*base = drv->fxosc_base;
102b5101c45SGhennadi Procopciuc 		break;
103b5101c45SGhennadi Procopciuc 	case S32CC_ARM_PLL:
104b5101c45SGhennadi Procopciuc 		*base = drv->armpll_base;
105b5101c45SGhennadi Procopciuc 		break;
1068653352aSGhennadi Procopciuc 	case S32CC_PERIPH_PLL:
1078653352aSGhennadi Procopciuc 		*base = drv->periphpll_base;
1088653352aSGhennadi Procopciuc 		break;
10918c2b137SGhennadi Procopciuc 	case S32CC_DDR_PLL:
11018c2b137SGhennadi Procopciuc 		*base = drv->ddrpll_base;
11118c2b137SGhennadi Procopciuc 		break;
1124cd04c50SGhennadi Procopciuc 	case S32CC_ARM_DFS:
1134cd04c50SGhennadi Procopciuc 		*base = drv->armdfs_base;
1144cd04c50SGhennadi Procopciuc 		break;
11529f8a952SGhennadi Procopciuc 	case S32CC_PERIPH_DFS:
11629f8a952SGhennadi Procopciuc 		*base = drv->periphdfs_base;
11729f8a952SGhennadi Procopciuc 		break;
1189dbca85dSGhennadi Procopciuc 	case S32CC_CGM0:
1199dbca85dSGhennadi Procopciuc 		*base = drv->cgm0_base;
1209dbca85dSGhennadi Procopciuc 		break;
121b5101c45SGhennadi Procopciuc 	case S32CC_CGM1:
1227004f678SGhennadi Procopciuc 		*base = drv->cgm1_base;
123b5101c45SGhennadi Procopciuc 		break;
1248a4f840bSGhennadi Procopciuc 	case S32CC_CGM5:
1258a4f840bSGhennadi Procopciuc 		*base = drv->cgm5_base;
1268a4f840bSGhennadi Procopciuc 		break;
127b5101c45SGhennadi Procopciuc 	case S32CC_FIRC:
128b5101c45SGhennadi Procopciuc 		break;
129b5101c45SGhennadi Procopciuc 	case S32CC_SIRC:
130b5101c45SGhennadi Procopciuc 		break;
131b5101c45SGhennadi Procopciuc 	default:
132b5101c45SGhennadi Procopciuc 		ret = -EINVAL;
133b5101c45SGhennadi Procopciuc 		break;
134b5101c45SGhennadi Procopciuc 	}
135b5101c45SGhennadi Procopciuc 
136b5101c45SGhennadi Procopciuc 	if (ret != 0) {
137b5101c45SGhennadi Procopciuc 		ERROR("Unknown clock source id: %u\n", id);
138b5101c45SGhennadi Procopciuc 	}
139b5101c45SGhennadi Procopciuc 
140b5101c45SGhennadi Procopciuc 	return ret;
141b5101c45SGhennadi Procopciuc }
142b5101c45SGhennadi Procopciuc 
1438ab34357SGhennadi Procopciuc static void enable_fxosc(const struct s32cc_clk_drv *drv)
1448ab34357SGhennadi Procopciuc {
1458ab34357SGhennadi Procopciuc 	uintptr_t fxosc_base = drv->fxosc_base;
1468ab34357SGhennadi Procopciuc 	uint32_t ctrl;
1478ab34357SGhennadi Procopciuc 
1488ab34357SGhennadi Procopciuc 	ctrl = mmio_read_32(FXOSC_CTRL(fxosc_base));
1498ab34357SGhennadi Procopciuc 	if ((ctrl & FXOSC_CTRL_OSCON) != U(0)) {
1508ab34357SGhennadi Procopciuc 		return;
1518ab34357SGhennadi Procopciuc 	}
1528ab34357SGhennadi Procopciuc 
1538ab34357SGhennadi Procopciuc 	ctrl = FXOSC_CTRL_COMP_EN;
1548ab34357SGhennadi Procopciuc 	ctrl &= ~FXOSC_CTRL_OSC_BYP;
1558ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_EOCV(0x1);
1568ab34357SGhennadi Procopciuc 	ctrl |= FXOSC_CTRL_GM_SEL(0x7);
1578ab34357SGhennadi Procopciuc 	mmio_write_32(FXOSC_CTRL(fxosc_base), ctrl);
1588ab34357SGhennadi Procopciuc 
1598ab34357SGhennadi Procopciuc 	/* Switch ON the crystal oscillator. */
1608ab34357SGhennadi Procopciuc 	mmio_setbits_32(FXOSC_CTRL(fxosc_base), FXOSC_CTRL_OSCON);
1618ab34357SGhennadi Procopciuc 
1628ab34357SGhennadi Procopciuc 	/* Wait until the clock is stable. */
1638ab34357SGhennadi Procopciuc 	while ((mmio_read_32(FXOSC_STAT(fxosc_base)) & FXOSC_STAT_OSC_STAT) == U(0)) {
1648ab34357SGhennadi Procopciuc 	}
1658ab34357SGhennadi Procopciuc }
1668ab34357SGhennadi Procopciuc 
1675300040bSGhennadi Procopciuc static int enable_osc(struct s32cc_clk_obj *module,
1688ab34357SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
1695300040bSGhennadi Procopciuc 		      unsigned int depth)
1708ab34357SGhennadi Procopciuc {
1718ab34357SGhennadi Procopciuc 	const struct s32cc_osc *osc = s32cc_obj2osc(module);
1728ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
1738ab34357SGhennadi Procopciuc 	int ret = 0;
1748ab34357SGhennadi Procopciuc 
1758ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1768ab34357SGhennadi Procopciuc 	if (ret != 0) {
1778ab34357SGhennadi Procopciuc 		return ret;
1788ab34357SGhennadi Procopciuc 	}
1798ab34357SGhennadi Procopciuc 
1808ab34357SGhennadi Procopciuc 	switch (osc->source) {
1818ab34357SGhennadi Procopciuc 	case S32CC_FXOSC:
1828ab34357SGhennadi Procopciuc 		enable_fxosc(drv);
1838ab34357SGhennadi Procopciuc 		break;
1848ab34357SGhennadi Procopciuc 	/* FIRC and SIRC oscillators are enabled by default */
1858ab34357SGhennadi Procopciuc 	case S32CC_FIRC:
1868ab34357SGhennadi Procopciuc 		break;
1878ab34357SGhennadi Procopciuc 	case S32CC_SIRC:
1888ab34357SGhennadi Procopciuc 		break;
1898ab34357SGhennadi Procopciuc 	default:
1908ab34357SGhennadi Procopciuc 		ERROR("Invalid oscillator %d\n", osc->source);
1918ab34357SGhennadi Procopciuc 		ret = -EINVAL;
1928ab34357SGhennadi Procopciuc 		break;
1938ab34357SGhennadi Procopciuc 	};
1948ab34357SGhennadi Procopciuc 
1958ab34357SGhennadi Procopciuc 	return ret;
1968ab34357SGhennadi Procopciuc }
1978ab34357SGhennadi Procopciuc 
19896e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_pll_parent(const struct s32cc_clk_obj *module)
19996e069cbSGhennadi Procopciuc {
20096e069cbSGhennadi Procopciuc 	const struct s32cc_pll *pll = s32cc_obj2pll(module);
20196e069cbSGhennadi Procopciuc 
20296e069cbSGhennadi Procopciuc 	if (pll->source == NULL) {
20396e069cbSGhennadi Procopciuc 		ERROR("Failed to identify PLL's parent\n");
20496e069cbSGhennadi Procopciuc 	}
20596e069cbSGhennadi Procopciuc 
20696e069cbSGhennadi Procopciuc 	return pll->source;
20796e069cbSGhennadi Procopciuc }
20896e069cbSGhennadi Procopciuc 
209b5101c45SGhennadi Procopciuc static int get_pll_mfi_mfn(unsigned long pll_vco, unsigned long ref_freq,
210b5101c45SGhennadi Procopciuc 			   uint32_t *mfi, uint32_t *mfn)
211b5101c45SGhennadi Procopciuc 
212b5101c45SGhennadi Procopciuc {
213b5101c45SGhennadi Procopciuc 	unsigned long vco;
214b5101c45SGhennadi Procopciuc 	unsigned long mfn64;
215b5101c45SGhennadi Procopciuc 
216b5101c45SGhennadi Procopciuc 	/* FRAC-N mode */
217b5101c45SGhennadi Procopciuc 	*mfi = (uint32_t)(pll_vco / ref_freq);
218b5101c45SGhennadi Procopciuc 
219b5101c45SGhennadi Procopciuc 	/* MFN formula : (double)(pll_vco % ref_freq) / ref_freq * 18432.0 */
220b5101c45SGhennadi Procopciuc 	mfn64 = pll_vco % ref_freq;
221b5101c45SGhennadi Procopciuc 	mfn64 *= FP_PRECISION;
222b5101c45SGhennadi Procopciuc 	mfn64 /= ref_freq;
223b5101c45SGhennadi Procopciuc 	mfn64 *= 18432UL;
224b5101c45SGhennadi Procopciuc 	mfn64 /= FP_PRECISION;
225b5101c45SGhennadi Procopciuc 
226b5101c45SGhennadi Procopciuc 	if (mfn64 > UINT32_MAX) {
227b5101c45SGhennadi Procopciuc 		return -EINVAL;
228b5101c45SGhennadi Procopciuc 	}
229b5101c45SGhennadi Procopciuc 
230b5101c45SGhennadi Procopciuc 	*mfn = (uint32_t)mfn64;
231b5101c45SGhennadi Procopciuc 
232b5101c45SGhennadi Procopciuc 	vco = ((unsigned long)*mfn * FP_PRECISION) / 18432UL;
233b5101c45SGhennadi Procopciuc 	vco += (unsigned long)*mfi * FP_PRECISION;
234b5101c45SGhennadi Procopciuc 	vco *= ref_freq;
235b5101c45SGhennadi Procopciuc 	vco /= FP_PRECISION;
236b5101c45SGhennadi Procopciuc 
237b5101c45SGhennadi Procopciuc 	if (vco != pll_vco) {
238b5101c45SGhennadi Procopciuc 		ERROR("Failed to find MFI and MFN settings for PLL freq %lu. Nearest freq = %lu\n",
239b5101c45SGhennadi Procopciuc 		      pll_vco, vco);
240b5101c45SGhennadi Procopciuc 		return -EINVAL;
241b5101c45SGhennadi Procopciuc 	}
242b5101c45SGhennadi Procopciuc 
243b5101c45SGhennadi Procopciuc 	return 0;
244b5101c45SGhennadi Procopciuc }
245b5101c45SGhennadi Procopciuc 
246b5101c45SGhennadi Procopciuc static struct s32cc_clkmux *get_pll_mux(const struct s32cc_pll *pll)
247b5101c45SGhennadi Procopciuc {
248b5101c45SGhennadi Procopciuc 	const struct s32cc_clk_obj *source = pll->source;
249b5101c45SGhennadi Procopciuc 	const struct s32cc_clk *clk;
250b5101c45SGhennadi Procopciuc 
251b5101c45SGhennadi Procopciuc 	if (source == NULL) {
252b5101c45SGhennadi Procopciuc 		ERROR("Failed to identify PLL's parent\n");
253b5101c45SGhennadi Procopciuc 		return NULL;
254b5101c45SGhennadi Procopciuc 	}
255b5101c45SGhennadi Procopciuc 
256b5101c45SGhennadi Procopciuc 	if (source->type != s32cc_clk_t) {
257b5101c45SGhennadi Procopciuc 		ERROR("The parent of the PLL isn't a clock\n");
258b5101c45SGhennadi Procopciuc 		return NULL;
259b5101c45SGhennadi Procopciuc 	}
260b5101c45SGhennadi Procopciuc 
261b5101c45SGhennadi Procopciuc 	clk = s32cc_obj2clk(source);
262b5101c45SGhennadi Procopciuc 
263b5101c45SGhennadi Procopciuc 	if (clk->module == NULL) {
264b5101c45SGhennadi Procopciuc 		ERROR("The clock isn't connected to a module\n");
265b5101c45SGhennadi Procopciuc 		return NULL;
266b5101c45SGhennadi Procopciuc 	}
267b5101c45SGhennadi Procopciuc 
268b5101c45SGhennadi Procopciuc 	source = clk->module;
269b5101c45SGhennadi Procopciuc 
270b5101c45SGhennadi Procopciuc 	if ((source->type != s32cc_clkmux_t) &&
271b5101c45SGhennadi Procopciuc 	    (source->type != s32cc_shared_clkmux_t)) {
272b5101c45SGhennadi Procopciuc 		ERROR("The parent of the PLL isn't a MUX\n");
273b5101c45SGhennadi Procopciuc 		return NULL;
274b5101c45SGhennadi Procopciuc 	}
275b5101c45SGhennadi Procopciuc 
276b5101c45SGhennadi Procopciuc 	return s32cc_obj2clkmux(source);
277b5101c45SGhennadi Procopciuc }
278b5101c45SGhennadi Procopciuc 
279b5101c45SGhennadi Procopciuc static void disable_odiv(uintptr_t pll_addr, uint32_t div_index)
280b5101c45SGhennadi Procopciuc {
281b5101c45SGhennadi Procopciuc 	mmio_clrbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
282b5101c45SGhennadi Procopciuc }
283b5101c45SGhennadi Procopciuc 
28484e82085SGhennadi Procopciuc static void enable_odiv(uintptr_t pll_addr, uint32_t div_index)
28584e82085SGhennadi Procopciuc {
28684e82085SGhennadi Procopciuc 	mmio_setbits_32(PLLDIG_PLLODIV(pll_addr, div_index), PLLDIG_PLLODIV_DE);
28784e82085SGhennadi Procopciuc }
28884e82085SGhennadi Procopciuc 
289c23dde6cSGhennadi Procopciuc static void enable_odivs(uintptr_t pll_addr, uint32_t ndivs, uint32_t mask)
290c23dde6cSGhennadi Procopciuc {
291c23dde6cSGhennadi Procopciuc 	uint32_t i;
292c23dde6cSGhennadi Procopciuc 
293c23dde6cSGhennadi Procopciuc 	for (i = 0; i < ndivs; i++) {
294c23dde6cSGhennadi Procopciuc 		if ((mask & BIT_32(i)) != 0U) {
295c23dde6cSGhennadi Procopciuc 			enable_odiv(pll_addr, i);
296c23dde6cSGhennadi Procopciuc 		}
297c23dde6cSGhennadi Procopciuc 	}
298c23dde6cSGhennadi Procopciuc }
299c23dde6cSGhennadi Procopciuc 
300c23dde6cSGhennadi Procopciuc static int adjust_odiv_settings(const struct s32cc_pll *pll, uintptr_t pll_addr,
301c23dde6cSGhennadi Procopciuc 				uint32_t odivs_mask, unsigned long old_vco)
302c23dde6cSGhennadi Procopciuc {
303c23dde6cSGhennadi Procopciuc 	uint64_t old_odiv_freq, odiv_freq;
304c23dde6cSGhennadi Procopciuc 	uint32_t i, pllodiv, pdiv;
305c23dde6cSGhennadi Procopciuc 	int ret = 0;
306c23dde6cSGhennadi Procopciuc 
307c23dde6cSGhennadi Procopciuc 	if (old_vco == 0UL) {
308c23dde6cSGhennadi Procopciuc 		return 0;
309c23dde6cSGhennadi Procopciuc 	}
310c23dde6cSGhennadi Procopciuc 
311c23dde6cSGhennadi Procopciuc 	for (i = 0; i < pll->ndividers; i++) {
312c23dde6cSGhennadi Procopciuc 		if ((odivs_mask & BIT_32(i)) == 0U) {
313c23dde6cSGhennadi Procopciuc 			continue;
314c23dde6cSGhennadi Procopciuc 		}
315c23dde6cSGhennadi Procopciuc 
316c23dde6cSGhennadi Procopciuc 		pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, i));
317c23dde6cSGhennadi Procopciuc 
318c23dde6cSGhennadi Procopciuc 		pdiv = PLLDIG_PLLODIV_DIV(pllodiv);
319c23dde6cSGhennadi Procopciuc 
320c23dde6cSGhennadi Procopciuc 		old_odiv_freq = ((old_vco * FP_PRECISION) / (pdiv + 1U)) / FP_PRECISION;
321c23dde6cSGhennadi Procopciuc 		pdiv = (uint32_t)(pll->vco_freq * FP_PRECISION / old_odiv_freq / FP_PRECISION);
322c23dde6cSGhennadi Procopciuc 
323c23dde6cSGhennadi Procopciuc 		odiv_freq = pll->vco_freq * FP_PRECISION / pdiv / FP_PRECISION;
324c23dde6cSGhennadi Procopciuc 
325c23dde6cSGhennadi Procopciuc 		if (old_odiv_freq != odiv_freq) {
326c23dde6cSGhennadi Procopciuc 			ERROR("Failed to adjust ODIV %" PRIu32 " to match previous frequency\n",
327c23dde6cSGhennadi Procopciuc 			      i);
328c23dde6cSGhennadi Procopciuc 		}
329c23dde6cSGhennadi Procopciuc 
330c23dde6cSGhennadi Procopciuc 		pllodiv = PLLDIG_PLLODIV_DIV_SET(pdiv - 1U);
331c23dde6cSGhennadi Procopciuc 		mmio_write_32(PLLDIG_PLLODIV(pll_addr, i), pllodiv);
332c23dde6cSGhennadi Procopciuc 	}
333c23dde6cSGhennadi Procopciuc 
334c23dde6cSGhennadi Procopciuc 	return ret;
335c23dde6cSGhennadi Procopciuc }
336c23dde6cSGhennadi Procopciuc 
337c23dde6cSGhennadi Procopciuc static uint32_t get_enabled_odivs(uintptr_t pll_addr, uint32_t ndivs)
338c23dde6cSGhennadi Procopciuc {
339c23dde6cSGhennadi Procopciuc 	uint32_t mask = 0;
340c23dde6cSGhennadi Procopciuc 	uint32_t pllodiv;
341c23dde6cSGhennadi Procopciuc 	uint32_t i;
342c23dde6cSGhennadi Procopciuc 
343c23dde6cSGhennadi Procopciuc 	for (i = 0; i < ndivs; i++) {
344c23dde6cSGhennadi Procopciuc 		pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, i));
345c23dde6cSGhennadi Procopciuc 		if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) {
346c23dde6cSGhennadi Procopciuc 			mask |= BIT_32(i);
347c23dde6cSGhennadi Procopciuc 		}
348c23dde6cSGhennadi Procopciuc 	}
349c23dde6cSGhennadi Procopciuc 
350c23dde6cSGhennadi Procopciuc 	return mask;
351c23dde6cSGhennadi Procopciuc }
352c23dde6cSGhennadi Procopciuc 
353b5101c45SGhennadi Procopciuc static void disable_odivs(uintptr_t pll_addr, uint32_t ndivs)
354b5101c45SGhennadi Procopciuc {
355b5101c45SGhennadi Procopciuc 	uint32_t i;
356b5101c45SGhennadi Procopciuc 
357b5101c45SGhennadi Procopciuc 	for (i = 0; i < ndivs; i++) {
358b5101c45SGhennadi Procopciuc 		disable_odiv(pll_addr, i);
359b5101c45SGhennadi Procopciuc 	}
360b5101c45SGhennadi Procopciuc }
361b5101c45SGhennadi Procopciuc 
362b5101c45SGhennadi Procopciuc static void enable_pll_hw(uintptr_t pll_addr)
363b5101c45SGhennadi Procopciuc {
364b5101c45SGhennadi Procopciuc 	/* Enable the PLL. */
365b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCR(pll_addr), 0x0);
366b5101c45SGhennadi Procopciuc 
367b5101c45SGhennadi Procopciuc 	/* Poll until PLL acquires lock. */
368b5101c45SGhennadi Procopciuc 	while ((mmio_read_32(PLLDIG_PLLSR(pll_addr)) & PLLDIG_PLLSR_LOCK) == 0U) {
369b5101c45SGhennadi Procopciuc 	}
370b5101c45SGhennadi Procopciuc }
371b5101c45SGhennadi Procopciuc 
372b5101c45SGhennadi Procopciuc static void disable_pll_hw(uintptr_t pll_addr)
373b5101c45SGhennadi Procopciuc {
374b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCR(pll_addr), PLLDIG_PLLCR_PLLPD);
375b5101c45SGhennadi Procopciuc }
376b5101c45SGhennadi Procopciuc 
377c23dde6cSGhennadi Procopciuc static bool is_pll_enabled(uintptr_t pll_base)
378c23dde6cSGhennadi Procopciuc {
379c23dde6cSGhennadi Procopciuc 	uint32_t pllcr, pllsr;
380c23dde6cSGhennadi Procopciuc 
381c23dde6cSGhennadi Procopciuc 	pllcr = mmio_read_32(PLLDIG_PLLCR(pll_base));
382c23dde6cSGhennadi Procopciuc 	pllsr = mmio_read_32(PLLDIG_PLLSR(pll_base));
383c23dde6cSGhennadi Procopciuc 
384c23dde6cSGhennadi Procopciuc 	/* Enabled and locked PLL */
385c23dde6cSGhennadi Procopciuc 	if ((pllcr & PLLDIG_PLLCR_PLLPD) != 0U) {
386c23dde6cSGhennadi Procopciuc 		return false;
387c23dde6cSGhennadi Procopciuc 	}
388c23dde6cSGhennadi Procopciuc 
389c23dde6cSGhennadi Procopciuc 	if ((pllsr & PLLDIG_PLLSR_LOCK) == 0U) {
390c23dde6cSGhennadi Procopciuc 		return false;
391c23dde6cSGhennadi Procopciuc 	}
392c23dde6cSGhennadi Procopciuc 
393c23dde6cSGhennadi Procopciuc 	return true;
394c23dde6cSGhennadi Procopciuc }
395c23dde6cSGhennadi Procopciuc 
396b5101c45SGhennadi Procopciuc static int program_pll(const struct s32cc_pll *pll, uintptr_t pll_addr,
397b5101c45SGhennadi Procopciuc 		       const struct s32cc_clk_drv *drv, uint32_t sclk_id,
398c23dde6cSGhennadi Procopciuc 		       unsigned long sclk_freq, unsigned int depth)
399b5101c45SGhennadi Procopciuc {
400b5101c45SGhennadi Procopciuc 	uint32_t rdiv = 1, mfi, mfn;
401c23dde6cSGhennadi Procopciuc 	unsigned long old_vco = 0UL;
402c23dde6cSGhennadi Procopciuc 	unsigned int ldepth = depth;
403c23dde6cSGhennadi Procopciuc 	uint32_t odivs_mask;
404b5101c45SGhennadi Procopciuc 	int ret;
405b5101c45SGhennadi Procopciuc 
406c23dde6cSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
407c23dde6cSGhennadi Procopciuc 	if (ret != 0) {
408c23dde6cSGhennadi Procopciuc 		return ret;
409c23dde6cSGhennadi Procopciuc 	}
410c23dde6cSGhennadi Procopciuc 
411b5101c45SGhennadi Procopciuc 	ret = get_pll_mfi_mfn(pll->vco_freq, sclk_freq, &mfi, &mfn);
412b5101c45SGhennadi Procopciuc 	if (ret != 0) {
413b5101c45SGhennadi Procopciuc 		return -EINVAL;
414b5101c45SGhennadi Procopciuc 	}
415b5101c45SGhennadi Procopciuc 
416c23dde6cSGhennadi Procopciuc 	odivs_mask = get_enabled_odivs(pll_addr, pll->ndividers);
417c23dde6cSGhennadi Procopciuc 
418c23dde6cSGhennadi Procopciuc 	if (is_pll_enabled(pll_addr)) {
419c23dde6cSGhennadi Procopciuc 		ret = get_module_rate(&pll->desc, drv, &old_vco, ldepth);
420c23dde6cSGhennadi Procopciuc 		if (ret != 0) {
421c23dde6cSGhennadi Procopciuc 			return ret;
422c23dde6cSGhennadi Procopciuc 		}
423c23dde6cSGhennadi Procopciuc 	}
424c23dde6cSGhennadi Procopciuc 
425b5101c45SGhennadi Procopciuc 	/* Disable ODIVs*/
426b5101c45SGhennadi Procopciuc 	disable_odivs(pll_addr, pll->ndividers);
427b5101c45SGhennadi Procopciuc 
428b5101c45SGhennadi Procopciuc 	/* Disable PLL */
429b5101c45SGhennadi Procopciuc 	disable_pll_hw(pll_addr);
430b5101c45SGhennadi Procopciuc 
431b5101c45SGhennadi Procopciuc 	/* Program PLLCLKMUX */
432b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLCLKMUX(pll_addr), sclk_id);
433b5101c45SGhennadi Procopciuc 
434b5101c45SGhennadi Procopciuc 	/* Program VCO */
435b5101c45SGhennadi Procopciuc 	mmio_clrsetbits_32(PLLDIG_PLLDV(pll_addr),
436b5101c45SGhennadi Procopciuc 			   PLLDIG_PLLDV_RDIV_MASK | PLLDIG_PLLDV_MFI_MASK,
437b5101c45SGhennadi Procopciuc 			   PLLDIG_PLLDV_RDIV_SET(rdiv) | PLLDIG_PLLDV_MFI(mfi));
438b5101c45SGhennadi Procopciuc 
439b5101c45SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLFD(pll_addr),
440b5101c45SGhennadi Procopciuc 		      PLLDIG_PLLFD_MFN_SET(mfn) | PLLDIG_PLLFD_SMDEN);
441b5101c45SGhennadi Procopciuc 
442c23dde6cSGhennadi Procopciuc 	ret = adjust_odiv_settings(pll, pll_addr, odivs_mask, old_vco);
443c23dde6cSGhennadi Procopciuc 	if (ret != 0) {
444c23dde6cSGhennadi Procopciuc 		return ret;
445c23dde6cSGhennadi Procopciuc 	}
446c23dde6cSGhennadi Procopciuc 
447b5101c45SGhennadi Procopciuc 	enable_pll_hw(pll_addr);
448b5101c45SGhennadi Procopciuc 
449c23dde6cSGhennadi Procopciuc 	/* Enable out dividers */
450c23dde6cSGhennadi Procopciuc 	enable_odivs(pll_addr, pll->ndividers, odivs_mask);
451c23dde6cSGhennadi Procopciuc 
452b5101c45SGhennadi Procopciuc 	return ret;
453b5101c45SGhennadi Procopciuc }
454b5101c45SGhennadi Procopciuc 
4555300040bSGhennadi Procopciuc static int enable_pll(struct s32cc_clk_obj *module,
456b5101c45SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
4575300040bSGhennadi Procopciuc 		      unsigned int depth)
458b5101c45SGhennadi Procopciuc {
459b5101c45SGhennadi Procopciuc 	const struct s32cc_pll *pll = s32cc_obj2pll(module);
460c23dde6cSGhennadi Procopciuc 	unsigned int clk_src, ldepth = depth;
461c23dde6cSGhennadi Procopciuc 	unsigned long sclk_freq, pll_vco;
462b5101c45SGhennadi Procopciuc 	const struct s32cc_clkmux *mux;
463b5101c45SGhennadi Procopciuc 	uintptr_t pll_addr = UL(0x0);
464c23dde6cSGhennadi Procopciuc 	bool pll_enabled;
465b5101c45SGhennadi Procopciuc 	uint32_t sclk_id;
466b5101c45SGhennadi Procopciuc 	int ret;
467b5101c45SGhennadi Procopciuc 
4688ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
469b5101c45SGhennadi Procopciuc 	if (ret != 0) {
470b5101c45SGhennadi Procopciuc 		return ret;
471b5101c45SGhennadi Procopciuc 	}
472b5101c45SGhennadi Procopciuc 
473b5101c45SGhennadi Procopciuc 	mux = get_pll_mux(pll);
474b5101c45SGhennadi Procopciuc 	if (mux == NULL) {
475b5101c45SGhennadi Procopciuc 		return -EINVAL;
476b5101c45SGhennadi Procopciuc 	}
477b5101c45SGhennadi Procopciuc 
478b5101c45SGhennadi Procopciuc 	if (pll->instance != mux->module) {
479b5101c45SGhennadi Procopciuc 		ERROR("MUX type is not in sync with PLL ID\n");
480b5101c45SGhennadi Procopciuc 		return -EINVAL;
481b5101c45SGhennadi Procopciuc 	}
482b5101c45SGhennadi Procopciuc 
483b5101c45SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
484b5101c45SGhennadi Procopciuc 	if (ret != 0) {
485b5101c45SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
486b5101c45SGhennadi Procopciuc 		return ret;
487b5101c45SGhennadi Procopciuc 	}
488b5101c45SGhennadi Procopciuc 
489b5101c45SGhennadi Procopciuc 	switch (mux->source_id) {
490b5101c45SGhennadi Procopciuc 	case S32CC_CLK_FIRC:
491b5101c45SGhennadi Procopciuc 		sclk_freq = 48U * MHZ;
492b5101c45SGhennadi Procopciuc 		sclk_id = 0;
493b5101c45SGhennadi Procopciuc 		break;
494b5101c45SGhennadi Procopciuc 	case S32CC_CLK_FXOSC:
495b5101c45SGhennadi Procopciuc 		sclk_freq = 40U * MHZ;
496b5101c45SGhennadi Procopciuc 		sclk_id = 1;
497b5101c45SGhennadi Procopciuc 		break;
498b5101c45SGhennadi Procopciuc 	default:
499b5101c45SGhennadi Procopciuc 		ERROR("Invalid source selection for PLL 0x%lx\n",
500b5101c45SGhennadi Procopciuc 		      pll_addr);
501b5101c45SGhennadi Procopciuc 		return -EINVAL;
502b5101c45SGhennadi Procopciuc 	};
503b5101c45SGhennadi Procopciuc 
504c23dde6cSGhennadi Procopciuc 	ret = get_module_rate(&pll->desc, drv, &pll_vco, depth);
505c23dde6cSGhennadi Procopciuc 	if (ret != 0) {
506c23dde6cSGhennadi Procopciuc 		return ret;
507c23dde6cSGhennadi Procopciuc 	}
508c23dde6cSGhennadi Procopciuc 
509c23dde6cSGhennadi Procopciuc 	pll_enabled = is_pll_enabled(pll_addr);
510c23dde6cSGhennadi Procopciuc 	clk_src = mmio_read_32(PLLDIG_PLLCLKMUX(pll_addr));
511c23dde6cSGhennadi Procopciuc 
512c23dde6cSGhennadi Procopciuc 	if ((clk_src == sclk_id) && pll_enabled &&
513c23dde6cSGhennadi Procopciuc 	    (pll_vco == pll->vco_freq)) {
514c23dde6cSGhennadi Procopciuc 		return 0;
515c23dde6cSGhennadi Procopciuc 	}
516c23dde6cSGhennadi Procopciuc 
517c23dde6cSGhennadi Procopciuc 	return program_pll(pll, pll_addr, drv, sclk_id, sclk_freq, ldepth);
518b5101c45SGhennadi Procopciuc }
519b5101c45SGhennadi Procopciuc 
52084e82085SGhennadi Procopciuc static inline struct s32cc_pll *get_div_pll(const struct s32cc_pll_out_div *pdiv)
52184e82085SGhennadi Procopciuc {
52284e82085SGhennadi Procopciuc 	const struct s32cc_clk_obj *parent;
52384e82085SGhennadi Procopciuc 
52484e82085SGhennadi Procopciuc 	parent = pdiv->parent;
52584e82085SGhennadi Procopciuc 	if (parent == NULL) {
52684e82085SGhennadi Procopciuc 		ERROR("Failed to identify PLL divider's parent\n");
52784e82085SGhennadi Procopciuc 		return NULL;
52884e82085SGhennadi Procopciuc 	}
52984e82085SGhennadi Procopciuc 
53084e82085SGhennadi Procopciuc 	if (parent->type != s32cc_pll_t) {
53184e82085SGhennadi Procopciuc 		ERROR("The parent of the divider is not a PLL instance\n");
53284e82085SGhennadi Procopciuc 		return NULL;
53384e82085SGhennadi Procopciuc 	}
53484e82085SGhennadi Procopciuc 
53584e82085SGhennadi Procopciuc 	return s32cc_obj2pll(parent);
53684e82085SGhennadi Procopciuc }
53784e82085SGhennadi Procopciuc 
53884e82085SGhennadi Procopciuc static void config_pll_out_div(uintptr_t pll_addr, uint32_t div_index, uint32_t dc)
53984e82085SGhennadi Procopciuc {
54084e82085SGhennadi Procopciuc 	uint32_t pllodiv;
54184e82085SGhennadi Procopciuc 	uint32_t pdiv;
54284e82085SGhennadi Procopciuc 
54384e82085SGhennadi Procopciuc 	pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, div_index));
54484e82085SGhennadi Procopciuc 	pdiv = PLLDIG_PLLODIV_DIV(pllodiv);
54584e82085SGhennadi Procopciuc 
54684e82085SGhennadi Procopciuc 	if (((pdiv + 1U) == dc) && ((pllodiv & PLLDIG_PLLODIV_DE) != 0U)) {
54784e82085SGhennadi Procopciuc 		return;
54884e82085SGhennadi Procopciuc 	}
54984e82085SGhennadi Procopciuc 
55084e82085SGhennadi Procopciuc 	if ((pllodiv & PLLDIG_PLLODIV_DE) != 0U) {
55184e82085SGhennadi Procopciuc 		disable_odiv(pll_addr, div_index);
55284e82085SGhennadi Procopciuc 	}
55384e82085SGhennadi Procopciuc 
55484e82085SGhennadi Procopciuc 	pllodiv = PLLDIG_PLLODIV_DIV_SET(dc - 1U);
55584e82085SGhennadi Procopciuc 	mmio_write_32(PLLDIG_PLLODIV(pll_addr, div_index), pllodiv);
55684e82085SGhennadi Procopciuc 
55784e82085SGhennadi Procopciuc 	enable_odiv(pll_addr, div_index);
55884e82085SGhennadi Procopciuc }
55984e82085SGhennadi Procopciuc 
56096e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_pll_div_parent(const struct s32cc_clk_obj *module)
56196e069cbSGhennadi Procopciuc {
56296e069cbSGhennadi Procopciuc 	const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
56396e069cbSGhennadi Procopciuc 
56496e069cbSGhennadi Procopciuc 	if (pdiv->parent == NULL) {
56596e069cbSGhennadi Procopciuc 		ERROR("Failed to identify PLL DIV's parent\n");
56696e069cbSGhennadi Procopciuc 	}
56796e069cbSGhennadi Procopciuc 
56896e069cbSGhennadi Procopciuc 	return pdiv->parent;
56996e069cbSGhennadi Procopciuc }
57096e069cbSGhennadi Procopciuc 
5715300040bSGhennadi Procopciuc static int enable_pll_div(struct s32cc_clk_obj *module,
57284e82085SGhennadi Procopciuc 			  const struct s32cc_clk_drv *drv,
5735300040bSGhennadi Procopciuc 			  unsigned int depth)
57484e82085SGhennadi Procopciuc {
57584e82085SGhennadi Procopciuc 	const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
57684e82085SGhennadi Procopciuc 	uintptr_t pll_addr = 0x0ULL;
5778ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
57884e82085SGhennadi Procopciuc 	const struct s32cc_pll *pll;
579c23dde6cSGhennadi Procopciuc 	unsigned long pll_vco;
58084e82085SGhennadi Procopciuc 	uint32_t dc;
58184e82085SGhennadi Procopciuc 	int ret;
58284e82085SGhennadi Procopciuc 
5838ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
58484e82085SGhennadi Procopciuc 	if (ret != 0) {
58584e82085SGhennadi Procopciuc 		return ret;
58684e82085SGhennadi Procopciuc 	}
58784e82085SGhennadi Procopciuc 
58884e82085SGhennadi Procopciuc 	pll = get_div_pll(pdiv);
58984e82085SGhennadi Procopciuc 	if (pll == NULL) {
59084e82085SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
59184e82085SGhennadi Procopciuc 		return 0;
59284e82085SGhennadi Procopciuc 	}
59384e82085SGhennadi Procopciuc 
59484e82085SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
59584e82085SGhennadi Procopciuc 	if (ret != 0) {
59684e82085SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
59784e82085SGhennadi Procopciuc 		return -EINVAL;
59884e82085SGhennadi Procopciuc 	}
59984e82085SGhennadi Procopciuc 
600c23dde6cSGhennadi Procopciuc 	ret = get_module_rate(&pll->desc, drv, &pll_vco, ldepth);
601c23dde6cSGhennadi Procopciuc 	if (ret != 0) {
602c23dde6cSGhennadi Procopciuc 		ERROR("Failed to enable the PLL due to unknown rate for 0x%" PRIxPTR "\n",
603c23dde6cSGhennadi Procopciuc 		      pll_addr);
604c23dde6cSGhennadi Procopciuc 		return ret;
605c23dde6cSGhennadi Procopciuc 	}
606c23dde6cSGhennadi Procopciuc 
607c23dde6cSGhennadi Procopciuc 	dc = (uint32_t)(pll_vco / pdiv->freq);
60884e82085SGhennadi Procopciuc 
60984e82085SGhennadi Procopciuc 	config_pll_out_div(pll_addr, pdiv->index, dc);
61084e82085SGhennadi Procopciuc 
61184e82085SGhennadi Procopciuc 	return 0;
61284e82085SGhennadi Procopciuc }
61384e82085SGhennadi Procopciuc 
6147004f678SGhennadi Procopciuc static int cgm_mux_clk_config(uintptr_t cgm_addr, uint32_t mux, uint32_t source,
6157004f678SGhennadi Procopciuc 			      bool safe_clk)
6167004f678SGhennadi Procopciuc {
6177004f678SGhennadi Procopciuc 	uint32_t css, csc;
6187004f678SGhennadi Procopciuc 
6197004f678SGhennadi Procopciuc 	css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
6207004f678SGhennadi Procopciuc 
6217004f678SGhennadi Procopciuc 	/* Already configured */
6227004f678SGhennadi Procopciuc 	if ((MC_CGM_MUXn_CSS_SELSTAT(css) == source) &&
6237004f678SGhennadi Procopciuc 	    (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
6247004f678SGhennadi Procopciuc 	    ((css & MC_CGM_MUXn_CSS_SWIP) == 0U) && !safe_clk) {
6257004f678SGhennadi Procopciuc 		return 0;
6267004f678SGhennadi Procopciuc 	}
6277004f678SGhennadi Procopciuc 
6287004f678SGhennadi Procopciuc 	/* Ongoing clock switch? */
6297004f678SGhennadi Procopciuc 	while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
6307004f678SGhennadi Procopciuc 		MC_CGM_MUXn_CSS_SWIP) != 0U) {
6317004f678SGhennadi Procopciuc 	}
6327004f678SGhennadi Procopciuc 
6337004f678SGhennadi Procopciuc 	csc = mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux));
6347004f678SGhennadi Procopciuc 
6357004f678SGhennadi Procopciuc 	/* Clear previous source. */
6367004f678SGhennadi Procopciuc 	csc &= ~(MC_CGM_MUXn_CSC_SELCTL_MASK);
6377004f678SGhennadi Procopciuc 
6387004f678SGhennadi Procopciuc 	if (!safe_clk) {
6397004f678SGhennadi Procopciuc 		/* Select the clock source and trigger the clock switch. */
6407004f678SGhennadi Procopciuc 		csc |= MC_CGM_MUXn_CSC_SELCTL(source) | MC_CGM_MUXn_CSC_CLK_SW;
6417004f678SGhennadi Procopciuc 	} else {
6427004f678SGhennadi Procopciuc 		/* Switch to safe clock */
6437004f678SGhennadi Procopciuc 		csc |= MC_CGM_MUXn_CSC_SAFE_SW;
6447004f678SGhennadi Procopciuc 	}
6457004f678SGhennadi Procopciuc 
6467004f678SGhennadi Procopciuc 	mmio_write_32(CGM_MUXn_CSC(cgm_addr, mux), csc);
6477004f678SGhennadi Procopciuc 
6487004f678SGhennadi Procopciuc 	/* Wait for configuration bit to auto-clear. */
6497004f678SGhennadi Procopciuc 	while ((mmio_read_32(CGM_MUXn_CSC(cgm_addr, mux)) &
6507004f678SGhennadi Procopciuc 		MC_CGM_MUXn_CSC_CLK_SW) != 0U) {
6517004f678SGhennadi Procopciuc 	}
6527004f678SGhennadi Procopciuc 
6537004f678SGhennadi Procopciuc 	/* Is the clock switch completed? */
6547004f678SGhennadi Procopciuc 	while ((mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux)) &
6557004f678SGhennadi Procopciuc 		MC_CGM_MUXn_CSS_SWIP) != 0U) {
6567004f678SGhennadi Procopciuc 	}
6577004f678SGhennadi Procopciuc 
6587004f678SGhennadi Procopciuc 	/*
6597004f678SGhennadi Procopciuc 	 * Check if the switch succeeded.
6607004f678SGhennadi Procopciuc 	 * Check switch trigger cause and the source.
6617004f678SGhennadi Procopciuc 	 */
6627004f678SGhennadi Procopciuc 	css = mmio_read_32(CGM_MUXn_CSS(cgm_addr, mux));
6637004f678SGhennadi Procopciuc 	if (!safe_clk) {
6647004f678SGhennadi Procopciuc 		if ((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SUCCESS) &&
6657004f678SGhennadi Procopciuc 		    (MC_CGM_MUXn_CSS_SELSTAT(css) == source)) {
6667004f678SGhennadi Procopciuc 			return 0;
6677004f678SGhennadi Procopciuc 		}
6687004f678SGhennadi Procopciuc 
6697004f678SGhennadi Procopciuc 		ERROR("Failed to change the source of mux %" PRIu32 " to %" PRIu32 " (CGM=%lu)\n",
6707004f678SGhennadi Procopciuc 		      mux, source, cgm_addr);
6717004f678SGhennadi Procopciuc 	} else {
6727004f678SGhennadi Procopciuc 		if (((MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK) ||
6737004f678SGhennadi Procopciuc 		     (MC_CGM_MUXn_CSS_SWTRG(css) == MC_CGM_MUXn_CSS_SWTRG_SAFE_CLK_INACTIVE)) &&
6747004f678SGhennadi Procopciuc 		     ((MC_CGM_MUXn_CSS_SAFE_SW & css) != 0U)) {
6757004f678SGhennadi Procopciuc 			return 0;
6767004f678SGhennadi Procopciuc 		}
6777004f678SGhennadi Procopciuc 
6787004f678SGhennadi Procopciuc 		ERROR("The switch of mux %" PRIu32 " (CGM=%lu) to safe clock failed\n",
6797004f678SGhennadi Procopciuc 		      mux, cgm_addr);
6807004f678SGhennadi Procopciuc 	}
6817004f678SGhennadi Procopciuc 
6827004f678SGhennadi Procopciuc 	return -EINVAL;
6837004f678SGhennadi Procopciuc }
6847004f678SGhennadi Procopciuc 
6857004f678SGhennadi Procopciuc static int enable_cgm_mux(const struct s32cc_clkmux *mux,
6867004f678SGhennadi Procopciuc 			  const struct s32cc_clk_drv *drv)
6877004f678SGhennadi Procopciuc {
6887004f678SGhennadi Procopciuc 	uintptr_t cgm_addr = UL(0x0);
6897004f678SGhennadi Procopciuc 	uint32_t mux_hw_clk;
6907004f678SGhennadi Procopciuc 	int ret;
6917004f678SGhennadi Procopciuc 
6927004f678SGhennadi Procopciuc 	ret = get_base_addr(mux->module, drv, &cgm_addr);
6937004f678SGhennadi Procopciuc 	if (ret != 0) {
6947004f678SGhennadi Procopciuc 		return ret;
6957004f678SGhennadi Procopciuc 	}
6967004f678SGhennadi Procopciuc 
6977004f678SGhennadi Procopciuc 	mux_hw_clk = (uint32_t)S32CC_CLK_ID(mux->source_id);
6987004f678SGhennadi Procopciuc 
6997004f678SGhennadi Procopciuc 	return cgm_mux_clk_config(cgm_addr, mux->index,
7007004f678SGhennadi Procopciuc 				  mux_hw_clk, false);
7017004f678SGhennadi Procopciuc }
7027004f678SGhennadi Procopciuc 
70396e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_mux_parent(const struct s32cc_clk_obj *module)
70496e069cbSGhennadi Procopciuc {
70596e069cbSGhennadi Procopciuc 	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
70696e069cbSGhennadi Procopciuc 	struct s32cc_clk *clk;
70796e069cbSGhennadi Procopciuc 
70896e069cbSGhennadi Procopciuc 	if (mux == NULL) {
70996e069cbSGhennadi Procopciuc 		return NULL;
71096e069cbSGhennadi Procopciuc 	}
71196e069cbSGhennadi Procopciuc 
71296e069cbSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(mux->source_id);
71396e069cbSGhennadi Procopciuc 	if (clk == NULL) {
71496e069cbSGhennadi Procopciuc 		ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n",
71596e069cbSGhennadi Procopciuc 		      mux->source_id, mux->index);
71696e069cbSGhennadi Procopciuc 		return NULL;
71796e069cbSGhennadi Procopciuc 	}
71896e069cbSGhennadi Procopciuc 
71996e069cbSGhennadi Procopciuc 	return &clk->desc;
72096e069cbSGhennadi Procopciuc }
72196e069cbSGhennadi Procopciuc 
7225300040bSGhennadi Procopciuc static int enable_mux(struct s32cc_clk_obj *module,
7237004f678SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
7245300040bSGhennadi Procopciuc 		      unsigned int depth)
7257004f678SGhennadi Procopciuc {
7267004f678SGhennadi Procopciuc 	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
7278ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
7287004f678SGhennadi Procopciuc 	const struct s32cc_clk *clk;
7297004f678SGhennadi Procopciuc 	int ret = 0;
7307004f678SGhennadi Procopciuc 
7318ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
7327004f678SGhennadi Procopciuc 	if (ret != 0) {
7337004f678SGhennadi Procopciuc 		return ret;
7347004f678SGhennadi Procopciuc 	}
7357004f678SGhennadi Procopciuc 
7367004f678SGhennadi Procopciuc 	if (mux == NULL) {
7377004f678SGhennadi Procopciuc 		return -EINVAL;
7387004f678SGhennadi Procopciuc 	}
7397004f678SGhennadi Procopciuc 
7407004f678SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(mux->source_id);
7417004f678SGhennadi Procopciuc 	if (clk == NULL) {
7427004f678SGhennadi Procopciuc 		ERROR("Invalid parent (%lu) for mux %" PRIu8 "\n",
7437004f678SGhennadi Procopciuc 		      mux->source_id, mux->index);
7447004f678SGhennadi Procopciuc 		return -EINVAL;
7457004f678SGhennadi Procopciuc 	}
7467004f678SGhennadi Procopciuc 
7477004f678SGhennadi Procopciuc 	switch (mux->module) {
7487004f678SGhennadi Procopciuc 	/* PLL mux will be enabled by PLL setup */
7497004f678SGhennadi Procopciuc 	case S32CC_ARM_PLL:
750f8490b85SGhennadi Procopciuc 	case S32CC_PERIPH_PLL:
75118c2b137SGhennadi Procopciuc 	case S32CC_DDR_PLL:
7527004f678SGhennadi Procopciuc 		break;
7537004f678SGhennadi Procopciuc 	case S32CC_CGM1:
7547004f678SGhennadi Procopciuc 		ret = enable_cgm_mux(mux, drv);
7557004f678SGhennadi Procopciuc 		break;
7569dbca85dSGhennadi Procopciuc 	case S32CC_CGM0:
7579dbca85dSGhennadi Procopciuc 		ret = enable_cgm_mux(mux, drv);
7589dbca85dSGhennadi Procopciuc 		break;
7598a4f840bSGhennadi Procopciuc 	case S32CC_CGM5:
7608a4f840bSGhennadi Procopciuc 		ret = enable_cgm_mux(mux, drv);
7618a4f840bSGhennadi Procopciuc 		break;
7627004f678SGhennadi Procopciuc 	default:
7637004f678SGhennadi Procopciuc 		ERROR("Unknown mux parent type: %d\n", mux->module);
7647004f678SGhennadi Procopciuc 		ret = -EINVAL;
7657004f678SGhennadi Procopciuc 		break;
7667004f678SGhennadi Procopciuc 	};
7677004f678SGhennadi Procopciuc 
7687004f678SGhennadi Procopciuc 	return ret;
7697004f678SGhennadi Procopciuc }
7707004f678SGhennadi Procopciuc 
77196e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_dfs_parent(const struct s32cc_clk_obj *module)
77296e069cbSGhennadi Procopciuc {
77396e069cbSGhennadi Procopciuc 	const struct s32cc_dfs *dfs = s32cc_obj2dfs(module);
77496e069cbSGhennadi Procopciuc 
77596e069cbSGhennadi Procopciuc 	if (dfs->parent == NULL) {
77696e069cbSGhennadi Procopciuc 		ERROR("Failed to identify DFS's parent\n");
77796e069cbSGhennadi Procopciuc 	}
77896e069cbSGhennadi Procopciuc 
77996e069cbSGhennadi Procopciuc 	return dfs->parent;
78096e069cbSGhennadi Procopciuc }
78196e069cbSGhennadi Procopciuc 
7825300040bSGhennadi Procopciuc static int enable_dfs(struct s32cc_clk_obj *module,
7834cd04c50SGhennadi Procopciuc 		      const struct s32cc_clk_drv *drv,
7845300040bSGhennadi Procopciuc 		      unsigned int depth)
7854cd04c50SGhennadi Procopciuc {
7868ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
7874cd04c50SGhennadi Procopciuc 	int ret = 0;
7884cd04c50SGhennadi Procopciuc 
7898ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
7904cd04c50SGhennadi Procopciuc 	if (ret != 0) {
7914cd04c50SGhennadi Procopciuc 		return ret;
7924cd04c50SGhennadi Procopciuc 	}
7934cd04c50SGhennadi Procopciuc 
7944cd04c50SGhennadi Procopciuc 	return 0;
7954cd04c50SGhennadi Procopciuc }
7964cd04c50SGhennadi Procopciuc 
7972fb25509SGhennadi Procopciuc static int get_dfs_freq(const struct s32cc_clk_obj *module,
7982fb25509SGhennadi Procopciuc 			const struct s32cc_clk_drv *drv,
7992fb25509SGhennadi Procopciuc 			unsigned long *rate, unsigned int depth)
8002fb25509SGhennadi Procopciuc {
8012fb25509SGhennadi Procopciuc 	const struct s32cc_dfs *dfs = s32cc_obj2dfs(module);
8022fb25509SGhennadi Procopciuc 	unsigned int ldepth = depth;
8032fb25509SGhennadi Procopciuc 	uintptr_t dfs_addr;
8042fb25509SGhennadi Procopciuc 	int ret;
8052fb25509SGhennadi Procopciuc 
8062fb25509SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
8072fb25509SGhennadi Procopciuc 	if (ret != 0) {
8082fb25509SGhennadi Procopciuc 		return ret;
8092fb25509SGhennadi Procopciuc 	}
8102fb25509SGhennadi Procopciuc 
8112fb25509SGhennadi Procopciuc 	ret = get_base_addr(dfs->instance, drv, &dfs_addr);
8122fb25509SGhennadi Procopciuc 	if (ret != 0) {
8132fb25509SGhennadi Procopciuc 		ERROR("Failed to detect the DFS instance\n");
8142fb25509SGhennadi Procopciuc 		return ret;
8152fb25509SGhennadi Procopciuc 	}
8162fb25509SGhennadi Procopciuc 
8172fb25509SGhennadi Procopciuc 	return get_module_rate(dfs->parent, drv, rate, ldepth);
8182fb25509SGhennadi Procopciuc }
8192fb25509SGhennadi Procopciuc 
8204cd04c50SGhennadi Procopciuc static struct s32cc_dfs *get_div_dfs(const struct s32cc_dfs_div *dfs_div)
8214cd04c50SGhennadi Procopciuc {
8224cd04c50SGhennadi Procopciuc 	const struct s32cc_clk_obj *parent = dfs_div->parent;
8234cd04c50SGhennadi Procopciuc 
8244cd04c50SGhennadi Procopciuc 	if (parent->type != s32cc_dfs_t) {
8254cd04c50SGhennadi Procopciuc 		ERROR("DFS DIV doesn't have a DFS as parent\n");
8264cd04c50SGhennadi Procopciuc 		return NULL;
8274cd04c50SGhennadi Procopciuc 	}
8284cd04c50SGhennadi Procopciuc 
8294cd04c50SGhennadi Procopciuc 	return s32cc_obj2dfs(parent);
8304cd04c50SGhennadi Procopciuc }
8314cd04c50SGhennadi Procopciuc 
8324cd04c50SGhennadi Procopciuc static int get_dfs_mfi_mfn(unsigned long dfs_freq, const struct s32cc_dfs_div *dfs_div,
8334cd04c50SGhennadi Procopciuc 			   uint32_t *mfi, uint32_t *mfn)
8344cd04c50SGhennadi Procopciuc {
8354cd04c50SGhennadi Procopciuc 	uint64_t factor64, tmp64, ofreq;
8364cd04c50SGhennadi Procopciuc 	uint32_t factor32;
8374cd04c50SGhennadi Procopciuc 
8384cd04c50SGhennadi Procopciuc 	unsigned long in = dfs_freq;
8394cd04c50SGhennadi Procopciuc 	unsigned long out = dfs_div->freq;
8404cd04c50SGhennadi Procopciuc 
8414cd04c50SGhennadi Procopciuc 	/**
8424cd04c50SGhennadi Procopciuc 	 * factor = (IN / OUT) / 2
8434cd04c50SGhennadi Procopciuc 	 * MFI = integer(factor)
8444cd04c50SGhennadi Procopciuc 	 * MFN = (factor - MFI) * 36
8454cd04c50SGhennadi Procopciuc 	 */
8464cd04c50SGhennadi Procopciuc 	factor64 = ((((uint64_t)in) * FP_PRECISION) / ((uint64_t)out)) / 2ULL;
8474cd04c50SGhennadi Procopciuc 	tmp64 = factor64 / FP_PRECISION;
8484cd04c50SGhennadi Procopciuc 	if (tmp64 > UINT32_MAX) {
8494cd04c50SGhennadi Procopciuc 		return -EINVAL;
8504cd04c50SGhennadi Procopciuc 	}
8514cd04c50SGhennadi Procopciuc 
8524cd04c50SGhennadi Procopciuc 	factor32 = (uint32_t)tmp64;
8534cd04c50SGhennadi Procopciuc 	*mfi = factor32;
8544cd04c50SGhennadi Procopciuc 
8554cd04c50SGhennadi Procopciuc 	tmp64 = ((factor64 - ((uint64_t)*mfi * FP_PRECISION)) * 36UL) / FP_PRECISION;
8564cd04c50SGhennadi Procopciuc 	if (tmp64 > UINT32_MAX) {
8574cd04c50SGhennadi Procopciuc 		return -EINVAL;
8584cd04c50SGhennadi Procopciuc 	}
8594cd04c50SGhennadi Procopciuc 
8604cd04c50SGhennadi Procopciuc 	*mfn = (uint32_t)tmp64;
8614cd04c50SGhennadi Procopciuc 
8624cd04c50SGhennadi Procopciuc 	/* div_freq = in / (2 * (*mfi + *mfn / 36.0)) */
8634cd04c50SGhennadi Procopciuc 	factor64 = (((uint64_t)*mfn) * FP_PRECISION) / 36ULL;
8644cd04c50SGhennadi Procopciuc 	factor64 += ((uint64_t)*mfi) * FP_PRECISION;
8654cd04c50SGhennadi Procopciuc 	factor64 *= 2ULL;
8664cd04c50SGhennadi Procopciuc 	ofreq = (((uint64_t)in) * FP_PRECISION) / factor64;
8674cd04c50SGhennadi Procopciuc 
8684cd04c50SGhennadi Procopciuc 	if (ofreq != dfs_div->freq) {
8694cd04c50SGhennadi Procopciuc 		ERROR("Failed to find MFI and MFN settings for DFS DIV freq %lu\n",
8704cd04c50SGhennadi Procopciuc 		      dfs_div->freq);
8714cd04c50SGhennadi Procopciuc 		ERROR("Nearest freq = %" PRIx64 "\n", ofreq);
8724cd04c50SGhennadi Procopciuc 		return -EINVAL;
8734cd04c50SGhennadi Procopciuc 	}
8744cd04c50SGhennadi Procopciuc 
8754cd04c50SGhennadi Procopciuc 	return 0;
8764cd04c50SGhennadi Procopciuc }
8774cd04c50SGhennadi Procopciuc 
8784cd04c50SGhennadi Procopciuc static int init_dfs_port(uintptr_t dfs_addr, uint32_t port,
8794cd04c50SGhennadi Procopciuc 			 uint32_t mfi, uint32_t mfn)
8804cd04c50SGhennadi Procopciuc {
8814cd04c50SGhennadi Procopciuc 	uint32_t portsr, portolsr;
8824cd04c50SGhennadi Procopciuc 	uint32_t mask, old_mfi, old_mfn;
8834cd04c50SGhennadi Procopciuc 	uint32_t dvport;
8844cd04c50SGhennadi Procopciuc 	bool init_dfs;
8854cd04c50SGhennadi Procopciuc 
8864cd04c50SGhennadi Procopciuc 	dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, port));
8874cd04c50SGhennadi Procopciuc 
8884cd04c50SGhennadi Procopciuc 	old_mfi = DFS_DVPORTn_MFI(dvport);
8894cd04c50SGhennadi Procopciuc 	old_mfn = DFS_DVPORTn_MFN(dvport);
8904cd04c50SGhennadi Procopciuc 
8914cd04c50SGhennadi Procopciuc 	portsr = mmio_read_32(DFS_PORTSR(dfs_addr));
8924cd04c50SGhennadi Procopciuc 	portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
8934cd04c50SGhennadi Procopciuc 
8944cd04c50SGhennadi Procopciuc 	/* Skip configuration if it's not needed */
8954cd04c50SGhennadi Procopciuc 	if (((portsr & BIT_32(port)) != 0U) &&
8964cd04c50SGhennadi Procopciuc 	    ((portolsr & BIT_32(port)) == 0U) &&
8974cd04c50SGhennadi Procopciuc 	    (mfi == old_mfi) && (mfn == old_mfn)) {
8984cd04c50SGhennadi Procopciuc 		return 0;
8994cd04c50SGhennadi Procopciuc 	}
9004cd04c50SGhennadi Procopciuc 
9014cd04c50SGhennadi Procopciuc 	init_dfs = (portsr == 0U);
9024cd04c50SGhennadi Procopciuc 
9034cd04c50SGhennadi Procopciuc 	if (init_dfs) {
9044cd04c50SGhennadi Procopciuc 		mask = DFS_PORTRESET_MASK;
9054cd04c50SGhennadi Procopciuc 	} else {
9064cd04c50SGhennadi Procopciuc 		mask = DFS_PORTRESET_SET(BIT_32(port));
9074cd04c50SGhennadi Procopciuc 	}
9084cd04c50SGhennadi Procopciuc 
9094cd04c50SGhennadi Procopciuc 	mmio_write_32(DFS_PORTOLSR(dfs_addr), mask);
9104cd04c50SGhennadi Procopciuc 	mmio_write_32(DFS_PORTRESET(dfs_addr), mask);
9114cd04c50SGhennadi Procopciuc 
9124cd04c50SGhennadi Procopciuc 	while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & mask) != 0U) {
9134cd04c50SGhennadi Procopciuc 	}
9144cd04c50SGhennadi Procopciuc 
9154cd04c50SGhennadi Procopciuc 	if (init_dfs) {
9164cd04c50SGhennadi Procopciuc 		mmio_write_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
9174cd04c50SGhennadi Procopciuc 	}
9184cd04c50SGhennadi Procopciuc 
9194cd04c50SGhennadi Procopciuc 	mmio_write_32(DFS_DVPORTn(dfs_addr, port),
9204cd04c50SGhennadi Procopciuc 		      DFS_DVPORTn_MFI_SET(mfi) | DFS_DVPORTn_MFN_SET(mfn));
9214cd04c50SGhennadi Procopciuc 
9224cd04c50SGhennadi Procopciuc 	if (init_dfs) {
9234cd04c50SGhennadi Procopciuc 		/* DFS clk enable programming */
9244cd04c50SGhennadi Procopciuc 		mmio_clrbits_32(DFS_CTL(dfs_addr), DFS_CTL_RESET);
9254cd04c50SGhennadi Procopciuc 	}
9264cd04c50SGhennadi Procopciuc 
9274cd04c50SGhennadi Procopciuc 	mmio_clrbits_32(DFS_PORTRESET(dfs_addr), BIT_32(port));
9284cd04c50SGhennadi Procopciuc 
9294cd04c50SGhennadi Procopciuc 	while ((mmio_read_32(DFS_PORTSR(dfs_addr)) & BIT_32(port)) != BIT_32(port)) {
9304cd04c50SGhennadi Procopciuc 	}
9314cd04c50SGhennadi Procopciuc 
9324cd04c50SGhennadi Procopciuc 	portolsr = mmio_read_32(DFS_PORTOLSR(dfs_addr));
9334cd04c50SGhennadi Procopciuc 	if ((portolsr & DFS_PORTOLSR_LOL(port)) != 0U) {
9344cd04c50SGhennadi Procopciuc 		ERROR("Failed to lock DFS divider\n");
9354cd04c50SGhennadi Procopciuc 		return -EINVAL;
9364cd04c50SGhennadi Procopciuc 	}
9374cd04c50SGhennadi Procopciuc 
9384cd04c50SGhennadi Procopciuc 	return 0;
9394cd04c50SGhennadi Procopciuc }
9404cd04c50SGhennadi Procopciuc 
94196e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *
94296e069cbSGhennadi Procopciuc get_dfs_div_parent(const struct s32cc_clk_obj *module)
94396e069cbSGhennadi Procopciuc {
94496e069cbSGhennadi Procopciuc 	const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
94596e069cbSGhennadi Procopciuc 
94696e069cbSGhennadi Procopciuc 	if (dfs_div->parent == NULL) {
94796e069cbSGhennadi Procopciuc 		ERROR("Failed to identify DFS divider's parent\n");
94896e069cbSGhennadi Procopciuc 	}
94996e069cbSGhennadi Procopciuc 
95096e069cbSGhennadi Procopciuc 	return dfs_div->parent;
95196e069cbSGhennadi Procopciuc }
95296e069cbSGhennadi Procopciuc 
9535300040bSGhennadi Procopciuc static int enable_dfs_div(struct s32cc_clk_obj *module,
9544cd04c50SGhennadi Procopciuc 			  const struct s32cc_clk_drv *drv,
9555300040bSGhennadi Procopciuc 			  unsigned int depth)
9564cd04c50SGhennadi Procopciuc {
9574cd04c50SGhennadi Procopciuc 	const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
9588ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
9594cd04c50SGhennadi Procopciuc 	const struct s32cc_dfs *dfs;
9604cd04c50SGhennadi Procopciuc 	uintptr_t dfs_addr = 0UL;
96143b4b29fSGhennadi Procopciuc 	unsigned long dfs_freq;
9624cd04c50SGhennadi Procopciuc 	uint32_t mfi, mfn;
9634cd04c50SGhennadi Procopciuc 	int ret = 0;
9644cd04c50SGhennadi Procopciuc 
9658ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
9664cd04c50SGhennadi Procopciuc 	if (ret != 0) {
9674cd04c50SGhennadi Procopciuc 		return ret;
9684cd04c50SGhennadi Procopciuc 	}
9694cd04c50SGhennadi Procopciuc 
9704cd04c50SGhennadi Procopciuc 	dfs = get_div_dfs(dfs_div);
9714cd04c50SGhennadi Procopciuc 	if (dfs == NULL) {
9724cd04c50SGhennadi Procopciuc 		return -EINVAL;
9734cd04c50SGhennadi Procopciuc 	}
9744cd04c50SGhennadi Procopciuc 
9754cd04c50SGhennadi Procopciuc 	ret = get_base_addr(dfs->instance, drv, &dfs_addr);
9764cd04c50SGhennadi Procopciuc 	if ((ret != 0) || (dfs_addr == 0UL)) {
9774cd04c50SGhennadi Procopciuc 		return -EINVAL;
9784cd04c50SGhennadi Procopciuc 	}
9794cd04c50SGhennadi Procopciuc 
98043b4b29fSGhennadi Procopciuc 	ret = get_module_rate(&dfs->desc, drv, &dfs_freq, depth);
98143b4b29fSGhennadi Procopciuc 	if (ret != 0) {
98243b4b29fSGhennadi Procopciuc 		return ret;
98343b4b29fSGhennadi Procopciuc 	}
98443b4b29fSGhennadi Procopciuc 
98543b4b29fSGhennadi Procopciuc 	ret = get_dfs_mfi_mfn(dfs_freq, dfs_div, &mfi, &mfn);
9864cd04c50SGhennadi Procopciuc 	if (ret != 0) {
9874cd04c50SGhennadi Procopciuc 		return -EINVAL;
9884cd04c50SGhennadi Procopciuc 	}
9894cd04c50SGhennadi Procopciuc 
9904cd04c50SGhennadi Procopciuc 	return init_dfs_port(dfs_addr, dfs_div->index, mfi, mfn);
9914cd04c50SGhennadi Procopciuc }
9924cd04c50SGhennadi Procopciuc 
9935300040bSGhennadi Procopciuc typedef int (*enable_clk_t)(struct s32cc_clk_obj *module,
9945300040bSGhennadi Procopciuc 			    const struct s32cc_clk_drv *drv,
9955300040bSGhennadi Procopciuc 			    unsigned int depth);
9965300040bSGhennadi Procopciuc 
9978a4f840bSGhennadi Procopciuc static int enable_part(struct s32cc_clk_obj *module,
9988a4f840bSGhennadi Procopciuc 		       const struct s32cc_clk_drv *drv,
9998a4f840bSGhennadi Procopciuc 		       unsigned int depth)
10008a4f840bSGhennadi Procopciuc {
10018a4f840bSGhennadi Procopciuc 	const struct s32cc_part *part = s32cc_obj2part(module);
10028a4f840bSGhennadi Procopciuc 	uint32_t part_no = part->partition_id;
10038a4f840bSGhennadi Procopciuc 
10048a4f840bSGhennadi Procopciuc 	if ((drv->mc_me == 0UL) || (drv->mc_rgm == 0UL) || (drv->rdc == 0UL)) {
10058a4f840bSGhennadi Procopciuc 		return -EINVAL;
10068a4f840bSGhennadi Procopciuc 	}
10078a4f840bSGhennadi Procopciuc 
10088a4f840bSGhennadi Procopciuc 	return mc_me_enable_partition(drv->mc_me, drv->mc_rgm, drv->rdc, part_no);
10098a4f840bSGhennadi Procopciuc }
10108a4f840bSGhennadi Procopciuc 
10118a4f840bSGhennadi Procopciuc static int enable_part_block(struct s32cc_clk_obj *module,
10128a4f840bSGhennadi Procopciuc 			     const struct s32cc_clk_drv *drv,
10138a4f840bSGhennadi Procopciuc 			     unsigned int depth)
10148a4f840bSGhennadi Procopciuc {
10158a4f840bSGhennadi Procopciuc 	const struct s32cc_part_block *block = s32cc_obj2partblock(module);
10168a4f840bSGhennadi Procopciuc 	const struct s32cc_part *part = block->part;
10178a4f840bSGhennadi Procopciuc 	uint32_t part_no = part->partition_id;
10188a4f840bSGhennadi Procopciuc 	unsigned int ldepth = depth;
10198a4f840bSGhennadi Procopciuc 	uint32_t cofb;
10208a4f840bSGhennadi Procopciuc 	int ret;
10218a4f840bSGhennadi Procopciuc 
10228a4f840bSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
10238a4f840bSGhennadi Procopciuc 	if (ret != 0) {
10248a4f840bSGhennadi Procopciuc 		return ret;
10258a4f840bSGhennadi Procopciuc 	}
10268a4f840bSGhennadi Procopciuc 
10278a4f840bSGhennadi Procopciuc 	if ((block->block >= s32cc_part_block0) &&
10288a4f840bSGhennadi Procopciuc 	    (block->block <= s32cc_part_block15)) {
10298a4f840bSGhennadi Procopciuc 		cofb = (uint32_t)block->block - (uint32_t)s32cc_part_block0;
10308a4f840bSGhennadi Procopciuc 		mc_me_enable_part_cofb(drv->mc_me, part_no, cofb, block->status);
10318a4f840bSGhennadi Procopciuc 	} else {
10328a4f840bSGhennadi Procopciuc 		ERROR("Unknown partition block type: %d\n", block->block);
10338a4f840bSGhennadi Procopciuc 		return -EINVAL;
10348a4f840bSGhennadi Procopciuc 	}
10358a4f840bSGhennadi Procopciuc 
10368a4f840bSGhennadi Procopciuc 	return 0;
10378a4f840bSGhennadi Procopciuc }
10388a4f840bSGhennadi Procopciuc 
10398a4f840bSGhennadi Procopciuc static struct s32cc_clk_obj *
10408a4f840bSGhennadi Procopciuc get_part_block_parent(const struct s32cc_clk_obj *module)
10418a4f840bSGhennadi Procopciuc {
10428a4f840bSGhennadi Procopciuc 	const struct s32cc_part_block *block = s32cc_obj2partblock(module);
10438a4f840bSGhennadi Procopciuc 
10448a4f840bSGhennadi Procopciuc 	return &block->part->desc;
10458a4f840bSGhennadi Procopciuc }
10468a4f840bSGhennadi Procopciuc 
10478a4f840bSGhennadi Procopciuc static int enable_module_with_refcount(struct s32cc_clk_obj *module,
10488a4f840bSGhennadi Procopciuc 				       const struct s32cc_clk_drv *drv,
10498a4f840bSGhennadi Procopciuc 				       unsigned int depth);
10508a4f840bSGhennadi Procopciuc 
10518a4f840bSGhennadi Procopciuc static int enable_part_block_link(struct s32cc_clk_obj *module,
10528a4f840bSGhennadi Procopciuc 				  const struct s32cc_clk_drv *drv,
10538a4f840bSGhennadi Procopciuc 				  unsigned int depth)
10548a4f840bSGhennadi Procopciuc {
10558a4f840bSGhennadi Procopciuc 	const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module);
10568a4f840bSGhennadi Procopciuc 	struct s32cc_part_block *block = link->block;
10578a4f840bSGhennadi Procopciuc 	unsigned int ldepth = depth;
10588a4f840bSGhennadi Procopciuc 	int ret;
10598a4f840bSGhennadi Procopciuc 
10608a4f840bSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
10618a4f840bSGhennadi Procopciuc 	if (ret != 0) {
10628a4f840bSGhennadi Procopciuc 		return ret;
10638a4f840bSGhennadi Procopciuc 	}
10648a4f840bSGhennadi Procopciuc 
10658a4f840bSGhennadi Procopciuc 	/* Move the enablement algorithm to partition tree */
10668a4f840bSGhennadi Procopciuc 	return enable_module_with_refcount(&block->desc, drv, ldepth);
10678a4f840bSGhennadi Procopciuc }
10688a4f840bSGhennadi Procopciuc 
10698a4f840bSGhennadi Procopciuc static struct s32cc_clk_obj *
10708a4f840bSGhennadi Procopciuc get_part_block_link_parent(const struct s32cc_clk_obj *module)
10718a4f840bSGhennadi Procopciuc {
10728a4f840bSGhennadi Procopciuc 	const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module);
10738a4f840bSGhennadi Procopciuc 
10748a4f840bSGhennadi Procopciuc 	return link->parent;
10758a4f840bSGhennadi Procopciuc }
10768a4f840bSGhennadi Procopciuc 
1077a74cf75fSGhennadi Procopciuc static int get_part_block_link_freq(const struct s32cc_clk_obj *module,
1078a74cf75fSGhennadi Procopciuc 				    const struct s32cc_clk_drv *drv,
1079a74cf75fSGhennadi Procopciuc 				    unsigned long *rate, unsigned int depth)
1080a74cf75fSGhennadi Procopciuc {
1081a74cf75fSGhennadi Procopciuc 	const struct s32cc_part_block_link *block = s32cc_obj2partblocklink(module);
1082a74cf75fSGhennadi Procopciuc 	unsigned int ldepth = depth;
1083a74cf75fSGhennadi Procopciuc 	int ret;
1084a74cf75fSGhennadi Procopciuc 
1085a74cf75fSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1086a74cf75fSGhennadi Procopciuc 	if (ret != 0) {
1087a74cf75fSGhennadi Procopciuc 		return ret;
1088a74cf75fSGhennadi Procopciuc 	}
1089a74cf75fSGhennadi Procopciuc 
1090a74cf75fSGhennadi Procopciuc 	return get_module_rate(block->parent, drv, rate, ldepth);
1091a74cf75fSGhennadi Procopciuc }
1092a74cf75fSGhennadi Procopciuc 
1093*2710bdadSGhennadi Procopciuc static void cgm_mux_div_config(uintptr_t cgm_addr, uint32_t mux,
1094*2710bdadSGhennadi Procopciuc 			       uint32_t dc, uint32_t div_index)
1095*2710bdadSGhennadi Procopciuc {
1096*2710bdadSGhennadi Procopciuc 	uint32_t updstat;
1097*2710bdadSGhennadi Procopciuc 	uint32_t dc_val = mmio_read_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index));
1098*2710bdadSGhennadi Procopciuc 
1099*2710bdadSGhennadi Procopciuc 	dc_val &= (MC_CGM_MUXn_DCm_DIV_MASK | MC_CGM_MUXn_DCm_DE);
1100*2710bdadSGhennadi Procopciuc 
1101*2710bdadSGhennadi Procopciuc 	if (dc_val == (MC_CGM_MUXn_DCm_DE | MC_CGM_MUXn_DCm_DIV_SET(dc))) {
1102*2710bdadSGhennadi Procopciuc 		return;
1103*2710bdadSGhennadi Procopciuc 	}
1104*2710bdadSGhennadi Procopciuc 
1105*2710bdadSGhennadi Procopciuc 	/* Set the divider */
1106*2710bdadSGhennadi Procopciuc 	mmio_write_32(MC_CGM_MUXn_DCm(cgm_addr, mux, div_index),
1107*2710bdadSGhennadi Procopciuc 		      MC_CGM_MUXn_DCm_DE | MC_CGM_MUXn_DCm_DIV_SET(dc));
1108*2710bdadSGhennadi Procopciuc 
1109*2710bdadSGhennadi Procopciuc 	/* Wait for divider to get updated */
1110*2710bdadSGhennadi Procopciuc 	do {
1111*2710bdadSGhennadi Procopciuc 		updstat = mmio_read_32(MC_CGM_MUXn_DIV_UPD_STAT(cgm_addr, mux));
1112*2710bdadSGhennadi Procopciuc 	} while (MC_CGM_MUXn_DIV_UPD_STAT_DIVSTAT(updstat) != 0U);
1113*2710bdadSGhennadi Procopciuc }
1114*2710bdadSGhennadi Procopciuc 
1115*2710bdadSGhennadi Procopciuc static inline struct s32cc_clkmux *get_cgm_div_mux(const struct s32cc_cgm_div *cgm_div)
1116*2710bdadSGhennadi Procopciuc {
1117*2710bdadSGhennadi Procopciuc 	const struct s32cc_clk_obj *parent = cgm_div->parent;
1118*2710bdadSGhennadi Procopciuc 	const struct s32cc_clk_obj *mux_obj;
1119*2710bdadSGhennadi Procopciuc 	const struct s32cc_clk *clk;
1120*2710bdadSGhennadi Procopciuc 
1121*2710bdadSGhennadi Procopciuc 	if (parent == NULL) {
1122*2710bdadSGhennadi Procopciuc 		ERROR("Failed to identify CGM DIV's parent\n");
1123*2710bdadSGhennadi Procopciuc 		return NULL;
1124*2710bdadSGhennadi Procopciuc 	}
1125*2710bdadSGhennadi Procopciuc 
1126*2710bdadSGhennadi Procopciuc 	if (parent->type != s32cc_clk_t) {
1127*2710bdadSGhennadi Procopciuc 		ERROR("The parent of the CGM DIV isn't a clock\n");
1128*2710bdadSGhennadi Procopciuc 		return NULL;
1129*2710bdadSGhennadi Procopciuc 	}
1130*2710bdadSGhennadi Procopciuc 
1131*2710bdadSGhennadi Procopciuc 	clk = s32cc_obj2clk(parent);
1132*2710bdadSGhennadi Procopciuc 
1133*2710bdadSGhennadi Procopciuc 	if (clk->module == NULL) {
1134*2710bdadSGhennadi Procopciuc 		ERROR("The clock isn't connected to a module\n");
1135*2710bdadSGhennadi Procopciuc 		return NULL;
1136*2710bdadSGhennadi Procopciuc 	}
1137*2710bdadSGhennadi Procopciuc 
1138*2710bdadSGhennadi Procopciuc 	mux_obj = clk->module;
1139*2710bdadSGhennadi Procopciuc 
1140*2710bdadSGhennadi Procopciuc 	if ((mux_obj->type != s32cc_clkmux_t) &&
1141*2710bdadSGhennadi Procopciuc 	    (mux_obj->type != s32cc_shared_clkmux_t)) {
1142*2710bdadSGhennadi Procopciuc 		ERROR("The parent of the CGM DIV isn't a MUX\n");
1143*2710bdadSGhennadi Procopciuc 		return NULL;
1144*2710bdadSGhennadi Procopciuc 	}
1145*2710bdadSGhennadi Procopciuc 
1146*2710bdadSGhennadi Procopciuc 	return s32cc_obj2clkmux(mux_obj);
1147*2710bdadSGhennadi Procopciuc }
1148*2710bdadSGhennadi Procopciuc 
1149*2710bdadSGhennadi Procopciuc static int enable_cgm_div(struct s32cc_clk_obj *module,
1150*2710bdadSGhennadi Procopciuc 			  const struct s32cc_clk_drv *drv, unsigned int depth)
1151*2710bdadSGhennadi Procopciuc {
1152*2710bdadSGhennadi Procopciuc 	const struct s32cc_cgm_div *cgm_div = s32cc_obj2cgmdiv(module);
1153*2710bdadSGhennadi Procopciuc 	const struct s32cc_clkmux *mux;
1154*2710bdadSGhennadi Procopciuc 	unsigned int ldepth = depth;
1155*2710bdadSGhennadi Procopciuc 	uintptr_t cgm_addr = 0ULL;
1156*2710bdadSGhennadi Procopciuc 	uint64_t pfreq, dc64;
1157*2710bdadSGhennadi Procopciuc 	uint32_t dc;
1158*2710bdadSGhennadi Procopciuc 	int ret;
1159*2710bdadSGhennadi Procopciuc 
1160*2710bdadSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1161*2710bdadSGhennadi Procopciuc 	if (ret != 0) {
1162*2710bdadSGhennadi Procopciuc 		return ret;
1163*2710bdadSGhennadi Procopciuc 	}
1164*2710bdadSGhennadi Procopciuc 
1165*2710bdadSGhennadi Procopciuc 	if (cgm_div->parent == NULL) {
1166*2710bdadSGhennadi Procopciuc 		ERROR("Failed to identify CGM divider's parent\n");
1167*2710bdadSGhennadi Procopciuc 		return -EINVAL;
1168*2710bdadSGhennadi Procopciuc 	}
1169*2710bdadSGhennadi Procopciuc 
1170*2710bdadSGhennadi Procopciuc 	if (cgm_div->freq == 0U) {
1171*2710bdadSGhennadi Procopciuc 		ERROR("The frequency of the divider %" PRIu32 " is not set\n",
1172*2710bdadSGhennadi Procopciuc 		      cgm_div->index);
1173*2710bdadSGhennadi Procopciuc 		return -EINVAL;
1174*2710bdadSGhennadi Procopciuc 	}
1175*2710bdadSGhennadi Procopciuc 
1176*2710bdadSGhennadi Procopciuc 	mux = get_cgm_div_mux(cgm_div);
1177*2710bdadSGhennadi Procopciuc 	if (mux == NULL) {
1178*2710bdadSGhennadi Procopciuc 		return -EINVAL;
1179*2710bdadSGhennadi Procopciuc 	}
1180*2710bdadSGhennadi Procopciuc 
1181*2710bdadSGhennadi Procopciuc 	ret = get_base_addr(mux->module, drv, &cgm_addr);
1182*2710bdadSGhennadi Procopciuc 	if (ret != 0) {
1183*2710bdadSGhennadi Procopciuc 		ERROR("Failed to get CGM base address of the MUX module %d\n",
1184*2710bdadSGhennadi Procopciuc 		      mux->module);
1185*2710bdadSGhennadi Procopciuc 		return ret;
1186*2710bdadSGhennadi Procopciuc 	}
1187*2710bdadSGhennadi Procopciuc 
1188*2710bdadSGhennadi Procopciuc 	ret = get_module_rate(cgm_div->parent, drv, &pfreq, ldepth);
1189*2710bdadSGhennadi Procopciuc 	if (ret != 0) {
1190*2710bdadSGhennadi Procopciuc 		ERROR("Failed to enable the div due to unknown frequency of "
1191*2710bdadSGhennadi Procopciuc 		      "the CGM MUX %" PRIu8 "(CGM=%" PRIxPTR ")\n",
1192*2710bdadSGhennadi Procopciuc 		      mux->index, cgm_addr);
1193*2710bdadSGhennadi Procopciuc 		return -EINVAL;
1194*2710bdadSGhennadi Procopciuc 	}
1195*2710bdadSGhennadi Procopciuc 
1196*2710bdadSGhennadi Procopciuc 	dc64 = ((pfreq * FP_PRECISION) / cgm_div->freq) / FP_PRECISION;
1197*2710bdadSGhennadi Procopciuc 	dc = (uint32_t)dc64;
1198*2710bdadSGhennadi Procopciuc 
1199*2710bdadSGhennadi Procopciuc 	if ((pfreq / dc64) != cgm_div->freq) {
1200*2710bdadSGhennadi Procopciuc 		ERROR("Cannot set CGM divider (mux:%" PRIu8 ", div:%" PRIu32
1201*2710bdadSGhennadi Procopciuc 		      ") for input = %lu & output = %lu, Nearest freq = %lu\n",
1202*2710bdadSGhennadi Procopciuc 		mux->index, cgm_div->index, (unsigned long)pfreq,
1203*2710bdadSGhennadi Procopciuc 		cgm_div->freq, (unsigned long)(pfreq / dc));
1204*2710bdadSGhennadi Procopciuc 		return -EINVAL;
1205*2710bdadSGhennadi Procopciuc 	}
1206*2710bdadSGhennadi Procopciuc 
1207*2710bdadSGhennadi Procopciuc 	cgm_mux_div_config(cgm_addr, mux->index, dc - 1U, cgm_div->index);
1208*2710bdadSGhennadi Procopciuc 	return 0;
1209*2710bdadSGhennadi Procopciuc }
1210*2710bdadSGhennadi Procopciuc 
12115300040bSGhennadi Procopciuc static int no_enable(struct s32cc_clk_obj *module,
12125300040bSGhennadi Procopciuc 		     const struct s32cc_clk_drv *drv,
12135300040bSGhennadi Procopciuc 		     unsigned int depth)
12148ab34357SGhennadi Procopciuc {
12155300040bSGhennadi Procopciuc 	return 0;
12165300040bSGhennadi Procopciuc }
12175300040bSGhennadi Procopciuc 
12185300040bSGhennadi Procopciuc static int exec_cb_with_refcount(enable_clk_t en_cb, struct s32cc_clk_obj *mod,
12195300040bSGhennadi Procopciuc 				 const struct s32cc_clk_drv *drv, bool leaf_node,
12205300040bSGhennadi Procopciuc 				 unsigned int depth)
12215300040bSGhennadi Procopciuc {
12228ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
12238ab34357SGhennadi Procopciuc 	int ret = 0;
12248ab34357SGhennadi Procopciuc 
12255300040bSGhennadi Procopciuc 	if (mod == NULL) {
12265300040bSGhennadi Procopciuc 		return 0;
12275300040bSGhennadi Procopciuc 	}
12285300040bSGhennadi Procopciuc 
12298ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
12305300040bSGhennadi Procopciuc 	if (ret != 0) {
12315300040bSGhennadi Procopciuc 		return ret;
12325300040bSGhennadi Procopciuc 	}
12335300040bSGhennadi Procopciuc 
12345300040bSGhennadi Procopciuc 	/* Refcount will be updated as part of the recursivity */
12355300040bSGhennadi Procopciuc 	if (leaf_node) {
12368ee0fc31SGhennadi Procopciuc 		return en_cb(mod, drv, ldepth);
12375300040bSGhennadi Procopciuc 	}
12385300040bSGhennadi Procopciuc 
12395300040bSGhennadi Procopciuc 	if (mod->refcount == 0U) {
12408ee0fc31SGhennadi Procopciuc 		ret = en_cb(mod, drv, ldepth);
12415300040bSGhennadi Procopciuc 	}
12425300040bSGhennadi Procopciuc 
12435300040bSGhennadi Procopciuc 	if (ret == 0) {
12445300040bSGhennadi Procopciuc 		mod->refcount++;
12455300040bSGhennadi Procopciuc 	}
12465300040bSGhennadi Procopciuc 
12475300040bSGhennadi Procopciuc 	return ret;
12485300040bSGhennadi Procopciuc }
12495300040bSGhennadi Procopciuc 
12505300040bSGhennadi Procopciuc static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module);
12515300040bSGhennadi Procopciuc 
12525300040bSGhennadi Procopciuc static int enable_module(struct s32cc_clk_obj *module,
12535300040bSGhennadi Procopciuc 			 const struct s32cc_clk_drv *drv,
12545300040bSGhennadi Procopciuc 			 unsigned int depth)
12555300040bSGhennadi Procopciuc {
12565300040bSGhennadi Procopciuc 	struct s32cc_clk_obj *parent = get_module_parent(module);
125763d536feSGhennadi Procopciuc 	static const enable_clk_t enable_clbs[13] = {
12585300040bSGhennadi Procopciuc 		[s32cc_clk_t] = no_enable,
12595300040bSGhennadi Procopciuc 		[s32cc_osc_t] = enable_osc,
12605300040bSGhennadi Procopciuc 		[s32cc_pll_t] = enable_pll,
12615300040bSGhennadi Procopciuc 		[s32cc_pll_out_div_t] = enable_pll_div,
12625300040bSGhennadi Procopciuc 		[s32cc_clkmux_t] = enable_mux,
12635300040bSGhennadi Procopciuc 		[s32cc_shared_clkmux_t] = enable_mux,
12645300040bSGhennadi Procopciuc 		[s32cc_dfs_t] = enable_dfs,
12655300040bSGhennadi Procopciuc 		[s32cc_dfs_div_t] = enable_dfs_div,
12668a4f840bSGhennadi Procopciuc 		[s32cc_part_t] = enable_part,
12678a4f840bSGhennadi Procopciuc 		[s32cc_part_block_t] = enable_part_block,
12688a4f840bSGhennadi Procopciuc 		[s32cc_part_block_link_t] = enable_part_block_link,
1269*2710bdadSGhennadi Procopciuc 		[s32cc_cgm_div_t] = enable_cgm_div,
12705300040bSGhennadi Procopciuc 	};
12718ee0fc31SGhennadi Procopciuc 	unsigned int ldepth = depth;
12725300040bSGhennadi Procopciuc 	uint32_t index;
12735300040bSGhennadi Procopciuc 	int ret = 0;
12745300040bSGhennadi Procopciuc 
12758ee0fc31SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
12768ab34357SGhennadi Procopciuc 	if (ret != 0) {
12778ab34357SGhennadi Procopciuc 		return ret;
12788ab34357SGhennadi Procopciuc 	}
12798ab34357SGhennadi Procopciuc 
12808ab34357SGhennadi Procopciuc 	if (drv == NULL) {
12818ab34357SGhennadi Procopciuc 		return -EINVAL;
12828ab34357SGhennadi Procopciuc 	}
12838ab34357SGhennadi Procopciuc 
12845300040bSGhennadi Procopciuc 	index = (uint32_t)module->type;
12855300040bSGhennadi Procopciuc 
12865300040bSGhennadi Procopciuc 	if (index >= ARRAY_SIZE(enable_clbs)) {
12875300040bSGhennadi Procopciuc 		ERROR("Undefined module type: %d\n", module->type);
12885300040bSGhennadi Procopciuc 		return -EINVAL;
12895300040bSGhennadi Procopciuc 	}
12905300040bSGhennadi Procopciuc 
12915300040bSGhennadi Procopciuc 	if (enable_clbs[index] == NULL) {
12925300040bSGhennadi Procopciuc 		ERROR("Undefined callback for the clock type: %d\n",
12935300040bSGhennadi Procopciuc 		      module->type);
12945300040bSGhennadi Procopciuc 		return -EINVAL;
12955300040bSGhennadi Procopciuc 	}
12965300040bSGhennadi Procopciuc 
12975300040bSGhennadi Procopciuc 	parent = get_module_parent(module);
12985300040bSGhennadi Procopciuc 
12995300040bSGhennadi Procopciuc 	ret = exec_cb_with_refcount(enable_module, parent, drv,
13008ee0fc31SGhennadi Procopciuc 				    false, ldepth);
13015300040bSGhennadi Procopciuc 	if (ret != 0) {
13025300040bSGhennadi Procopciuc 		return ret;
13035300040bSGhennadi Procopciuc 	}
13045300040bSGhennadi Procopciuc 
13055300040bSGhennadi Procopciuc 	ret = exec_cb_with_refcount(enable_clbs[index], module, drv,
13068ee0fc31SGhennadi Procopciuc 				    true, ldepth);
13075300040bSGhennadi Procopciuc 	if (ret != 0) {
13085300040bSGhennadi Procopciuc 		return ret;
13098ab34357SGhennadi Procopciuc 	}
13108ab34357SGhennadi Procopciuc 
13118ab34357SGhennadi Procopciuc 	return ret;
13128ab34357SGhennadi Procopciuc }
13138ab34357SGhennadi Procopciuc 
13145300040bSGhennadi Procopciuc static int enable_module_with_refcount(struct s32cc_clk_obj *module,
13155300040bSGhennadi Procopciuc 				       const struct s32cc_clk_drv *drv,
13165300040bSGhennadi Procopciuc 				       unsigned int depth)
13175300040bSGhennadi Procopciuc {
13185300040bSGhennadi Procopciuc 	return exec_cb_with_refcount(enable_module, module, drv, false, depth);
13195300040bSGhennadi Procopciuc }
13205300040bSGhennadi Procopciuc 
13213a580e9eSGhennadi Procopciuc static int s32cc_clk_enable(unsigned long id)
13223a580e9eSGhennadi Procopciuc {
13235300040bSGhennadi Procopciuc 	const struct s32cc_clk_drv *drv = get_drv();
13248ab34357SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
13255300040bSGhennadi Procopciuc 	struct s32cc_clk *clk;
13268ab34357SGhennadi Procopciuc 
13278ab34357SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
13288ab34357SGhennadi Procopciuc 	if (clk == NULL) {
13298ab34357SGhennadi Procopciuc 		return -EINVAL;
13308ab34357SGhennadi Procopciuc 	}
13318ab34357SGhennadi Procopciuc 
13325300040bSGhennadi Procopciuc 	return enable_module_with_refcount(&clk->desc, drv, depth);
13333a580e9eSGhennadi Procopciuc }
13343a580e9eSGhennadi Procopciuc 
13353a580e9eSGhennadi Procopciuc static void s32cc_clk_disable(unsigned long id)
13363a580e9eSGhennadi Procopciuc {
13373a580e9eSGhennadi Procopciuc }
13383a580e9eSGhennadi Procopciuc 
13393a580e9eSGhennadi Procopciuc static bool s32cc_clk_is_enabled(unsigned long id)
13403a580e9eSGhennadi Procopciuc {
13413a580e9eSGhennadi Procopciuc 	return false;
13423a580e9eSGhennadi Procopciuc }
13433a580e9eSGhennadi Procopciuc 
1344d9373519SGhennadi Procopciuc static int set_osc_freq(const struct s32cc_clk_obj *module, unsigned long rate,
1345d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
1346d9373519SGhennadi Procopciuc {
1347d9373519SGhennadi Procopciuc 	struct s32cc_osc *osc = s32cc_obj2osc(module);
1348d9373519SGhennadi Procopciuc 	int ret;
1349d9373519SGhennadi Procopciuc 
1350d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1351d9373519SGhennadi Procopciuc 	if (ret != 0) {
1352d9373519SGhennadi Procopciuc 		return ret;
1353d9373519SGhennadi Procopciuc 	}
1354d9373519SGhennadi Procopciuc 
1355d9373519SGhennadi Procopciuc 	if ((osc->freq != 0UL) && (rate != osc->freq)) {
1356d9373519SGhennadi Procopciuc 		ERROR("Already initialized oscillator. freq = %lu\n",
1357d9373519SGhennadi Procopciuc 		      osc->freq);
1358d9373519SGhennadi Procopciuc 		return -EINVAL;
1359d9373519SGhennadi Procopciuc 	}
1360d9373519SGhennadi Procopciuc 
1361d9373519SGhennadi Procopciuc 	osc->freq = rate;
1362d9373519SGhennadi Procopciuc 	*orate = osc->freq;
1363d9373519SGhennadi Procopciuc 
1364d9373519SGhennadi Procopciuc 	return 0;
1365d9373519SGhennadi Procopciuc }
1366d9373519SGhennadi Procopciuc 
1367bd691136SGhennadi Procopciuc static int get_osc_freq(const struct s32cc_clk_obj *module,
1368bd691136SGhennadi Procopciuc 			const struct s32cc_clk_drv *drv,
1369bd691136SGhennadi Procopciuc 			unsigned long *rate, unsigned int depth)
1370bd691136SGhennadi Procopciuc {
1371bd691136SGhennadi Procopciuc 	const struct s32cc_osc *osc = s32cc_obj2osc(module);
1372bd691136SGhennadi Procopciuc 	unsigned int ldepth = depth;
1373bd691136SGhennadi Procopciuc 	int ret;
1374bd691136SGhennadi Procopciuc 
1375bd691136SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1376bd691136SGhennadi Procopciuc 	if (ret != 0) {
1377bd691136SGhennadi Procopciuc 		return ret;
1378bd691136SGhennadi Procopciuc 	}
1379bd691136SGhennadi Procopciuc 
1380bd691136SGhennadi Procopciuc 	if (osc->freq == 0UL) {
1381bd691136SGhennadi Procopciuc 		ERROR("Uninitialized oscillator\n");
1382bd691136SGhennadi Procopciuc 		return -EINVAL;
1383bd691136SGhennadi Procopciuc 	}
1384bd691136SGhennadi Procopciuc 
1385bd691136SGhennadi Procopciuc 	*rate = osc->freq;
1386bd691136SGhennadi Procopciuc 
1387bd691136SGhennadi Procopciuc 	return 0;
1388bd691136SGhennadi Procopciuc }
1389bd691136SGhennadi Procopciuc 
1390d9373519SGhennadi Procopciuc static int set_clk_freq(const struct s32cc_clk_obj *module, unsigned long rate,
1391d9373519SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
1392d9373519SGhennadi Procopciuc {
1393d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
1394d9373519SGhennadi Procopciuc 	int ret;
1395d9373519SGhennadi Procopciuc 
1396d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1397d9373519SGhennadi Procopciuc 	if (ret != 0) {
1398d9373519SGhennadi Procopciuc 		return ret;
1399d9373519SGhennadi Procopciuc 	}
1400d9373519SGhennadi Procopciuc 
1401d9373519SGhennadi Procopciuc 	if ((clk->min_freq != 0UL) && (clk->max_freq != 0UL) &&
1402d9373519SGhennadi Procopciuc 	    ((rate < clk->min_freq) || (rate > clk->max_freq))) {
1403d9373519SGhennadi Procopciuc 		ERROR("%lu frequency is out of the allowed range: [%lu:%lu]\n",
1404d9373519SGhennadi Procopciuc 		      rate, clk->min_freq, clk->max_freq);
1405d9373519SGhennadi Procopciuc 		return -EINVAL;
1406d9373519SGhennadi Procopciuc 	}
1407d9373519SGhennadi Procopciuc 
1408d9373519SGhennadi Procopciuc 	if (clk->module != NULL) {
1409d9373519SGhennadi Procopciuc 		return set_module_rate(clk->module, rate, orate, depth);
1410d9373519SGhennadi Procopciuc 	}
1411d9373519SGhennadi Procopciuc 
1412d9373519SGhennadi Procopciuc 	if (clk->pclock != NULL) {
1413d9373519SGhennadi Procopciuc 		return set_clk_freq(&clk->pclock->desc, rate, orate, depth);
1414d9373519SGhennadi Procopciuc 	}
1415d9373519SGhennadi Procopciuc 
1416d9373519SGhennadi Procopciuc 	return -EINVAL;
1417d9373519SGhennadi Procopciuc }
1418d9373519SGhennadi Procopciuc 
141946de0b9cSGhennadi Procopciuc static int get_clk_freq(const struct s32cc_clk_obj *module,
142046de0b9cSGhennadi Procopciuc 			const struct s32cc_clk_drv *drv, unsigned long *rate,
142146de0b9cSGhennadi Procopciuc 			unsigned int depth)
142246de0b9cSGhennadi Procopciuc {
142346de0b9cSGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_obj2clk(module);
142446de0b9cSGhennadi Procopciuc 	unsigned int ldepth = depth;
142546de0b9cSGhennadi Procopciuc 	int ret;
142646de0b9cSGhennadi Procopciuc 
142746de0b9cSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
142846de0b9cSGhennadi Procopciuc 	if (ret != 0) {
142946de0b9cSGhennadi Procopciuc 		return ret;
143046de0b9cSGhennadi Procopciuc 	}
143146de0b9cSGhennadi Procopciuc 
143246de0b9cSGhennadi Procopciuc 	if (clk == NULL) {
143346de0b9cSGhennadi Procopciuc 		ERROR("Invalid clock\n");
143446de0b9cSGhennadi Procopciuc 		return -EINVAL;
143546de0b9cSGhennadi Procopciuc 	}
143646de0b9cSGhennadi Procopciuc 
143746de0b9cSGhennadi Procopciuc 	if (clk->module != NULL) {
143846de0b9cSGhennadi Procopciuc 		return get_module_rate(clk->module, drv, rate, ldepth);
143946de0b9cSGhennadi Procopciuc 	}
144046de0b9cSGhennadi Procopciuc 
144146de0b9cSGhennadi Procopciuc 	if (clk->pclock == NULL) {
144246de0b9cSGhennadi Procopciuc 		ERROR("Invalid clock parent\n");
144346de0b9cSGhennadi Procopciuc 		return -EINVAL;
144446de0b9cSGhennadi Procopciuc 	}
144546de0b9cSGhennadi Procopciuc 
144646de0b9cSGhennadi Procopciuc 	return get_clk_freq(&clk->pclock->desc, drv, rate, ldepth);
144746de0b9cSGhennadi Procopciuc }
144846de0b9cSGhennadi Procopciuc 
14497ad4e231SGhennadi Procopciuc static int set_pll_freq(const struct s32cc_clk_obj *module, unsigned long rate,
14507ad4e231SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
14517ad4e231SGhennadi Procopciuc {
14527ad4e231SGhennadi Procopciuc 	struct s32cc_pll *pll = s32cc_obj2pll(module);
14537ad4e231SGhennadi Procopciuc 	int ret;
14547ad4e231SGhennadi Procopciuc 
14557ad4e231SGhennadi Procopciuc 	ret = update_stack_depth(depth);
14567ad4e231SGhennadi Procopciuc 	if (ret != 0) {
14577ad4e231SGhennadi Procopciuc 		return ret;
14587ad4e231SGhennadi Procopciuc 	}
14597ad4e231SGhennadi Procopciuc 
14607ad4e231SGhennadi Procopciuc 	if ((pll->vco_freq != 0UL) && (pll->vco_freq != rate)) {
14617ad4e231SGhennadi Procopciuc 		ERROR("PLL frequency was already set\n");
14627ad4e231SGhennadi Procopciuc 		return -EINVAL;
14637ad4e231SGhennadi Procopciuc 	}
14647ad4e231SGhennadi Procopciuc 
14657ad4e231SGhennadi Procopciuc 	pll->vco_freq = rate;
14667ad4e231SGhennadi Procopciuc 	*orate = pll->vco_freq;
14677ad4e231SGhennadi Procopciuc 
14687ad4e231SGhennadi Procopciuc 	return 0;
14697ad4e231SGhennadi Procopciuc }
14707ad4e231SGhennadi Procopciuc 
1471fbebafa5SGhennadi Procopciuc static int get_pll_freq(const struct s32cc_clk_obj *module,
1472fbebafa5SGhennadi Procopciuc 			const struct s32cc_clk_drv *drv,
1473fbebafa5SGhennadi Procopciuc 			unsigned long *rate, unsigned int depth)
1474fbebafa5SGhennadi Procopciuc {
1475fbebafa5SGhennadi Procopciuc 	const struct s32cc_pll *pll = s32cc_obj2pll(module);
1476fbebafa5SGhennadi Procopciuc 	const struct s32cc_clk *source;
1477fbebafa5SGhennadi Procopciuc 	uint32_t mfi, mfn, rdiv, plldv;
1478fbebafa5SGhennadi Procopciuc 	unsigned long prate, clk_src;
1479fbebafa5SGhennadi Procopciuc 	unsigned int ldepth = depth;
1480fbebafa5SGhennadi Procopciuc 	uintptr_t pll_addr = 0UL;
1481fbebafa5SGhennadi Procopciuc 	uint64_t t1, t2;
1482fbebafa5SGhennadi Procopciuc 	int ret;
1483fbebafa5SGhennadi Procopciuc 
1484fbebafa5SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1485fbebafa5SGhennadi Procopciuc 	if (ret != 0) {
1486fbebafa5SGhennadi Procopciuc 		return ret;
1487fbebafa5SGhennadi Procopciuc 	}
1488fbebafa5SGhennadi Procopciuc 
1489fbebafa5SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
1490fbebafa5SGhennadi Procopciuc 	if (ret != 0) {
1491fbebafa5SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
1492fbebafa5SGhennadi Procopciuc 		return ret;
1493fbebafa5SGhennadi Procopciuc 	}
1494fbebafa5SGhennadi Procopciuc 
1495fbebafa5SGhennadi Procopciuc 	/* Disabled PLL */
1496c23dde6cSGhennadi Procopciuc 	if (!is_pll_enabled(pll_addr)) {
1497fbebafa5SGhennadi Procopciuc 		*rate = pll->vco_freq;
1498fbebafa5SGhennadi Procopciuc 		return 0;
1499fbebafa5SGhennadi Procopciuc 	}
1500fbebafa5SGhennadi Procopciuc 
1501fbebafa5SGhennadi Procopciuc 	clk_src = mmio_read_32(PLLDIG_PLLCLKMUX(pll_addr));
1502fbebafa5SGhennadi Procopciuc 	switch (clk_src) {
1503fbebafa5SGhennadi Procopciuc 	case 0:
1504fbebafa5SGhennadi Procopciuc 		clk_src = S32CC_CLK_FIRC;
1505fbebafa5SGhennadi Procopciuc 		break;
1506fbebafa5SGhennadi Procopciuc 	case 1:
1507fbebafa5SGhennadi Procopciuc 		clk_src = S32CC_CLK_FXOSC;
1508fbebafa5SGhennadi Procopciuc 		break;
1509fbebafa5SGhennadi Procopciuc 	default:
1510fbebafa5SGhennadi Procopciuc 		ERROR("Failed to identify PLL source id %" PRIu64 "\n", clk_src);
1511fbebafa5SGhennadi Procopciuc 		return -EINVAL;
1512fbebafa5SGhennadi Procopciuc 	};
1513fbebafa5SGhennadi Procopciuc 
1514fbebafa5SGhennadi Procopciuc 	source = s32cc_get_arch_clk(clk_src);
1515fbebafa5SGhennadi Procopciuc 	if (source == NULL) {
1516fbebafa5SGhennadi Procopciuc 		ERROR("Failed to get PLL source clock\n");
1517fbebafa5SGhennadi Procopciuc 		return -EINVAL;
1518fbebafa5SGhennadi Procopciuc 	}
1519fbebafa5SGhennadi Procopciuc 
1520fbebafa5SGhennadi Procopciuc 	ret = get_module_rate(&source->desc, drv, &prate, ldepth);
1521fbebafa5SGhennadi Procopciuc 	if (ret != 0) {
1522fbebafa5SGhennadi Procopciuc 		ERROR("Failed to get PLL's parent frequency\n");
1523fbebafa5SGhennadi Procopciuc 		return ret;
1524fbebafa5SGhennadi Procopciuc 	}
1525fbebafa5SGhennadi Procopciuc 
1526fbebafa5SGhennadi Procopciuc 	plldv = mmio_read_32(PLLDIG_PLLDV(pll_addr));
1527fbebafa5SGhennadi Procopciuc 	mfi = PLLDIG_PLLDV_MFI(plldv);
1528fbebafa5SGhennadi Procopciuc 	rdiv = PLLDIG_PLLDV_RDIV(plldv);
1529fbebafa5SGhennadi Procopciuc 	if (rdiv == 0U) {
1530fbebafa5SGhennadi Procopciuc 		rdiv = 1;
1531fbebafa5SGhennadi Procopciuc 	}
1532fbebafa5SGhennadi Procopciuc 
1533fbebafa5SGhennadi Procopciuc 	/* Frac-N mode */
1534fbebafa5SGhennadi Procopciuc 	mfn = PLLDIG_PLLFD_MFN_SET(mmio_read_32(PLLDIG_PLLFD(pll_addr)));
1535fbebafa5SGhennadi Procopciuc 
1536fbebafa5SGhennadi Procopciuc 	/* PLL VCO frequency in Fractional mode when PLLDV[RDIV] is not 0 */
1537fbebafa5SGhennadi Procopciuc 	t1 = prate / rdiv;
1538fbebafa5SGhennadi Procopciuc 	t2 = (mfi * FP_PRECISION) + (mfn * FP_PRECISION / 18432U);
1539fbebafa5SGhennadi Procopciuc 
1540fbebafa5SGhennadi Procopciuc 	*rate = t1 * t2 / FP_PRECISION;
1541fbebafa5SGhennadi Procopciuc 
1542fbebafa5SGhennadi Procopciuc 	return 0;
1543fbebafa5SGhennadi Procopciuc }
1544fbebafa5SGhennadi Procopciuc 
1545de950ef0SGhennadi Procopciuc static int set_pll_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
1546de950ef0SGhennadi Procopciuc 			    unsigned long *orate, unsigned int *depth)
1547de950ef0SGhennadi Procopciuc {
1548de950ef0SGhennadi Procopciuc 	struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
1549de950ef0SGhennadi Procopciuc 	const struct s32cc_pll *pll;
1550de950ef0SGhennadi Procopciuc 	unsigned long prate, dc;
1551de950ef0SGhennadi Procopciuc 	int ret;
1552de950ef0SGhennadi Procopciuc 
1553de950ef0SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1554de950ef0SGhennadi Procopciuc 	if (ret != 0) {
1555de950ef0SGhennadi Procopciuc 		return ret;
1556de950ef0SGhennadi Procopciuc 	}
1557de950ef0SGhennadi Procopciuc 
1558de950ef0SGhennadi Procopciuc 	if (pdiv->parent == NULL) {
1559de950ef0SGhennadi Procopciuc 		ERROR("Failed to identify PLL divider's parent\n");
1560de950ef0SGhennadi Procopciuc 		return -EINVAL;
1561de950ef0SGhennadi Procopciuc 	}
1562de950ef0SGhennadi Procopciuc 
1563de950ef0SGhennadi Procopciuc 	pll = s32cc_obj2pll(pdiv->parent);
1564de950ef0SGhennadi Procopciuc 	if (pll == NULL) {
1565de950ef0SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
1566de950ef0SGhennadi Procopciuc 		return -EINVAL;
1567de950ef0SGhennadi Procopciuc 	}
1568de950ef0SGhennadi Procopciuc 
1569de950ef0SGhennadi Procopciuc 	prate = pll->vco_freq;
1570de950ef0SGhennadi Procopciuc 
1571de950ef0SGhennadi Procopciuc 	/**
1572de950ef0SGhennadi Procopciuc 	 * The PLL is not initialized yet, so let's take a risk
1573de950ef0SGhennadi Procopciuc 	 * and accept the proposed rate.
1574de950ef0SGhennadi Procopciuc 	 */
1575de950ef0SGhennadi Procopciuc 	if (prate == 0UL) {
1576de950ef0SGhennadi Procopciuc 		pdiv->freq = rate;
1577de950ef0SGhennadi Procopciuc 		*orate = rate;
1578de950ef0SGhennadi Procopciuc 		return 0;
1579de950ef0SGhennadi Procopciuc 	}
1580de950ef0SGhennadi Procopciuc 
1581de950ef0SGhennadi Procopciuc 	/* Decline in case the rate cannot fit PLL's requirements. */
1582de950ef0SGhennadi Procopciuc 	dc = prate / rate;
1583de950ef0SGhennadi Procopciuc 	if ((prate / dc) != rate) {
1584de950ef0SGhennadi Procopciuc 		return -EINVAL;
1585de950ef0SGhennadi Procopciuc 	}
1586de950ef0SGhennadi Procopciuc 
1587de950ef0SGhennadi Procopciuc 	pdiv->freq = rate;
1588de950ef0SGhennadi Procopciuc 	*orate = pdiv->freq;
1589de950ef0SGhennadi Procopciuc 
1590de950ef0SGhennadi Procopciuc 	return 0;
1591de950ef0SGhennadi Procopciuc }
1592de950ef0SGhennadi Procopciuc 
1593a762c505SGhennadi Procopciuc static int get_pll_div_freq(const struct s32cc_clk_obj *module,
1594a762c505SGhennadi Procopciuc 			    const struct s32cc_clk_drv *drv,
1595a762c505SGhennadi Procopciuc 			    unsigned long *rate, unsigned int depth)
1596a762c505SGhennadi Procopciuc {
1597a762c505SGhennadi Procopciuc 	const struct s32cc_pll_out_div *pdiv = s32cc_obj2plldiv(module);
1598a762c505SGhennadi Procopciuc 	const struct s32cc_pll *pll;
1599a762c505SGhennadi Procopciuc 	unsigned int ldepth = depth;
1600a762c505SGhennadi Procopciuc 	uintptr_t pll_addr = 0UL;
1601a762c505SGhennadi Procopciuc 	unsigned long pfreq;
1602a762c505SGhennadi Procopciuc 	uint32_t pllodiv;
1603a762c505SGhennadi Procopciuc 	uint32_t dc;
1604a762c505SGhennadi Procopciuc 	int ret;
1605a762c505SGhennadi Procopciuc 
1606a762c505SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1607a762c505SGhennadi Procopciuc 	if (ret != 0) {
1608a762c505SGhennadi Procopciuc 		return ret;
1609a762c505SGhennadi Procopciuc 	}
1610a762c505SGhennadi Procopciuc 
1611a762c505SGhennadi Procopciuc 	pll = get_div_pll(pdiv);
1612a762c505SGhennadi Procopciuc 	if (pll == NULL) {
1613a762c505SGhennadi Procopciuc 		ERROR("The parent of the PLL DIV is invalid\n");
1614a762c505SGhennadi Procopciuc 		return -EINVAL;
1615a762c505SGhennadi Procopciuc 	}
1616a762c505SGhennadi Procopciuc 
1617a762c505SGhennadi Procopciuc 	ret = get_base_addr(pll->instance, drv, &pll_addr);
1618a762c505SGhennadi Procopciuc 	if (ret != 0) {
1619a762c505SGhennadi Procopciuc 		ERROR("Failed to detect PLL instance\n");
1620a762c505SGhennadi Procopciuc 		return -EINVAL;
1621a762c505SGhennadi Procopciuc 	}
1622a762c505SGhennadi Procopciuc 
1623a762c505SGhennadi Procopciuc 	ret = get_module_rate(pdiv->parent, drv, &pfreq, ldepth);
1624a762c505SGhennadi Procopciuc 	if (ret != 0) {
1625a762c505SGhennadi Procopciuc 		ERROR("Failed to get the frequency of PLL %" PRIxPTR "\n",
1626a762c505SGhennadi Procopciuc 		      pll_addr);
1627a762c505SGhennadi Procopciuc 		return ret;
1628a762c505SGhennadi Procopciuc 	}
1629a762c505SGhennadi Procopciuc 
1630a762c505SGhennadi Procopciuc 	pllodiv = mmio_read_32(PLLDIG_PLLODIV(pll_addr, pdiv->index));
1631a762c505SGhennadi Procopciuc 
1632a762c505SGhennadi Procopciuc 	/* Disabled module */
1633a762c505SGhennadi Procopciuc 	if ((pllodiv & PLLDIG_PLLODIV_DE) == 0U) {
1634a762c505SGhennadi Procopciuc 		*rate = pdiv->freq;
1635a762c505SGhennadi Procopciuc 		return 0;
1636a762c505SGhennadi Procopciuc 	}
1637a762c505SGhennadi Procopciuc 
1638a762c505SGhennadi Procopciuc 	dc = PLLDIG_PLLODIV_DIV(pllodiv);
1639a762c505SGhennadi Procopciuc 	*rate = (pfreq * FP_PRECISION) / (dc + 1U) / FP_PRECISION;
1640a762c505SGhennadi Procopciuc 
1641a762c505SGhennadi Procopciuc 	return 0;
1642a762c505SGhennadi Procopciuc }
1643a762c505SGhennadi Procopciuc 
164465739db2SGhennadi Procopciuc static int set_fixed_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
164565739db2SGhennadi Procopciuc 			      unsigned long *orate, unsigned int *depth)
164665739db2SGhennadi Procopciuc {
164765739db2SGhennadi Procopciuc 	const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module);
164865739db2SGhennadi Procopciuc 	int ret;
164965739db2SGhennadi Procopciuc 
165065739db2SGhennadi Procopciuc 	ret = update_stack_depth(depth);
165165739db2SGhennadi Procopciuc 	if (ret != 0) {
165265739db2SGhennadi Procopciuc 		return ret;
165365739db2SGhennadi Procopciuc 	}
165465739db2SGhennadi Procopciuc 
165565739db2SGhennadi Procopciuc 	if (fdiv->parent == NULL) {
165665739db2SGhennadi Procopciuc 		ERROR("The divider doesn't have a valid parent\b");
165765739db2SGhennadi Procopciuc 		return -EINVAL;
165865739db2SGhennadi Procopciuc 	}
165965739db2SGhennadi Procopciuc 
166065739db2SGhennadi Procopciuc 	ret = set_module_rate(fdiv->parent, rate * fdiv->rate_div, orate, depth);
166165739db2SGhennadi Procopciuc 
166265739db2SGhennadi Procopciuc 	/* Update the output rate based on the parent's rate */
166365739db2SGhennadi Procopciuc 	*orate /= fdiv->rate_div;
166465739db2SGhennadi Procopciuc 
166565739db2SGhennadi Procopciuc 	return ret;
166665739db2SGhennadi Procopciuc }
166765739db2SGhennadi Procopciuc 
16687c298ebcSGhennadi Procopciuc static int get_fixed_div_freq(const struct s32cc_clk_obj *module,
16697c298ebcSGhennadi Procopciuc 			      const struct s32cc_clk_drv *drv,
16707c298ebcSGhennadi Procopciuc 			      unsigned long *rate, unsigned int depth)
16717c298ebcSGhennadi Procopciuc {
16727c298ebcSGhennadi Procopciuc 	const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module);
16737c298ebcSGhennadi Procopciuc 	unsigned long pfreq;
16747c298ebcSGhennadi Procopciuc 	int ret;
16757c298ebcSGhennadi Procopciuc 
16767c298ebcSGhennadi Procopciuc 	ret = get_module_rate(fdiv->parent, drv, &pfreq, depth);
16777c298ebcSGhennadi Procopciuc 	if (ret != 0) {
16787c298ebcSGhennadi Procopciuc 		return ret;
16797c298ebcSGhennadi Procopciuc 	}
16807c298ebcSGhennadi Procopciuc 
16817c298ebcSGhennadi Procopciuc 	*rate = (pfreq * FP_PRECISION / fdiv->rate_div) / FP_PRECISION;
16827c298ebcSGhennadi Procopciuc 	return 0;
16837c298ebcSGhennadi Procopciuc }
16847c298ebcSGhennadi Procopciuc 
168535988a9dSGhennadi Procopciuc static inline struct s32cc_clk_obj *get_fixed_div_parent(const struct s32cc_clk_obj *module)
168635988a9dSGhennadi Procopciuc {
168735988a9dSGhennadi Procopciuc 	const struct s32cc_fixed_div *fdiv = s32cc_obj2fixeddiv(module);
168835988a9dSGhennadi Procopciuc 
168935988a9dSGhennadi Procopciuc 	return fdiv->parent;
169035988a9dSGhennadi Procopciuc }
169135988a9dSGhennadi Procopciuc 
169264e0c226SGhennadi Procopciuc static int set_mux_freq(const struct s32cc_clk_obj *module, unsigned long rate,
169364e0c226SGhennadi Procopciuc 			unsigned long *orate, unsigned int *depth)
169464e0c226SGhennadi Procopciuc {
169564e0c226SGhennadi Procopciuc 	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
169664e0c226SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id);
169764e0c226SGhennadi Procopciuc 	int ret;
169864e0c226SGhennadi Procopciuc 
169964e0c226SGhennadi Procopciuc 	ret = update_stack_depth(depth);
170064e0c226SGhennadi Procopciuc 	if (ret != 0) {
170164e0c226SGhennadi Procopciuc 		return ret;
170264e0c226SGhennadi Procopciuc 	}
170364e0c226SGhennadi Procopciuc 
170464e0c226SGhennadi Procopciuc 	if (clk == NULL) {
170564e0c226SGhennadi Procopciuc 		ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n",
170664e0c226SGhennadi Procopciuc 		      mux->index, mux->source_id);
170764e0c226SGhennadi Procopciuc 		return -EINVAL;
170864e0c226SGhennadi Procopciuc 	}
170964e0c226SGhennadi Procopciuc 
171064e0c226SGhennadi Procopciuc 	return set_module_rate(&clk->desc, rate, orate, depth);
171164e0c226SGhennadi Procopciuc }
171264e0c226SGhennadi Procopciuc 
1713d1567da6SGhennadi Procopciuc static int get_mux_freq(const struct s32cc_clk_obj *module,
1714d1567da6SGhennadi Procopciuc 			const struct s32cc_clk_drv *drv,
1715d1567da6SGhennadi Procopciuc 			unsigned long *rate, unsigned int depth)
1716d1567da6SGhennadi Procopciuc {
1717d1567da6SGhennadi Procopciuc 	const struct s32cc_clkmux *mux = s32cc_obj2clkmux(module);
1718d1567da6SGhennadi Procopciuc 	const struct s32cc_clk *clk = s32cc_get_arch_clk(mux->source_id);
1719d1567da6SGhennadi Procopciuc 	unsigned int ldepth = depth;
1720d1567da6SGhennadi Procopciuc 	int ret;
1721d1567da6SGhennadi Procopciuc 
1722d1567da6SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1723d1567da6SGhennadi Procopciuc 	if (ret != 0) {
1724d1567da6SGhennadi Procopciuc 		return ret;
1725d1567da6SGhennadi Procopciuc 	}
1726d1567da6SGhennadi Procopciuc 
1727d1567da6SGhennadi Procopciuc 	if (clk == NULL) {
1728d1567da6SGhennadi Procopciuc 		ERROR("Mux (id:%" PRIu8 ") without a valid source (%lu)\n",
1729d1567da6SGhennadi Procopciuc 		      mux->index, mux->source_id);
1730d1567da6SGhennadi Procopciuc 		return -EINVAL;
1731d1567da6SGhennadi Procopciuc 	}
1732d1567da6SGhennadi Procopciuc 
1733d1567da6SGhennadi Procopciuc 	return get_clk_freq(&clk->desc, drv, rate, ldepth);
1734d1567da6SGhennadi Procopciuc }
1735d1567da6SGhennadi Procopciuc 
17364cd04c50SGhennadi Procopciuc static int set_dfs_div_freq(const struct s32cc_clk_obj *module, unsigned long rate,
17374cd04c50SGhennadi Procopciuc 			    unsigned long *orate, unsigned int *depth)
17384cd04c50SGhennadi Procopciuc {
17394cd04c50SGhennadi Procopciuc 	struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
17404cd04c50SGhennadi Procopciuc 	const struct s32cc_dfs *dfs;
17414cd04c50SGhennadi Procopciuc 	int ret;
17424cd04c50SGhennadi Procopciuc 
17434cd04c50SGhennadi Procopciuc 	ret = update_stack_depth(depth);
17444cd04c50SGhennadi Procopciuc 	if (ret != 0) {
17454cd04c50SGhennadi Procopciuc 		return ret;
17464cd04c50SGhennadi Procopciuc 	}
17474cd04c50SGhennadi Procopciuc 
17484cd04c50SGhennadi Procopciuc 	if (dfs_div->parent == NULL) {
17494cd04c50SGhennadi Procopciuc 		ERROR("Failed to identify DFS divider's parent\n");
17504cd04c50SGhennadi Procopciuc 		return -EINVAL;
17514cd04c50SGhennadi Procopciuc 	}
17524cd04c50SGhennadi Procopciuc 
17534cd04c50SGhennadi Procopciuc 	/* Sanity check */
17544cd04c50SGhennadi Procopciuc 	dfs = s32cc_obj2dfs(dfs_div->parent);
17554cd04c50SGhennadi Procopciuc 	if (dfs->parent == NULL) {
17564cd04c50SGhennadi Procopciuc 		ERROR("Failed to identify DFS's parent\n");
17574cd04c50SGhennadi Procopciuc 		return -EINVAL;
17584cd04c50SGhennadi Procopciuc 	}
17594cd04c50SGhennadi Procopciuc 
17604cd04c50SGhennadi Procopciuc 	if ((dfs_div->freq != 0U) && (dfs_div->freq != rate)) {
17614cd04c50SGhennadi Procopciuc 		ERROR("DFS DIV frequency was already set to %lu\n",
17624cd04c50SGhennadi Procopciuc 		      dfs_div->freq);
17634cd04c50SGhennadi Procopciuc 		return -EINVAL;
17644cd04c50SGhennadi Procopciuc 	}
17654cd04c50SGhennadi Procopciuc 
17664cd04c50SGhennadi Procopciuc 	dfs_div->freq = rate;
17674cd04c50SGhennadi Procopciuc 	*orate = rate;
17684cd04c50SGhennadi Procopciuc 
17694cd04c50SGhennadi Procopciuc 	return ret;
17704cd04c50SGhennadi Procopciuc }
17714cd04c50SGhennadi Procopciuc 
17728f23e76fSGhennadi Procopciuc static unsigned long compute_dfs_div_freq(unsigned long pfreq, uint32_t mfi, uint32_t mfn)
17738f23e76fSGhennadi Procopciuc {
17748f23e76fSGhennadi Procopciuc 	unsigned long freq;
17758f23e76fSGhennadi Procopciuc 
17768f23e76fSGhennadi Procopciuc 	/**
17778f23e76fSGhennadi Procopciuc 	 * Formula for input and output clocks of each port divider.
17788f23e76fSGhennadi Procopciuc 	 * See 'Digital Frequency Synthesizer' chapter from Reference Manual.
17798f23e76fSGhennadi Procopciuc 	 *
17808f23e76fSGhennadi Procopciuc 	 * freq = pfreq / (2 * (mfi + mfn / 36.0));
17818f23e76fSGhennadi Procopciuc 	 */
17828f23e76fSGhennadi Procopciuc 	freq = (mfi * FP_PRECISION) + (mfn * FP_PRECISION / 36UL);
17838f23e76fSGhennadi Procopciuc 	freq *= 2UL;
17848f23e76fSGhennadi Procopciuc 	freq = pfreq * FP_PRECISION / freq;
17858f23e76fSGhennadi Procopciuc 
17868f23e76fSGhennadi Procopciuc 	return freq;
17878f23e76fSGhennadi Procopciuc }
17888f23e76fSGhennadi Procopciuc 
17898f23e76fSGhennadi Procopciuc static int get_dfs_div_freq(const struct s32cc_clk_obj *module,
17908f23e76fSGhennadi Procopciuc 			    const struct s32cc_clk_drv *drv,
17918f23e76fSGhennadi Procopciuc 			    unsigned long *rate, unsigned int depth)
17928f23e76fSGhennadi Procopciuc {
17938f23e76fSGhennadi Procopciuc 	const struct s32cc_dfs_div *dfs_div = s32cc_obj2dfsdiv(module);
17948f23e76fSGhennadi Procopciuc 	unsigned int ldepth = depth;
17958f23e76fSGhennadi Procopciuc 	const struct s32cc_dfs *dfs;
17968f23e76fSGhennadi Procopciuc 	uint32_t dvport, mfi, mfn;
17978f23e76fSGhennadi Procopciuc 	uintptr_t dfs_addr = 0UL;
17988f23e76fSGhennadi Procopciuc 	unsigned long pfreq;
17998f23e76fSGhennadi Procopciuc 	int ret;
18008f23e76fSGhennadi Procopciuc 
18018f23e76fSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
18028f23e76fSGhennadi Procopciuc 	if (ret != 0) {
18038f23e76fSGhennadi Procopciuc 		return ret;
18048f23e76fSGhennadi Procopciuc 	}
18058f23e76fSGhennadi Procopciuc 
18068f23e76fSGhennadi Procopciuc 	dfs = get_div_dfs(dfs_div);
18078f23e76fSGhennadi Procopciuc 	if (dfs == NULL) {
18088f23e76fSGhennadi Procopciuc 		return -EINVAL;
18098f23e76fSGhennadi Procopciuc 	}
18108f23e76fSGhennadi Procopciuc 
18118f23e76fSGhennadi Procopciuc 	ret = get_module_rate(dfs_div->parent, drv, &pfreq, ldepth);
18128f23e76fSGhennadi Procopciuc 	if (ret != 0) {
18138f23e76fSGhennadi Procopciuc 		return ret;
18148f23e76fSGhennadi Procopciuc 	}
18158f23e76fSGhennadi Procopciuc 
18168f23e76fSGhennadi Procopciuc 	ret = get_base_addr(dfs->instance, drv, &dfs_addr);
18178f23e76fSGhennadi Procopciuc 	if (ret != 0) {
18188f23e76fSGhennadi Procopciuc 		ERROR("Failed to detect the DFS instance\n");
18198f23e76fSGhennadi Procopciuc 		return ret;
18208f23e76fSGhennadi Procopciuc 	}
18218f23e76fSGhennadi Procopciuc 
18228f23e76fSGhennadi Procopciuc 	dvport = mmio_read_32(DFS_DVPORTn(dfs_addr, dfs_div->index));
18238f23e76fSGhennadi Procopciuc 
18248f23e76fSGhennadi Procopciuc 	mfi = DFS_DVPORTn_MFI(dvport);
18258f23e76fSGhennadi Procopciuc 	mfn = DFS_DVPORTn_MFN(dvport);
18268f23e76fSGhennadi Procopciuc 
18278f23e76fSGhennadi Procopciuc 	/* Disabled port */
18288f23e76fSGhennadi Procopciuc 	if ((mfi == 0U) && (mfn == 0U)) {
18298f23e76fSGhennadi Procopciuc 		*rate = dfs_div->freq;
18308f23e76fSGhennadi Procopciuc 		return 0;
18318f23e76fSGhennadi Procopciuc 	}
18328f23e76fSGhennadi Procopciuc 
18338f23e76fSGhennadi Procopciuc 	*rate = compute_dfs_div_freq(pfreq, mfi, mfn);
18348f23e76fSGhennadi Procopciuc 	return 0;
18358f23e76fSGhennadi Procopciuc }
18368f23e76fSGhennadi Procopciuc 
18378501b1fcSGhennadi Procopciuc static int set_part_block_link_freq(const struct s32cc_clk_obj *module,
18388501b1fcSGhennadi Procopciuc 				    unsigned long rate, unsigned long *orate,
18398501b1fcSGhennadi Procopciuc 				    const unsigned int *depth)
18408501b1fcSGhennadi Procopciuc {
18418501b1fcSGhennadi Procopciuc 	const struct s32cc_part_block_link *link = s32cc_obj2partblocklink(module);
18428501b1fcSGhennadi Procopciuc 	const struct s32cc_clk_obj *parent = link->parent;
18438501b1fcSGhennadi Procopciuc 	unsigned int ldepth = *depth;
18448501b1fcSGhennadi Procopciuc 	int ret;
18458501b1fcSGhennadi Procopciuc 
18468501b1fcSGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
18478501b1fcSGhennadi Procopciuc 	if (ret != 0) {
18488501b1fcSGhennadi Procopciuc 		return ret;
18498501b1fcSGhennadi Procopciuc 	}
18508501b1fcSGhennadi Procopciuc 
18518501b1fcSGhennadi Procopciuc 	if (parent == NULL) {
18528501b1fcSGhennadi Procopciuc 		ERROR("Partition block link with no parent\n");
18538501b1fcSGhennadi Procopciuc 		return -EINVAL;
18548501b1fcSGhennadi Procopciuc 	}
18558501b1fcSGhennadi Procopciuc 
18568501b1fcSGhennadi Procopciuc 	return set_module_rate(parent, rate, orate, &ldepth);
18578501b1fcSGhennadi Procopciuc }
18588501b1fcSGhennadi Procopciuc 
1859d9373519SGhennadi Procopciuc static int set_module_rate(const struct s32cc_clk_obj *module,
1860d9373519SGhennadi Procopciuc 			   unsigned long rate, unsigned long *orate,
1861d9373519SGhennadi Procopciuc 			   unsigned int *depth)
1862d9373519SGhennadi Procopciuc {
1863d9373519SGhennadi Procopciuc 	int ret = 0;
1864d9373519SGhennadi Procopciuc 
1865d9373519SGhennadi Procopciuc 	ret = update_stack_depth(depth);
1866d9373519SGhennadi Procopciuc 	if (ret != 0) {
1867d9373519SGhennadi Procopciuc 		return ret;
1868d9373519SGhennadi Procopciuc 	}
1869d9373519SGhennadi Procopciuc 
18704cd04c50SGhennadi Procopciuc 	ret = -EINVAL;
18714cd04c50SGhennadi Procopciuc 
1872d9373519SGhennadi Procopciuc 	switch (module->type) {
1873d9373519SGhennadi Procopciuc 	case s32cc_clk_t:
1874d9373519SGhennadi Procopciuc 		ret = set_clk_freq(module, rate, orate, depth);
1875d9373519SGhennadi Procopciuc 		break;
1876d9373519SGhennadi Procopciuc 	case s32cc_osc_t:
1877d9373519SGhennadi Procopciuc 		ret = set_osc_freq(module, rate, orate, depth);
1878d9373519SGhennadi Procopciuc 		break;
18797ad4e231SGhennadi Procopciuc 	case s32cc_pll_t:
18807ad4e231SGhennadi Procopciuc 		ret = set_pll_freq(module, rate, orate, depth);
18817ad4e231SGhennadi Procopciuc 		break;
1882de950ef0SGhennadi Procopciuc 	case s32cc_pll_out_div_t:
1883de950ef0SGhennadi Procopciuc 		ret = set_pll_div_freq(module, rate, orate, depth);
1884de950ef0SGhennadi Procopciuc 		break;
188565739db2SGhennadi Procopciuc 	case s32cc_fixed_div_t:
188665739db2SGhennadi Procopciuc 		ret = set_fixed_div_freq(module, rate, orate, depth);
188765739db2SGhennadi Procopciuc 		break;
1888a8be748aSGhennadi Procopciuc 	case s32cc_clkmux_t:
188964e0c226SGhennadi Procopciuc 		ret = set_mux_freq(module, rate, orate, depth);
189064e0c226SGhennadi Procopciuc 		break;
18913fa91a94SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
189264e0c226SGhennadi Procopciuc 		ret = set_mux_freq(module, rate, orate, depth);
1893a8be748aSGhennadi Procopciuc 		break;
18944cd04c50SGhennadi Procopciuc 	case s32cc_dfs_t:
18954cd04c50SGhennadi Procopciuc 		ERROR("Setting the frequency of a DFS is not allowed!");
18964cd04c50SGhennadi Procopciuc 		break;
18974cd04c50SGhennadi Procopciuc 	case s32cc_dfs_div_t:
18984cd04c50SGhennadi Procopciuc 		ret = set_dfs_div_freq(module, rate, orate, depth);
18994cd04c50SGhennadi Procopciuc 		break;
19008501b1fcSGhennadi Procopciuc 	case s32cc_part_block_link_t:
19018501b1fcSGhennadi Procopciuc 		ret = set_part_block_link_freq(module, rate, orate, depth);
19028501b1fcSGhennadi Procopciuc 		break;
19038501b1fcSGhennadi Procopciuc 	case s32cc_part_t:
19048501b1fcSGhennadi Procopciuc 		ERROR("It's not allowed to set the frequency of a partition !");
19058501b1fcSGhennadi Procopciuc 		break;
19068501b1fcSGhennadi Procopciuc 	case s32cc_part_block_t:
19078501b1fcSGhennadi Procopciuc 		ERROR("It's not allowed to set the frequency of a partition block !");
19088501b1fcSGhennadi Procopciuc 		break;
1909d9373519SGhennadi Procopciuc 	default:
1910d9373519SGhennadi Procopciuc 		break;
1911d9373519SGhennadi Procopciuc 	}
1912d9373519SGhennadi Procopciuc 
1913d9373519SGhennadi Procopciuc 	return ret;
1914d9373519SGhennadi Procopciuc }
1915d9373519SGhennadi Procopciuc 
1916bd691136SGhennadi Procopciuc static int get_module_rate(const struct s32cc_clk_obj *module,
1917bd691136SGhennadi Procopciuc 			   const struct s32cc_clk_drv *drv,
1918bd691136SGhennadi Procopciuc 			   unsigned long *rate,
1919bd691136SGhennadi Procopciuc 			   unsigned int depth)
1920bd691136SGhennadi Procopciuc {
1921bd691136SGhennadi Procopciuc 	unsigned int ldepth = depth;
1922bd691136SGhennadi Procopciuc 	int ret = 0;
1923bd691136SGhennadi Procopciuc 
1924bd691136SGhennadi Procopciuc 	ret = update_stack_depth(&ldepth);
1925bd691136SGhennadi Procopciuc 	if (ret != 0) {
1926bd691136SGhennadi Procopciuc 		return ret;
1927bd691136SGhennadi Procopciuc 	}
1928bd691136SGhennadi Procopciuc 
1929bd691136SGhennadi Procopciuc 	switch (module->type) {
1930bd691136SGhennadi Procopciuc 	case s32cc_osc_t:
1931bd691136SGhennadi Procopciuc 		ret = get_osc_freq(module, drv, rate, ldepth);
1932bd691136SGhennadi Procopciuc 		break;
193346de0b9cSGhennadi Procopciuc 	case s32cc_clk_t:
193446de0b9cSGhennadi Procopciuc 		ret = get_clk_freq(module, drv, rate, ldepth);
193546de0b9cSGhennadi Procopciuc 		break;
1936fbebafa5SGhennadi Procopciuc 	case s32cc_pll_t:
1937fbebafa5SGhennadi Procopciuc 		ret = get_pll_freq(module, drv, rate, ldepth);
1938fbebafa5SGhennadi Procopciuc 		break;
19392fb25509SGhennadi Procopciuc 	case s32cc_dfs_t:
19402fb25509SGhennadi Procopciuc 		ret = get_dfs_freq(module, drv, rate, ldepth);
19412fb25509SGhennadi Procopciuc 		break;
19428f23e76fSGhennadi Procopciuc 	case s32cc_dfs_div_t:
19438f23e76fSGhennadi Procopciuc 		ret = get_dfs_div_freq(module, drv, rate, ldepth);
19448f23e76fSGhennadi Procopciuc 		break;
19457c298ebcSGhennadi Procopciuc 	case s32cc_fixed_div_t:
19467c298ebcSGhennadi Procopciuc 		ret = get_fixed_div_freq(module, drv, rate, ldepth);
19477c298ebcSGhennadi Procopciuc 		break;
1948a762c505SGhennadi Procopciuc 	case s32cc_pll_out_div_t:
1949a762c505SGhennadi Procopciuc 		ret = get_pll_div_freq(module, drv, rate, ldepth);
1950a762c505SGhennadi Procopciuc 		break;
1951d1567da6SGhennadi Procopciuc 	case s32cc_clkmux_t:
1952d1567da6SGhennadi Procopciuc 		ret = get_mux_freq(module, drv, rate, ldepth);
1953d1567da6SGhennadi Procopciuc 		break;
1954d1567da6SGhennadi Procopciuc 	case s32cc_shared_clkmux_t:
1955d1567da6SGhennadi Procopciuc 		ret = get_mux_freq(module, drv, rate, ldepth);
1956d1567da6SGhennadi Procopciuc 		break;
1957a74cf75fSGhennadi Procopciuc 	case s32cc_part_t:
1958a74cf75fSGhennadi Procopciuc 		ERROR("s32cc_part_t cannot be used to get rate\n");
1959a74cf75fSGhennadi Procopciuc 		break;
1960a74cf75fSGhennadi Procopciuc 	case s32cc_part_block_t:
1961a74cf75fSGhennadi Procopciuc 		ERROR("s32cc_part_block_t cannot be used to get rate\n");
1962a74cf75fSGhennadi Procopciuc 		break;
1963a74cf75fSGhennadi Procopciuc 	case s32cc_part_block_link_t:
1964a74cf75fSGhennadi Procopciuc 		ret = get_part_block_link_freq(module, drv, rate, ldepth);
1965a74cf75fSGhennadi Procopciuc 		break;
1966bd691136SGhennadi Procopciuc 	default:
1967bd691136SGhennadi Procopciuc 		ret = -EINVAL;
1968bd691136SGhennadi Procopciuc 		break;
1969bd691136SGhennadi Procopciuc 	}
1970bd691136SGhennadi Procopciuc 
1971bd691136SGhennadi Procopciuc 	return ret;
1972bd691136SGhennadi Procopciuc }
1973bd691136SGhennadi Procopciuc 
19743a580e9eSGhennadi Procopciuc static int s32cc_clk_set_rate(unsigned long id, unsigned long rate,
19753a580e9eSGhennadi Procopciuc 			      unsigned long *orate)
19763a580e9eSGhennadi Procopciuc {
1977d9373519SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
1978d9373519SGhennadi Procopciuc 	const struct s32cc_clk *clk;
1979d9373519SGhennadi Procopciuc 	int ret;
1980d9373519SGhennadi Procopciuc 
1981d9373519SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
1982d9373519SGhennadi Procopciuc 	if (clk == NULL) {
1983d9373519SGhennadi Procopciuc 		return -EINVAL;
1984d9373519SGhennadi Procopciuc 	}
1985d9373519SGhennadi Procopciuc 
1986d9373519SGhennadi Procopciuc 	ret = set_module_rate(&clk->desc, rate, orate, &depth);
1987d9373519SGhennadi Procopciuc 	if (ret != 0) {
1988d9373519SGhennadi Procopciuc 		ERROR("Failed to set frequency (%lu MHz) for clock %lu\n",
1989d9373519SGhennadi Procopciuc 		      rate, id);
1990d9373519SGhennadi Procopciuc 	}
1991d9373519SGhennadi Procopciuc 
1992d9373519SGhennadi Procopciuc 	return ret;
19933a580e9eSGhennadi Procopciuc }
19943a580e9eSGhennadi Procopciuc 
1995bd691136SGhennadi Procopciuc static unsigned long s32cc_clk_get_rate(unsigned long id)
1996bd691136SGhennadi Procopciuc {
1997bd691136SGhennadi Procopciuc 	const struct s32cc_clk_drv *drv = get_drv();
1998bd691136SGhennadi Procopciuc 	unsigned int depth = MAX_STACK_DEPTH;
1999bd691136SGhennadi Procopciuc 	const struct s32cc_clk *clk;
2000bd691136SGhennadi Procopciuc 	unsigned long rate = 0UL;
2001bd691136SGhennadi Procopciuc 	int ret;
2002bd691136SGhennadi Procopciuc 
2003bd691136SGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
2004bd691136SGhennadi Procopciuc 	if (clk == NULL) {
2005bd691136SGhennadi Procopciuc 		return 0;
2006bd691136SGhennadi Procopciuc 	}
2007bd691136SGhennadi Procopciuc 
2008bd691136SGhennadi Procopciuc 	ret = get_module_rate(&clk->desc, drv, &rate, depth);
2009bd691136SGhennadi Procopciuc 	if (ret != 0) {
2010bd691136SGhennadi Procopciuc 		ERROR("Failed to get frequency (%lu MHz) for clock %lu\n",
2011bd691136SGhennadi Procopciuc 		      rate, id);
2012bd691136SGhennadi Procopciuc 		return 0;
2013bd691136SGhennadi Procopciuc 	}
2014bd691136SGhennadi Procopciuc 
2015bd691136SGhennadi Procopciuc 	return rate;
2016bd691136SGhennadi Procopciuc }
2017bd691136SGhennadi Procopciuc 
201896e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_no_parent(const struct s32cc_clk_obj *module)
201996e069cbSGhennadi Procopciuc {
202096e069cbSGhennadi Procopciuc 	return NULL;
202196e069cbSGhennadi Procopciuc }
202296e069cbSGhennadi Procopciuc 
202396e069cbSGhennadi Procopciuc typedef struct s32cc_clk_obj *(*get_parent_clb_t)(const struct s32cc_clk_obj *clk_obj);
202496e069cbSGhennadi Procopciuc 
202596e069cbSGhennadi Procopciuc static struct s32cc_clk_obj *get_module_parent(const struct s32cc_clk_obj *module)
202696e069cbSGhennadi Procopciuc {
202763d536feSGhennadi Procopciuc 	static const get_parent_clb_t parents_clbs[13] = {
202896e069cbSGhennadi Procopciuc 		[s32cc_clk_t] = get_clk_parent,
202996e069cbSGhennadi Procopciuc 		[s32cc_osc_t] = get_no_parent,
203096e069cbSGhennadi Procopciuc 		[s32cc_pll_t] = get_pll_parent,
203196e069cbSGhennadi Procopciuc 		[s32cc_pll_out_div_t] = get_pll_div_parent,
203296e069cbSGhennadi Procopciuc 		[s32cc_clkmux_t] = get_mux_parent,
203396e069cbSGhennadi Procopciuc 		[s32cc_shared_clkmux_t] = get_mux_parent,
203496e069cbSGhennadi Procopciuc 		[s32cc_dfs_t] = get_dfs_parent,
203596e069cbSGhennadi Procopciuc 		[s32cc_dfs_div_t] = get_dfs_div_parent,
20368a4f840bSGhennadi Procopciuc 		[s32cc_part_t] = get_no_parent,
203735988a9dSGhennadi Procopciuc 		[s32cc_fixed_div_t] = get_fixed_div_parent,
20388a4f840bSGhennadi Procopciuc 		[s32cc_part_block_t] = get_part_block_parent,
20398a4f840bSGhennadi Procopciuc 		[s32cc_part_block_link_t] = get_part_block_link_parent,
204096e069cbSGhennadi Procopciuc 	};
204196e069cbSGhennadi Procopciuc 	uint32_t index;
204296e069cbSGhennadi Procopciuc 
204396e069cbSGhennadi Procopciuc 	if (module == NULL) {
204496e069cbSGhennadi Procopciuc 		return NULL;
204596e069cbSGhennadi Procopciuc 	}
204696e069cbSGhennadi Procopciuc 
204796e069cbSGhennadi Procopciuc 	index = (uint32_t)module->type;
204896e069cbSGhennadi Procopciuc 
204996e069cbSGhennadi Procopciuc 	if (index >= ARRAY_SIZE(parents_clbs)) {
205096e069cbSGhennadi Procopciuc 		ERROR("Undefined module type: %d\n", module->type);
205196e069cbSGhennadi Procopciuc 		return NULL;
205296e069cbSGhennadi Procopciuc 	}
205396e069cbSGhennadi Procopciuc 
205496e069cbSGhennadi Procopciuc 	if (parents_clbs[index] == NULL) {
205596e069cbSGhennadi Procopciuc 		ERROR("Undefined parent getter for type: %d\n", module->type);
205696e069cbSGhennadi Procopciuc 		return NULL;
205796e069cbSGhennadi Procopciuc 	}
205896e069cbSGhennadi Procopciuc 
205996e069cbSGhennadi Procopciuc 	return parents_clbs[index](module);
206096e069cbSGhennadi Procopciuc }
206196e069cbSGhennadi Procopciuc 
20623a580e9eSGhennadi Procopciuc static int s32cc_clk_get_parent(unsigned long id)
20633a580e9eSGhennadi Procopciuc {
206496e069cbSGhennadi Procopciuc 	struct s32cc_clk *parent_clk;
206596e069cbSGhennadi Procopciuc 	const struct s32cc_clk_obj *parent;
206696e069cbSGhennadi Procopciuc 	const struct s32cc_clk *clk;
206796e069cbSGhennadi Procopciuc 	unsigned long parent_id;
206896e069cbSGhennadi Procopciuc 	int ret;
206996e069cbSGhennadi Procopciuc 
207096e069cbSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
207196e069cbSGhennadi Procopciuc 	if (clk == NULL) {
207296e069cbSGhennadi Procopciuc 		return -EINVAL;
207396e069cbSGhennadi Procopciuc 	}
207496e069cbSGhennadi Procopciuc 
207596e069cbSGhennadi Procopciuc 	parent = get_module_parent(clk->module);
207696e069cbSGhennadi Procopciuc 	if (parent == NULL) {
207796e069cbSGhennadi Procopciuc 		return -EINVAL;
207896e069cbSGhennadi Procopciuc 	}
207996e069cbSGhennadi Procopciuc 
208096e069cbSGhennadi Procopciuc 	parent_clk = s32cc_obj2clk(parent);
208196e069cbSGhennadi Procopciuc 	if (parent_clk == NULL) {
208296e069cbSGhennadi Procopciuc 		return -EINVAL;
208396e069cbSGhennadi Procopciuc 	}
208496e069cbSGhennadi Procopciuc 
208596e069cbSGhennadi Procopciuc 	ret = s32cc_get_clk_id(parent_clk, &parent_id);
208696e069cbSGhennadi Procopciuc 	if (ret != 0) {
208796e069cbSGhennadi Procopciuc 		return ret;
208896e069cbSGhennadi Procopciuc 	}
208996e069cbSGhennadi Procopciuc 
209096e069cbSGhennadi Procopciuc 	if (parent_id > (unsigned long)INT_MAX) {
209196e069cbSGhennadi Procopciuc 		return -E2BIG;
209296e069cbSGhennadi Procopciuc 	}
209396e069cbSGhennadi Procopciuc 
209496e069cbSGhennadi Procopciuc 	return (int)parent_id;
20953a580e9eSGhennadi Procopciuc }
20963a580e9eSGhennadi Procopciuc 
20973a580e9eSGhennadi Procopciuc static int s32cc_clk_set_parent(unsigned long id, unsigned long parent_id)
20983a580e9eSGhennadi Procopciuc {
209912e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *parent;
210012e7a2cdSGhennadi Procopciuc 	const struct s32cc_clk *clk;
210112e7a2cdSGhennadi Procopciuc 	bool valid_source = false;
210212e7a2cdSGhennadi Procopciuc 	struct s32cc_clkmux *mux;
210312e7a2cdSGhennadi Procopciuc 	uint8_t i;
210412e7a2cdSGhennadi Procopciuc 
210512e7a2cdSGhennadi Procopciuc 	clk = s32cc_get_arch_clk(id);
210612e7a2cdSGhennadi Procopciuc 	if (clk == NULL) {
210712e7a2cdSGhennadi Procopciuc 		return -EINVAL;
210812e7a2cdSGhennadi Procopciuc 	}
210912e7a2cdSGhennadi Procopciuc 
211012e7a2cdSGhennadi Procopciuc 	parent = s32cc_get_arch_clk(parent_id);
211112e7a2cdSGhennadi Procopciuc 	if (parent == NULL) {
211212e7a2cdSGhennadi Procopciuc 		return -EINVAL;
211312e7a2cdSGhennadi Procopciuc 	}
211412e7a2cdSGhennadi Procopciuc 
211512e7a2cdSGhennadi Procopciuc 	if (!is_s32cc_clk_mux(clk)) {
211612e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a mux\n", id);
211712e7a2cdSGhennadi Procopciuc 		return -EINVAL;
211812e7a2cdSGhennadi Procopciuc 	}
211912e7a2cdSGhennadi Procopciuc 
212012e7a2cdSGhennadi Procopciuc 	mux = s32cc_clk2mux(clk);
212112e7a2cdSGhennadi Procopciuc 	if (mux == NULL) {
212212e7a2cdSGhennadi Procopciuc 		ERROR("Failed to cast clock %lu to clock mux\n", id);
212312e7a2cdSGhennadi Procopciuc 		return -EINVAL;
212412e7a2cdSGhennadi Procopciuc 	}
212512e7a2cdSGhennadi Procopciuc 
212612e7a2cdSGhennadi Procopciuc 	for (i = 0; i < mux->nclks; i++) {
212712e7a2cdSGhennadi Procopciuc 		if (mux->clkids[i] == parent_id) {
212812e7a2cdSGhennadi Procopciuc 			valid_source = true;
212912e7a2cdSGhennadi Procopciuc 			break;
213012e7a2cdSGhennadi Procopciuc 		}
213112e7a2cdSGhennadi Procopciuc 	}
213212e7a2cdSGhennadi Procopciuc 
213312e7a2cdSGhennadi Procopciuc 	if (!valid_source) {
213412e7a2cdSGhennadi Procopciuc 		ERROR("Clock %lu is not a valid clock for mux %lu\n",
213512e7a2cdSGhennadi Procopciuc 		      parent_id, id);
213612e7a2cdSGhennadi Procopciuc 		return -EINVAL;
213712e7a2cdSGhennadi Procopciuc 	}
213812e7a2cdSGhennadi Procopciuc 
213912e7a2cdSGhennadi Procopciuc 	mux->source_id = parent_id;
214012e7a2cdSGhennadi Procopciuc 
214112e7a2cdSGhennadi Procopciuc 	return 0;
21423a580e9eSGhennadi Procopciuc }
21433a580e9eSGhennadi Procopciuc 
2144514c7380SGhennadi Procopciuc static int s32cc_clk_mmap_regs(const struct s32cc_clk_drv *drv)
2145514c7380SGhennadi Procopciuc {
214629f8a952SGhennadi Procopciuc 	const uintptr_t base_addrs[12] = {
2147514c7380SGhennadi Procopciuc 		drv->fxosc_base,
2148514c7380SGhennadi Procopciuc 		drv->armpll_base,
2149514c7380SGhennadi Procopciuc 		drv->periphpll_base,
2150514c7380SGhennadi Procopciuc 		drv->armdfs_base,
215129f8a952SGhennadi Procopciuc 		drv->periphdfs_base,
2152514c7380SGhennadi Procopciuc 		drv->cgm0_base,
2153514c7380SGhennadi Procopciuc 		drv->cgm1_base,
2154514c7380SGhennadi Procopciuc 		drv->cgm5_base,
2155514c7380SGhennadi Procopciuc 		drv->ddrpll_base,
2156514c7380SGhennadi Procopciuc 		drv->mc_me,
2157514c7380SGhennadi Procopciuc 		drv->mc_rgm,
2158514c7380SGhennadi Procopciuc 		drv->rdc,
2159514c7380SGhennadi Procopciuc 	};
2160514c7380SGhennadi Procopciuc 	size_t i;
2161514c7380SGhennadi Procopciuc 	int ret;
2162514c7380SGhennadi Procopciuc 
2163514c7380SGhennadi Procopciuc 	for (i = 0U; i < ARRAY_SIZE(base_addrs); i++) {
2164514c7380SGhennadi Procopciuc 		ret = mmap_add_dynamic_region(base_addrs[i], base_addrs[i],
2165514c7380SGhennadi Procopciuc 					      PAGE_SIZE,
2166514c7380SGhennadi Procopciuc 					      MT_DEVICE | MT_RW | MT_SECURE);
2167514c7380SGhennadi Procopciuc 		if (ret != 0) {
2168514c7380SGhennadi Procopciuc 			ERROR("Failed to map clock module 0x%" PRIuPTR "\n",
2169514c7380SGhennadi Procopciuc 			      base_addrs[i]);
2170514c7380SGhennadi Procopciuc 			return ret;
2171514c7380SGhennadi Procopciuc 		}
2172514c7380SGhennadi Procopciuc 	}
2173514c7380SGhennadi Procopciuc 
2174514c7380SGhennadi Procopciuc 	return 0;
2175514c7380SGhennadi Procopciuc }
2176514c7380SGhennadi Procopciuc 
217761b5ef21SGhennadi Procopciuc int s32cc_clk_register_drv(bool mmap_regs)
21783a580e9eSGhennadi Procopciuc {
21793a580e9eSGhennadi Procopciuc 	static const struct clk_ops s32cc_clk_ops = {
21803a580e9eSGhennadi Procopciuc 		.enable		= s32cc_clk_enable,
21813a580e9eSGhennadi Procopciuc 		.disable	= s32cc_clk_disable,
21823a580e9eSGhennadi Procopciuc 		.is_enabled	= s32cc_clk_is_enabled,
21833a580e9eSGhennadi Procopciuc 		.get_rate	= s32cc_clk_get_rate,
21843a580e9eSGhennadi Procopciuc 		.set_rate	= s32cc_clk_set_rate,
21853a580e9eSGhennadi Procopciuc 		.get_parent	= s32cc_clk_get_parent,
21863a580e9eSGhennadi Procopciuc 		.set_parent	= s32cc_clk_set_parent,
21873a580e9eSGhennadi Procopciuc 	};
2188514c7380SGhennadi Procopciuc 	const struct s32cc_clk_drv *drv;
21893a580e9eSGhennadi Procopciuc 
21903a580e9eSGhennadi Procopciuc 	clk_register(&s32cc_clk_ops);
2191514c7380SGhennadi Procopciuc 
2192514c7380SGhennadi Procopciuc 	drv = get_drv();
2193514c7380SGhennadi Procopciuc 	if (drv == NULL) {
2194514c7380SGhennadi Procopciuc 		return -EINVAL;
2195514c7380SGhennadi Procopciuc 	}
2196514c7380SGhennadi Procopciuc 
219761b5ef21SGhennadi Procopciuc 	if (mmap_regs) {
2198514c7380SGhennadi Procopciuc 		return s32cc_clk_mmap_regs(drv);
21993a580e9eSGhennadi Procopciuc 	}
22003a580e9eSGhennadi Procopciuc 
220161b5ef21SGhennadi Procopciuc 	return 0;
220261b5ef21SGhennadi Procopciuc }
220361b5ef21SGhennadi Procopciuc 
2204