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