xref: /optee_os/core/drivers/clk/sam/clk-sam9x60-pll.c (revision b20bd0e0d0bb88b66a85e8fd75e52acca58a3eb8)
14318c69fSTony Han // SPDX-License-Identifier: BSD-2-Clause
24318c69fSTony Han /*
34318c69fSTony Han  *  Copyright (C) 2019 Microchip Technology Inc.
44318c69fSTony Han  */
54318c69fSTony Han 
64318c69fSTony Han #include <io.h>
74318c69fSTony Han #include <kernel/misc.h>
84318c69fSTony Han #include <mm/core_memprot.h>
94318c69fSTony Han #include <types_ext.h>
104318c69fSTony Han #include <util.h>
114318c69fSTony Han #include "at91_clk.h"
124318c69fSTony Han 
134318c69fSTony Han #define PMC_PLL_CTRL0_DIV_MASK 0xf
144318c69fSTony Han #define PMC_PLL_CTRL0_DIV_POS 0
154318c69fSTony Han #define PMC_PLL_CTRL1_MUL_MASK 0xff
164318c69fSTony Han #define PMC_PLL_CTRL1_MUL_POS 24
174318c69fSTony Han #define PMC_PLL_CTRL1_FRACR_MASK 0x3fffff
184318c69fSTony Han #define PMC_PLL_CTRL1_FRACR_POS 0
194318c69fSTony Han 
204318c69fSTony Han #define PLL_STATUS_MASK(id)	BIT(1 + (id))
214318c69fSTony Han #define PLL_REG(id)		(AT91_CKGR_PLLAR + ((id) * 4))
224318c69fSTony Han #define PLL_DIV_MASK		0xff
234318c69fSTony Han #define PLL_DIV_MAX		PLL_DIV_MASK
244318c69fSTony Han #define PLL_DIV(reg)		((reg) & PLL_DIV_MASK)
254318c69fSTony Han #define PLL_MUL(reg, layout) \
264318c69fSTony Han 	({ \
274318c69fSTony Han 		typeof(layout) __layout = layout; \
284318c69fSTony Han 		\
294318c69fSTony Han 		(((reg) >> (__layout)->mul_shift) & (__layout)->mul_mask); \
304318c69fSTony Han 	})
314318c69fSTony Han #define PLL_MUL_MIN		2
324318c69fSTony Han #define PLL_MUL_MASK(layout)	((layout)->mul_mask)
334318c69fSTony Han #define PLL_MUL_MAX(layout)	(PLL_MUL_MASK(layout) + 1)
344318c69fSTony Han #define PLL_ICPR_SHIFT(id)	((id) * 16)
354318c69fSTony Han #define PLL_ICPR_MASK(id)	SHIFT_U64(0xffff, PLL_ICPR_SHIFT(id))
364318c69fSTony Han #define PLL_MAX_COUNT		0x3f
374318c69fSTony Han #define PLL_COUNT_SHIFT		8
384318c69fSTony Han #define PLL_OUT_SHIFT		14
394318c69fSTony Han 
404318c69fSTony Han struct sam9x60_pll_core {
414318c69fSTony Han 	vaddr_t base;
424318c69fSTony Han 	const struct clk_pll_charac *charac;
434318c69fSTony Han 	const struct clk_pll_layout *layout;
444318c69fSTony Han 	struct clk *hw;
454318c69fSTony Han 	uint8_t id;
464318c69fSTony Han };
474318c69fSTony Han 
484318c69fSTony Han struct sam9x60_frac {
494318c69fSTony Han 	struct sam9x60_pll_core core;
504318c69fSTony Han 	uint32_t frac;
514318c69fSTony Han 	uint16_t mul;
524318c69fSTony Han };
534318c69fSTony Han 
544318c69fSTony Han struct sam9x60_div {
554318c69fSTony Han 	struct sam9x60_pll_core core;
564318c69fSTony Han 	uint8_t div;
574318c69fSTony Han 	uint8_t safe_div;
584318c69fSTony Han };
594318c69fSTony Han 
604318c69fSTony Han #define WAIT_PLL_READY_TIMEOUT(_base, _id) \
614318c69fSTony Han 	({ \
624318c69fSTony Han 		uint32_t __timeout = 0; \
634318c69fSTony Han 		uint32_t _c = 0; \
644318c69fSTony Han 		\
65a53e4bdaSTony Han 		while (__timeout++ < 1000) { \
664318c69fSTony Han 			_c = io_read32((_base) + AT91_PMC_PLL_ISR0) & \
674318c69fSTony Han 				BIT(_id); \
684318c69fSTony Han 			if (_c) \
694318c69fSTony Han 				break; \
704318c69fSTony Han 			wait_cycles(100); \
714318c69fSTony Han 		} \
724318c69fSTony Han 		!(_c); \
734318c69fSTony Han 	})
744318c69fSTony Han 
sam9x60_pll_ready(vaddr_t base,int id)754318c69fSTony Han static bool sam9x60_pll_ready(vaddr_t base, int id)
764318c69fSTony Han {
774318c69fSTony Han 	return io_read32(base + AT91_PMC_PLL_ISR0) & BIT(id);
784318c69fSTony Han }
794318c69fSTony Han 
sam9x60_frac_pll_ready(vaddr_t regmap,uint8_t id)804318c69fSTony Han static bool sam9x60_frac_pll_ready(vaddr_t regmap, uint8_t id)
814318c69fSTony Han {
824318c69fSTony Han 	return sam9x60_pll_ready(regmap, id);
834318c69fSTony Han }
844318c69fSTony Han 
sam9x60_frac_pll_recalc_rate(struct clk * hw,unsigned long parent_rate)854318c69fSTony Han static unsigned long sam9x60_frac_pll_recalc_rate(struct clk *hw,
864318c69fSTony Han 						  unsigned long parent_rate)
874318c69fSTony Han {
884318c69fSTony Han 	struct sam9x60_frac *frac = hw->priv;
894318c69fSTony Han 
904318c69fSTony Han 	return parent_rate * (frac->mul + 1) +
914318c69fSTony Han 		UDIV_ROUND_NEAREST((unsigned long long)parent_rate * frac->frac,
924318c69fSTony Han 				   1 << 22);
934318c69fSTony Han }
944318c69fSTony Han 
sam9x60_frac_pll_set(struct sam9x60_frac * frac)954318c69fSTony Han static TEE_Result sam9x60_frac_pll_set(struct sam9x60_frac *frac)
964318c69fSTony Han {
974318c69fSTony Han 	struct sam9x60_pll_core *core = &frac->core;
984318c69fSTony Han 	vaddr_t regmap = frac->core.base;
994318c69fSTony Han 	unsigned int val = 0;
1004318c69fSTony Han 	unsigned int cfrac = 0;
1014318c69fSTony Han 	unsigned int cmul = 0;
1024318c69fSTony Han 
1034318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
1044318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK, core->id);
1054318c69fSTony Han 	val = io_read32(regmap + AT91_PMC_PLL_CTRL1);
1064318c69fSTony Han 	cmul = (val & core->layout->mul_mask) >> core->layout->mul_shift;
1074318c69fSTony Han 	cfrac = (val & core->layout->frac_mask) >> core->layout->frac_shift;
1084318c69fSTony Han 
1094318c69fSTony Han 	if (sam9x60_frac_pll_ready(regmap, core->id) &&
1104318c69fSTony Han 	    cmul == frac->mul && cfrac == frac->frac)
1114318c69fSTony Han 		return TEE_SUCCESS;
1124318c69fSTony Han 
1134318c69fSTony Han 	/* Recommended value for PMC_PLL_ACR */
1144318c69fSTony Han 	if (core->charac->upll)
1154318c69fSTony Han 		val = AT91_PMC_PLL_ACR_DEFAULT_UPLL;
1164318c69fSTony Han 	else
1174318c69fSTony Han 		val = AT91_PMC_PLL_ACR_DEFAULT_PLLA;
1184318c69fSTony Han 	io_write32(regmap + AT91_PMC_PLL_ACR, val);
1194318c69fSTony Han 
1204318c69fSTony Han 	io_write32(regmap + AT91_PMC_PLL_CTRL1,
1214318c69fSTony Han 		   SHIFT_U32(frac->mul, core->layout->mul_shift) |
1224318c69fSTony Han 		   SHIFT_U32(frac->frac, core->layout->frac_shift));
1234318c69fSTony Han 
1244318c69fSTony Han 	if (core->charac->upll) {
1254318c69fSTony Han 		/* Enable the UTMI internal bandgap */
1264318c69fSTony Han 		val |= AT91_PMC_PLL_ACR_UTMIBG;
1274318c69fSTony Han 		io_write32(regmap + AT91_PMC_PLL_ACR, val);
1284318c69fSTony Han 
1294318c69fSTony Han 		udelay(10);
1304318c69fSTony Han 
1314318c69fSTony Han 		/* Enable the UTMI internal regulator */
1324318c69fSTony Han 		val |= AT91_PMC_PLL_ACR_UTMIVR;
1334318c69fSTony Han 		io_write32(regmap + AT91_PMC_PLL_ACR, val);
1344318c69fSTony Han 
1354318c69fSTony Han 		udelay(10);
1364318c69fSTony Han 	}
1374318c69fSTony Han 
1384318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
1394318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MASK,
1404318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | core->id);
1414318c69fSTony Han 
1424318c69fSTony Han 	io_setbits32(regmap + AT91_PMC_PLL_CTRL0,
1434318c69fSTony Han 		     AT91_PMC_PLL_CTRL0_ENLOCK | AT91_PMC_PLL_CTRL0_ENPLL);
1444318c69fSTony Han 
1454318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
1464318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MASK,
1474318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | core->id);
1484318c69fSTony Han 
1494318c69fSTony Han 	if (WAIT_PLL_READY_TIMEOUT(regmap, core->id)) {
1504318c69fSTony Han 		EMSG("PLL not ready");
1514318c69fSTony Han 		return TEE_ERROR_BUSY;
1524318c69fSTony Han 	}
1534318c69fSTony Han 
1544318c69fSTony Han 	return TEE_SUCCESS;
1554318c69fSTony Han }
1564318c69fSTony Han 
sam9x60_frac_pll_prepare(struct clk * hw)1574318c69fSTony Han static TEE_Result sam9x60_frac_pll_prepare(struct clk *hw)
1584318c69fSTony Han {
1594318c69fSTony Han 	struct sam9x60_frac *frac = hw->priv;
1604318c69fSTony Han 
1614318c69fSTony Han 	return sam9x60_frac_pll_set(frac);
1624318c69fSTony Han }
1634318c69fSTony Han 
sam9x60_frac_pll_unprepare(struct clk * hw)1644318c69fSTony Han static void sam9x60_frac_pll_unprepare(struct clk *hw)
1654318c69fSTony Han {
1664318c69fSTony Han 	struct sam9x60_frac *frac = hw->priv;
1674318c69fSTony Han 
1684318c69fSTony Han 	io_clrsetbits32(frac->core.base + AT91_PMC_PLL_UPDT,
1694318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK, frac->core.id);
1704318c69fSTony Han 
1714318c69fSTony Han 	io_clrbits32(frac->core.base + AT91_PMC_PLL_CTRL0,
1724318c69fSTony Han 		     AT91_PMC_PLL_CTRL0_ENPLL);
1734318c69fSTony Han 
1744318c69fSTony Han 	if (frac->core.charac->upll)
1754318c69fSTony Han 		io_clrbits32(frac->core.base + AT91_PMC_PLL_ACR,
1764318c69fSTony Han 			     AT91_PMC_PLL_ACR_UTMIBG |
1774318c69fSTony Han 			     AT91_PMC_PLL_ACR_UTMIVR);
1784318c69fSTony Han 
1794318c69fSTony Han 	io_clrsetbits32(frac->core.base + AT91_PMC_PLL_UPDT,
1804318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MASK,
1814318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | frac->core.id);
1824318c69fSTony Han }
1834318c69fSTony Han 
sam9x60_frac_pll_compute_mul_frac(struct sam9x60_frac * frac,unsigned long rate,unsigned long parent_rate,bool update)1844318c69fSTony Han static TEE_Result sam9x60_frac_pll_compute_mul_frac(struct sam9x60_frac *frac,
1854318c69fSTony Han 						    unsigned long rate,
1864318c69fSTony Han 						    unsigned long parent_rate,
1874318c69fSTony Han 						    bool update)
1884318c69fSTony Han {
1894318c69fSTony Han 	unsigned long tmprate = 0;
1904318c69fSTony Han 	unsigned long remainder = 0;
1914318c69fSTony Han 	unsigned long nmul = 0;
1924318c69fSTony Han 	unsigned long nfrac = 0;
1934318c69fSTony Han 
1944318c69fSTony Han 	if (rate < frac->core.charac->output[0].min ||
1954318c69fSTony Han 	    rate > frac->core.charac->output[0].max)
1964318c69fSTony Han 		return TEE_ERROR_GENERIC;
1974318c69fSTony Han 
1984318c69fSTony Han 	/*
1994318c69fSTony Han 	 * Calculate the multiplier associated with the current
2004318c69fSTony Han 	 * divider that provide the closest rate to the requested one.
2014318c69fSTony Han 	 */
2024318c69fSTony Han 	nmul = rate / parent_rate;
2034318c69fSTony Han 	tmprate = parent_rate * nmul;
2044318c69fSTony Han 	remainder = rate - tmprate;
2054318c69fSTony Han 
2064318c69fSTony Han 	if (remainder) {
2074318c69fSTony Han 		nfrac = UDIV_ROUND_NEAREST((uint64_t)remainder * (1 << 22),
2084318c69fSTony Han 					   parent_rate);
2094318c69fSTony Han 
2104318c69fSTony Han 		tmprate += UDIV_ROUND_NEAREST((uint64_t)nfrac * parent_rate,
2114318c69fSTony Han 					      1 << 22);
2124318c69fSTony Han 	}
2134318c69fSTony Han 
2144318c69fSTony Han 	/* Check if resulted rate is a valid. */
2154318c69fSTony Han 	if (tmprate < frac->core.charac->output[0].min ||
2164318c69fSTony Han 	    tmprate > frac->core.charac->output[0].max)
2174318c69fSTony Han 		return TEE_ERROR_GENERIC;
2184318c69fSTony Han 
2194318c69fSTony Han 	if (update) {
2204318c69fSTony Han 		frac->mul = nmul - 1;
2214318c69fSTony Han 		frac->frac = nfrac;
2224318c69fSTony Han 	}
2234318c69fSTony Han 
2244318c69fSTony Han 	return TEE_SUCCESS;
2254318c69fSTony Han }
2264318c69fSTony Han 
sam9x60_frac_pll_set_rate_chg(struct clk * hw,unsigned long rate,unsigned long parent_rate)2274318c69fSTony Han static TEE_Result sam9x60_frac_pll_set_rate_chg(struct clk *hw,
2284318c69fSTony Han 						unsigned long rate,
2294318c69fSTony Han 						unsigned long parent_rate)
2304318c69fSTony Han {
2314318c69fSTony Han 	TEE_Result ret = TEE_SUCCESS;
2324318c69fSTony Han 	struct sam9x60_frac *frac = hw->priv;
2334318c69fSTony Han 	struct sam9x60_pll_core *core = &frac->core;
2344318c69fSTony Han 	vaddr_t regmap = core->base;
2354318c69fSTony Han 
2364318c69fSTony Han 	ret = sam9x60_frac_pll_compute_mul_frac(frac, rate, parent_rate, true);
2374318c69fSTony Han 	if (ret == TEE_SUCCESS) {
238e83d1906STony Han 		io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
239e83d1906STony Han 				AT91_PMC_PLL_UPDT_ID_MASK, core->id);
240e83d1906STony Han 
2414318c69fSTony Han 		io_write32(regmap + AT91_PMC_PLL_CTRL1,
2424318c69fSTony Han 			   SHIFT_U32(frac->mul, core->layout->mul_shift) |
2434318c69fSTony Han 			   SHIFT_U32(frac->frac, core->layout->frac_shift));
2444318c69fSTony Han 
2454318c69fSTony Han 		io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
2464318c69fSTony Han 				AT91_PMC_PLL_UPDT_UPDATE |
2474318c69fSTony Han 				AT91_PMC_PLL_UPDT_ID_MASK,
2484318c69fSTony Han 				AT91_PMC_PLL_UPDT_UPDATE | core->id);
2494318c69fSTony Han 
2504318c69fSTony Han 		io_setbits32(regmap + AT91_PMC_PLL_CTRL0,
2514318c69fSTony Han 			     AT91_PMC_PLL_CTRL0_ENLOCK |
2524318c69fSTony Han 			     AT91_PMC_PLL_CTRL0_ENPLL);
2534318c69fSTony Han 
2544318c69fSTony Han 		io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
2554318c69fSTony Han 				AT91_PMC_PLL_UPDT_UPDATE |
2564318c69fSTony Han 				AT91_PMC_PLL_UPDT_ID_MASK,
2574318c69fSTony Han 				AT91_PMC_PLL_UPDT_UPDATE | core->id);
2584318c69fSTony Han 
2594318c69fSTony Han 		if (WAIT_PLL_READY_TIMEOUT(regmap, core->id)) {
2604318c69fSTony Han 			EMSG("PLL not ready");
2614318c69fSTony Han 			return TEE_ERROR_BUSY;
2624318c69fSTony Han 		}
2634318c69fSTony Han 	}
2644318c69fSTony Han 
2654318c69fSTony Han 	return ret;
2664318c69fSTony Han }
2674318c69fSTony Han 
2684318c69fSTony Han static const struct clk_ops sam9x60_frac_pll_ops_chg = {
2694318c69fSTony Han 	.enable = sam9x60_frac_pll_prepare,
2704318c69fSTony Han 	.disable = sam9x60_frac_pll_unprepare,
2714318c69fSTony Han 	.get_rate = sam9x60_frac_pll_recalc_rate,
2724318c69fSTony Han 	.set_rate = sam9x60_frac_pll_set_rate_chg,
2734318c69fSTony Han };
2744318c69fSTony Han 
sam9x60_div_pll_set_div(struct sam9x60_pll_core * core,uint32_t div,bool enable)2754318c69fSTony Han static TEE_Result sam9x60_div_pll_set_div(struct sam9x60_pll_core *core,
2764318c69fSTony Han 					  uint32_t div,
2774318c69fSTony Han 					  bool enable)
2784318c69fSTony Han {
2794318c69fSTony Han 	vaddr_t regmap = core->base;
2804318c69fSTony Han 	uint32_t enable_mask = enable ? core->layout->endiv_mask : 0;
2814318c69fSTony Han 	uint32_t ena_val = enable ? BIT(core->layout->endiv_shift) : 0;
2824318c69fSTony Han 
283e83d1906STony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
284e83d1906STony Han 			AT91_PMC_PLL_UPDT_ID_MASK, core->id);
285e83d1906STony Han 
2864318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_CTRL0,
2874318c69fSTony Han 			core->layout->div_mask | enable_mask,
2884318c69fSTony Han 			SHIFT_U32(div, core->layout->div_shift) | ena_val);
2894318c69fSTony Han 
2904318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
2914318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MASK,
2924318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | core->id);
2934318c69fSTony Han 
2944318c69fSTony Han 	if (WAIT_PLL_READY_TIMEOUT(regmap, core->id)) {
2954318c69fSTony Han 		EMSG("PLL not ready");
2964318c69fSTony Han 		return TEE_ERROR_BUSY;
2974318c69fSTony Han 	}
2984318c69fSTony Han 
2994318c69fSTony Han 	return TEE_SUCCESS;
3004318c69fSTony Han }
3014318c69fSTony Han 
sam9x60_div_pll_set(struct sam9x60_div * div)3024318c69fSTony Han static TEE_Result sam9x60_div_pll_set(struct sam9x60_div *div)
3034318c69fSTony Han {
3044318c69fSTony Han 	struct sam9x60_pll_core *core = &div->core;
3054318c69fSTony Han 	vaddr_t regmap = core->base;
3064318c69fSTony Han 	unsigned int val = 0;
3074318c69fSTony Han 	unsigned int cdiv = 0;
3084318c69fSTony Han 
3094318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
3104318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK, core->id);
3114318c69fSTony Han 	val = io_read32(regmap + AT91_PMC_PLL_CTRL0);
3124318c69fSTony Han 	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
3134318c69fSTony Han 
3144318c69fSTony Han 	/* Stop if enabled an nothing changed. */
3154318c69fSTony Han 	if ((val & core->layout->endiv_mask) && cdiv == div->div)
3164318c69fSTony Han 		return TEE_SUCCESS;
3174318c69fSTony Han 
3184318c69fSTony Han 	return sam9x60_div_pll_set_div(core, div->div, 1);
3194318c69fSTony Han }
3204318c69fSTony Han 
sam9x60_div_pll_prepare(struct clk * hw)3214318c69fSTony Han static TEE_Result sam9x60_div_pll_prepare(struct clk *hw)
3224318c69fSTony Han {
3234318c69fSTony Han 	struct sam9x60_div *div = hw->priv;
3244318c69fSTony Han 
3254318c69fSTony Han 	return sam9x60_div_pll_set(div);
3264318c69fSTony Han }
3274318c69fSTony Han 
sam9x60_div_pll_unprepare(struct clk * hw)3284318c69fSTony Han static void sam9x60_div_pll_unprepare(struct clk *hw)
3294318c69fSTony Han {
3304318c69fSTony Han 	struct sam9x60_div *div = hw->priv;
3314318c69fSTony Han 	struct sam9x60_pll_core *core = &div->core;
3324318c69fSTony Han 	vaddr_t regmap = core->base;
3334318c69fSTony Han 
3344318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
3354318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK, core->id);
3364318c69fSTony Han 
3374318c69fSTony Han 	io_clrbits32(regmap + AT91_PMC_PLL_CTRL0, core->layout->endiv_mask);
3384318c69fSTony Han 
3394318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
3404318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MASK,
3414318c69fSTony Han 			AT91_PMC_PLL_UPDT_UPDATE | core->id);
3424318c69fSTony Han }
3434318c69fSTony Han 
sam9x60_div_pll_recalc_rate(struct clk * hw,unsigned long parent_rate)3444318c69fSTony Han static unsigned long sam9x60_div_pll_recalc_rate(struct clk *hw,
3454318c69fSTony Han 						 unsigned long parent_rate)
3464318c69fSTony Han {
3474318c69fSTony Han 	struct sam9x60_div *div = hw->priv;
3484318c69fSTony Han 
3494318c69fSTony Han 	return UDIV_ROUND_NEAREST(parent_rate, div->div + 1);
3504318c69fSTony Han }
3514318c69fSTony Han 
sam9x60_div_pll_set_rate(struct clk * hw,unsigned long rate,unsigned long parent_rate)3524318c69fSTony Han static TEE_Result sam9x60_div_pll_set_rate(struct clk *hw,
3534318c69fSTony Han 					   unsigned long rate,
3544318c69fSTony Han 					   unsigned long parent_rate)
3554318c69fSTony Han {
3564318c69fSTony Han 	struct sam9x60_div *div = hw->priv;
3574318c69fSTony Han 
358*b20bd0e0STony Han 	if (parent_rate > rate)
3594318c69fSTony Han 		div->div = UDIV_ROUND_NEAREST(parent_rate, rate) - 1;
360*b20bd0e0STony Han 	else
361*b20bd0e0STony Han 		div->div = 0;
3624318c69fSTony Han 
3634318c69fSTony Han 	return TEE_SUCCESS;
3644318c69fSTony Han }
3654318c69fSTony Han 
sam9x60_div_pll_set_rate_chg(struct clk * hw,unsigned long rate,unsigned long parent_rate)3664318c69fSTony Han static TEE_Result sam9x60_div_pll_set_rate_chg(struct clk *hw,
3674318c69fSTony Han 					       unsigned long rate,
3684318c69fSTony Han 					       unsigned long parent_rate)
3694318c69fSTony Han {
3704318c69fSTony Han 	struct sam9x60_div *div = hw->priv;
3714318c69fSTony Han 	struct sam9x60_pll_core *core = &div->core;
3724318c69fSTony Han 	vaddr_t regmap = core->base;
3734318c69fSTony Han 	unsigned int val = 0;
3744318c69fSTony Han 	unsigned int cdiv = 0;
3754318c69fSTony Han 
376*b20bd0e0STony Han 	if (parent_rate > rate)
3774318c69fSTony Han 		div->div = UDIV_ROUND_NEAREST(parent_rate, rate) - 1;
378*b20bd0e0STony Han 	else
379*b20bd0e0STony Han 		div->div = 0;
3804318c69fSTony Han 
3814318c69fSTony Han 	io_clrsetbits32(regmap + AT91_PMC_PLL_UPDT,
3824318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK,
3834318c69fSTony Han 			core->id);
3844318c69fSTony Han 	val = io_read32(regmap + AT91_PMC_PLL_CTRL0);
3854318c69fSTony Han 	cdiv = (val & core->layout->div_mask) >> core->layout->div_shift;
3864318c69fSTony Han 
3874318c69fSTony Han 	/* Stop if nothing changed. */
3884318c69fSTony Han 	if (cdiv == div->div)
3894318c69fSTony Han 		return TEE_SUCCESS;
3904318c69fSTony Han 
3914318c69fSTony Han 	return sam9x60_div_pll_set_div(core, div->div, 0);
3924318c69fSTony Han }
3934318c69fSTony Han 
3944318c69fSTony Han static const struct clk_ops sam9x60_div_pll_ops = {
3954318c69fSTony Han 	.enable = sam9x60_div_pll_prepare,
3964318c69fSTony Han 	.disable = sam9x60_div_pll_unprepare,
3974318c69fSTony Han 	.set_rate = sam9x60_div_pll_set_rate,
3984318c69fSTony Han 	.get_rate = sam9x60_div_pll_recalc_rate,
3994318c69fSTony Han };
4004318c69fSTony Han 
4014318c69fSTony Han static const struct clk_ops sam9x60_div_pll_ops_chg = {
4024318c69fSTony Han 	.enable = sam9x60_div_pll_prepare,
4034318c69fSTony Han 	.disable = sam9x60_div_pll_unprepare,
4044318c69fSTony Han 	.set_rate = sam9x60_div_pll_set_rate_chg,
4054318c69fSTony Han 	.get_rate = sam9x60_div_pll_recalc_rate,
4064318c69fSTony Han };
4074318c69fSTony Han 
sam9x60_clk_register_frac_pll(struct pmc_data * pmc,const char * name,struct clk * parent,uint8_t id,const struct clk_pll_charac * charac,const struct clk_pll_layout * layout,uint32_t flags)4084318c69fSTony Han struct clk *sam9x60_clk_register_frac_pll(struct pmc_data *pmc,
4094318c69fSTony Han 					  const char *name,
4104318c69fSTony Han 					  struct clk *parent,
4114318c69fSTony Han 					  uint8_t id,
4124318c69fSTony Han 					  const struct clk_pll_charac *charac,
4134318c69fSTony Han 					  const struct clk_pll_layout *layout,
4144318c69fSTony Han 					  uint32_t flags)
4154318c69fSTony Han {
4164318c69fSTony Han 	struct sam9x60_frac *frac = NULL;
4174318c69fSTony Han 	struct clk *hw = NULL;
4184318c69fSTony Han 	unsigned long parent_rate = 0;
4194318c69fSTony Han 	unsigned int val = 0;
4204318c69fSTony Han 	TEE_Result ret = TEE_SUCCESS;
4214318c69fSTony Han 
4224318c69fSTony Han 	frac = calloc(1, sizeof(*frac));
4234318c69fSTony Han 	if (!frac)
4244318c69fSTony Han 		return NULL;
4254318c69fSTony Han 
4264318c69fSTony Han 	hw = clk_alloc(name, &sam9x60_frac_pll_ops_chg, &parent, 1);
4274318c69fSTony Han 	if (!hw) {
4284318c69fSTony Han 		free(frac);
4294318c69fSTony Han 		return NULL;
4304318c69fSTony Han 	}
4314318c69fSTony Han 
4324318c69fSTony Han 	hw->priv = frac;
4334318c69fSTony Han 	hw->flags = flags;
4344318c69fSTony Han 	frac->core.id = id;
4354318c69fSTony Han 	frac->core.charac = charac;
4364318c69fSTony Han 	frac->core.layout = layout;
4374318c69fSTony Han 	frac->core.base = pmc->base;
4384318c69fSTony Han 
4394318c69fSTony Han 	if (sam9x60_pll_ready(pmc->base, id)) {
4404318c69fSTony Han 		io_clrsetbits32(frac->core.base + AT91_PMC_PLL_UPDT,
4414318c69fSTony Han 				AT91_PMC_PLL_UPDT_ID_MASK, id);
4424318c69fSTony Han 		val = io_read32(pmc->base + AT91_PMC_PLL_CTRL1);
4434318c69fSTony Han 		frac->mul = (val >> PMC_PLL_CTRL1_MUL_POS) &
4444318c69fSTony Han 			PMC_PLL_CTRL1_MUL_MASK;
4454318c69fSTony Han 		frac->frac = (val >> PMC_PLL_CTRL1_FRACR_POS) &
4464318c69fSTony Han 			PMC_PLL_CTRL1_FRACR_MASK;
4474318c69fSTony Han 	} else {
4484318c69fSTony Han 		/*
4494318c69fSTony Han 		 * This means the PLL is not setup by bootloaders. In this
4504318c69fSTony Han 		 * case we need to set the minimum rate for it. Otherwise
4514318c69fSTony Han 		 * a clock child of this PLL may be enabled before setting
4524318c69fSTony Han 		 * its rate leading to enabling this PLL with unsupported
4534318c69fSTony Han 		 * rate. This will lead to PLL not being locked at all.
4544318c69fSTony Han 		 */
4554318c69fSTony Han 		parent_rate = clk_get_rate(parent);
4564318c69fSTony Han 		if (!parent_rate) {
4574318c69fSTony Han 			clk_free(hw);
4584318c69fSTony Han 			free(frac);
4594318c69fSTony Han 			return NULL;
4604318c69fSTony Han 		}
4614318c69fSTony Han 
4624318c69fSTony Han 		ret = sam9x60_frac_pll_compute_mul_frac(frac,
4634318c69fSTony Han 							charac->output[0].min,
4644318c69fSTony Han 							parent_rate, true);
4654318c69fSTony Han 		if (ret != TEE_SUCCESS) {
4664318c69fSTony Han 			clk_free(hw);
4674318c69fSTony Han 			free(frac);
4684318c69fSTony Han 			return NULL;
4694318c69fSTony Han 		}
4704318c69fSTony Han 	}
4714318c69fSTony Han 
4724318c69fSTony Han 	frac->core.hw = hw;
4734318c69fSTony Han 	if (clk_register(hw)) {
4744318c69fSTony Han 		clk_free(hw);
4754318c69fSTony Han 		free(frac);
4764318c69fSTony Han 		return NULL;
4774318c69fSTony Han 	}
4784318c69fSTony Han 
4794318c69fSTony Han 	return hw;
4804318c69fSTony Han }
4814318c69fSTony Han 
sam9x60_clk_register_div_pll(struct pmc_data * pmc,const char * name,struct clk * parent,uint8_t id,const struct clk_pll_charac * charac,const struct clk_pll_layout * layout,uint32_t flags,uint32_t safe_div)4824318c69fSTony Han struct clk *sam9x60_clk_register_div_pll(struct pmc_data *pmc,
4834318c69fSTony Han 					 const char *name,
4844318c69fSTony Han 					 struct clk *parent,
4854318c69fSTony Han 					 uint8_t id,
4864318c69fSTony Han 					 const struct clk_pll_charac *charac,
4874318c69fSTony Han 					 const struct clk_pll_layout *layout,
4884318c69fSTony Han 					 uint32_t flags,
4894318c69fSTony Han 					 uint32_t safe_div)
4904318c69fSTony Han {
4914318c69fSTony Han 	struct sam9x60_div *div = NULL;
4924318c69fSTony Han 	struct clk *hw = NULL;
4934318c69fSTony Han 	unsigned int val = 0;
4944318c69fSTony Han 
4954318c69fSTony Han 	if (safe_div >= PLL_DIV_MAX)
4964318c69fSTony Han 		safe_div = PLL_DIV_MAX - 1;
4974318c69fSTony Han 
4984318c69fSTony Han 	div = calloc(1, sizeof(*div));
4994318c69fSTony Han 	if (!div)
5004318c69fSTony Han 		return NULL;
5014318c69fSTony Han 
5024318c69fSTony Han 	if (flags & CLK_SET_RATE_GATE)
5034318c69fSTony Han 		hw = clk_alloc(name, &sam9x60_div_pll_ops, &parent, 1);
5044318c69fSTony Han 	else
5054318c69fSTony Han 		hw = clk_alloc(name, &sam9x60_div_pll_ops_chg, &parent, 1);
5064318c69fSTony Han 	if (!hw) {
5074318c69fSTony Han 		free(div);
5084318c69fSTony Han 		return NULL;
5094318c69fSTony Han 	}
5104318c69fSTony Han 
5114318c69fSTony Han 	hw->priv = div;
5124318c69fSTony Han 	hw->flags = flags;
5134318c69fSTony Han 	div->core.id = id;
5144318c69fSTony Han 	div->core.charac = charac;
5154318c69fSTony Han 	div->core.layout = layout;
5164318c69fSTony Han 	div->core.base = pmc->base;
5174318c69fSTony Han 	div->safe_div = safe_div;
5184318c69fSTony Han 
5194318c69fSTony Han 	io_clrsetbits32(pmc->base + AT91_PMC_PLL_UPDT,
5204318c69fSTony Han 			AT91_PMC_PLL_UPDT_ID_MASK, id);
5214318c69fSTony Han 	val = io_read32(pmc->base + AT91_PMC_PLL_CTRL0);
5224318c69fSTony Han 	div->div = (val >> PMC_PLL_CTRL0_DIV_POS) & PMC_PLL_CTRL0_DIV_MASK;
5234318c69fSTony Han 
5244318c69fSTony Han 	div->core.hw = hw;
5254318c69fSTony Han 	if (clk_register(hw)) {
5264318c69fSTony Han 		clk_free(hw);
5274318c69fSTony Han 		free(div);
5284318c69fSTony Han 		return NULL;
5294318c69fSTony Han 	}
5304318c69fSTony Han 
5314318c69fSTony Han 	return hw;
5324318c69fSTony Han }
533