Lines Matching +full:clock +full:- +full:mult

1 // SPDX-License-Identifier: GPL-2.0
3 * R-Car Gen4 Clock Pulse Generator
7 * Based on rcar-gen3-cpg.c
9 * Copyright (C) 2015-2018 Glider bvba
15 #include <linux/clk-provider.h>
23 #include "renesas-cpg-mssr.h"
24 #include "rcar-gen4-cpg.h"
25 #include "rcar-cpg-lib.h"
33 #define CPG_PLLECR_PLLST(n) BIT(8 + ((n) < 3 ? (n) - 1 : \
56 #define CPG_PLLxCR0_NI8 GENMASK(27, 20) /* Integer mult. factor */
57 #define CPG_PLLxCR1_NF25 GENMASK(24, 0) /* Fractional mult. factor */
60 #define CPG_PLLxCR0_NI9 GENMASK(28, 20) /* Integer mult. factor */
61 #define CPG_PLLxCR1_NF24 GENMASK(23, 0) /* Fractional mult. factor */
65 #define CPG_RPCCKCR 0x874 /* RPC Clock Freq. Control Register */
67 #define CPG_SD0CKCR1 0x8a4 /* SD-IF0 Clock Freq. Control Reg. 1 */
69 #define CPG_SD0CKCR1_SDSRC_SEL GENMASK(30, 29) /* SDSRC clock freq. select */
86 u32 cr0 = readl(pll_clk->pllcr0_reg); in cpg_pll_8_25_clk_recalc_rate()
93 nf = FIELD_GET(CPG_PLLxCR1_NF25, readl(pll_clk->pllcr1_reg)); in cpg_pll_8_25_clk_recalc_rate()
105 u32 cr0 = readl(pll_clk->pllcr0_reg); in cpg_pll_8_25_clk_determine_rate()
108 prate = req->best_parent_rate * 2; in cpg_pll_8_25_clk_determine_rate()
109 min_mult = max(div64_ul(req->min_rate, prate), 1ULL); in cpg_pll_8_25_clk_determine_rate()
110 max_mult = min(div64_ul(req->max_rate, prate), 256ULL); in cpg_pll_8_25_clk_determine_rate()
112 return -EINVAL; in cpg_pll_8_25_clk_determine_rate()
115 ni = div64_ul(req->rate, prate); in cpg_pll_8_25_clk_determine_rate()
121 nf = div64_ul((u64)(req->rate - prate * ni) << 24, in cpg_pll_8_25_clk_determine_rate()
122 req->best_parent_rate); in cpg_pll_8_25_clk_determine_rate()
125 ni = DIV_ROUND_CLOSEST_ULL(req->rate, prate); in cpg_pll_8_25_clk_determine_rate()
129 req->rate = prate * ni + mul_u64_u32_shr(req->best_parent_rate, nf, 24); in cpg_pll_8_25_clk_determine_rate()
139 u32 cr0 = readl(pll_clk->pllcr0_reg); in cpg_pll_8_25_clk_set_rate()
150 nf = div64_ul((u64)(rate - prate * ni) << 24, in cpg_pll_8_25_clk_set_rate()
158 if (readl(pll_clk->pllcr0_reg) & CPG_PLLxCR0_KICK) in cpg_pll_8_25_clk_set_rate()
159 return -EBUSY; in cpg_pll_8_25_clk_set_rate()
161 cpg_reg_modify(pll_clk->pllcr0_reg, CPG_PLLxCR0_NI8, in cpg_pll_8_25_clk_set_rate()
162 FIELD_PREP(CPG_PLLxCR0_NI8, ni - 1)); in cpg_pll_8_25_clk_set_rate()
164 cpg_reg_modify(pll_clk->pllcr1_reg, CPG_PLLxCR1_NF25, in cpg_pll_8_25_clk_set_rate()
169 * clock change completion. in cpg_pll_8_25_clk_set_rate()
171 cpg_reg_modify(pll_clk->pllcr0_reg, 0, CPG_PLLxCR0_KICK); in cpg_pll_8_25_clk_set_rate()
182 return readl_poll_timeout(pll_clk->pllecr_reg, val, in cpg_pll_8_25_clk_set_rate()
183 val & pll_clk->pllecr_pllst_mask, 0, 1000); in cpg_pll_8_25_clk_set_rate()
200 u32 cr0 = readl(pll_clk->pllcr0_reg); in cpg_pll_9_24_clk_recalc_rate()
207 nf = FIELD_GET(CPG_PLLxCR1_NF24, readl(pll_clk->pllcr1_reg)); in cpg_pll_9_24_clk_recalc_rate()
227 [1 - 1] = { CPG_PLL1CR0, CPG_PLL1CR1 }, in cpg_pll_clk_register()
228 [2 - 1] = { CPG_PLL2CR0, CPG_PLL2CR1 }, in cpg_pll_clk_register()
229 [3 - 1] = { CPG_PLL3CR0, CPG_PLL3CR1 }, in cpg_pll_clk_register()
230 [4 - 1] = { CPG_PLL4CR0, CPG_PLL4CR1 }, in cpg_pll_clk_register()
231 [6 - 1] = { CPG_PLL6CR0, CPG_PLL6CR1 }, in cpg_pll_clk_register()
239 return ERR_PTR(-ENOMEM); in cpg_pll_clk_register()
246 pll_clk->hw.init = &init; in cpg_pll_clk_register()
247 pll_clk->pllcr0_reg = base + pll_cr_offsets[index - 1].cr0; in cpg_pll_clk_register()
248 pll_clk->pllcr1_reg = base + pll_cr_offsets[index - 1].cr1; in cpg_pll_clk_register()
249 pll_clk->pllecr_reg = base + CPG_PLLECR; in cpg_pll_clk_register()
250 pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index); in cpg_pll_clk_register()
252 clk = clk_register(NULL, &pll_clk->hw); in cpg_pll_clk_register()
260 * Z0 Clock & Z1 Clock
282 unsigned int mult; in cpg_z_clk_recalc_rate() local
285 val = readl(zclk->reg) & zclk->mask; in cpg_z_clk_recalc_rate()
286 mult = 32 - (val >> __ffs(zclk->mask)); in cpg_z_clk_recalc_rate()
288 return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, in cpg_z_clk_recalc_rate()
289 32 * zclk->fixed_div); in cpg_z_clk_recalc_rate()
296 unsigned int min_mult, max_mult, mult; in cpg_z_clk_determine_rate() local
299 rate = min(req->rate, req->max_rate); in cpg_z_clk_determine_rate()
300 if (rate <= zclk->max_rate) { in cpg_z_clk_determine_rate()
302 prate = zclk->max_rate; in cpg_z_clk_determine_rate()
307 req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), in cpg_z_clk_determine_rate()
308 prate * zclk->fixed_div); in cpg_z_clk_determine_rate()
310 prate = req->best_parent_rate / zclk->fixed_div; in cpg_z_clk_determine_rate()
311 min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL); in cpg_z_clk_determine_rate()
312 max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL); in cpg_z_clk_determine_rate()
314 return -EINVAL; in cpg_z_clk_determine_rate()
316 mult = DIV_ROUND_CLOSEST_ULL(rate * 32ULL, prate); in cpg_z_clk_determine_rate()
317 mult = clamp(mult, min_mult, max_mult); in cpg_z_clk_determine_rate()
319 req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32); in cpg_z_clk_determine_rate()
327 unsigned int mult; in cpg_z_clk_set_rate() local
330 mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div, in cpg_z_clk_set_rate()
332 mult = clamp(mult, 1U, 32U); in cpg_z_clk_set_rate()
334 if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) in cpg_z_clk_set_rate()
335 return -EBUSY; in cpg_z_clk_set_rate()
337 cpg_reg_modify(zclk->reg, zclk->mask, (32 - mult) << __ffs(zclk->mask)); in cpg_z_clk_set_rate()
341 * clock change completion. in cpg_z_clk_set_rate()
343 cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK); in cpg_z_clk_set_rate()
354 for (i = 1000; i; i--) { in cpg_z_clk_set_rate()
355 if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) in cpg_z_clk_set_rate()
361 return -ETIMEDOUT; in cpg_z_clk_set_rate()
382 return ERR_PTR(-ENOMEM); in cpg_z_clk_register()
391 zclk->reg = reg + CPG_FRQCRC0; in cpg_z_clk_register()
393 zclk->reg = reg + CPG_FRQCRC1; in cpg_z_clk_register()
394 offset -= 32; in cpg_z_clk_register()
396 zclk->kick_reg = reg + CPG_FRQCRB; in cpg_z_clk_register()
397 zclk->hw.init = &init; in cpg_z_clk_register()
398 zclk->mask = GENMASK(offset + 4, offset); in cpg_z_clk_register()
399 zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */ in cpg_z_clk_register()
401 clk = clk_register(NULL, &zclk->hw); in cpg_z_clk_register()
407 zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) / in cpg_z_clk_register()
408 zclk->fixed_div; in cpg_z_clk_register()
425 unsigned int mult = 1; in rcar_gen4_cpg_clk_register() local
429 parent = clks[core->parent & 0xffff]; /* some types use high bits */ in rcar_gen4_cpg_clk_register()
433 switch (core->type) { in rcar_gen4_cpg_clk_register()
435 div = cpg_pll_config->extal_div; in rcar_gen4_cpg_clk_register()
439 mult = cpg_pll_config->pll1_mult; in rcar_gen4_cpg_clk_register()
440 div = cpg_pll_config->pll1_div; in rcar_gen4_cpg_clk_register()
444 mult = cpg_pll_config->pll5_mult; in rcar_gen4_cpg_clk_register()
445 div = cpg_pll_config->pll5_div; in rcar_gen4_cpg_clk_register()
449 value = readl(base + core->offset); in rcar_gen4_cpg_clk_register()
450 mult = (FIELD_GET(CPG_PLLxCR_STC, value) + 1) * 2; in rcar_gen4_cpg_clk_register()
454 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
455 base, core->offset, in rcar_gen4_cpg_clk_register()
459 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
460 base, core->offset, in rcar_gen4_cpg_clk_register()
467 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
468 base, core->offset, in rcar_gen4_cpg_clk_register()
472 return cpg_z_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
473 base, core->div, core->offset); in rcar_gen4_cpg_clk_register()
481 return cpg_sdh_clk_register(core->name, base + core->offset, in rcar_gen4_cpg_clk_register()
485 return cpg_sd_clk_register(core->name, base + core->offset, in rcar_gen4_cpg_clk_register()
490 * Clock selectable between two parents and two fixed dividers in rcar_gen4_cpg_clk_register()
493 if (cpg_mode & BIT(core->offset)) { in rcar_gen4_cpg_clk_register()
494 div = core->div & 0xffff; in rcar_gen4_cpg_clk_register()
496 parent = clks[core->parent >> 16]; in rcar_gen4_cpg_clk_register()
499 div = core->div >> 16; in rcar_gen4_cpg_clk_register()
501 mult = 1; in rcar_gen4_cpg_clk_register()
506 * Clock combining OSC EXTAL predivider and a fixed divider in rcar_gen4_cpg_clk_register()
508 div = cpg_pll_config->osc_prediv * core->div; in rcar_gen4_cpg_clk_register()
512 return clk_register_divider_table(NULL, core->name, in rcar_gen4_cpg_clk_register()
519 return cpg_rpc_clk_register(core->name, base + CPG_RPCCKCR, in rcar_gen4_cpg_clk_register()
523 return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR, in rcar_gen4_cpg_clk_register()
527 return ERR_PTR(-EINVAL); in rcar_gen4_cpg_clk_register()
530 return clk_register_fixed_factor(NULL, core->name, in rcar_gen4_cpg_clk_register()
531 __clk_get_name(parent), 0, mult, div); in rcar_gen4_cpg_clk_register()