Lines Matching +full:center +full:- +full:spread
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 : \
51 #define CPG_PLLxCR0_SSMODE_CENT BIT(16) /* Center (vs. Down) Spread Dithering */
67 #define CPG_SD0CKCR1 0x8a4 /* SD-IF0 Clock Freq. Control Reg. 1 */
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()
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()
282 unsigned int mult = 32 - field_get(zclk->mask, readl(zclk->reg)); in cpg_z_clk_recalc_rate()
285 32 * zclk->fixed_div); in cpg_z_clk_recalc_rate()
295 rate = min(req->rate, req->max_rate); in cpg_z_clk_determine_rate()
296 if (rate <= zclk->max_rate) { in cpg_z_clk_determine_rate()
298 prate = zclk->max_rate; in cpg_z_clk_determine_rate()
303 req->best_parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw), in cpg_z_clk_determine_rate()
304 prate * zclk->fixed_div); in cpg_z_clk_determine_rate()
306 prate = req->best_parent_rate / zclk->fixed_div; in cpg_z_clk_determine_rate()
307 min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL); in cpg_z_clk_determine_rate()
308 max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL); in cpg_z_clk_determine_rate()
310 return -EINVAL; in cpg_z_clk_determine_rate()
315 req->rate = DIV_ROUND_CLOSEST_ULL((u64)prate * mult, 32); in cpg_z_clk_determine_rate()
326 mult = DIV64_U64_ROUND_CLOSEST(rate * 32ULL * zclk->fixed_div, in cpg_z_clk_set_rate()
330 if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) in cpg_z_clk_set_rate()
331 return -EBUSY; in cpg_z_clk_set_rate()
333 cpg_reg_modify(zclk->reg, zclk->mask, in cpg_z_clk_set_rate()
334 field_prep(zclk->mask, 32 - mult)); in cpg_z_clk_set_rate()
340 cpg_reg_modify(zclk->kick_reg, 0, CPG_FRQCRB_KICK); in cpg_z_clk_set_rate()
351 for (i = 1000; i; i--) { in cpg_z_clk_set_rate()
352 if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) in cpg_z_clk_set_rate()
358 return -ETIMEDOUT; in cpg_z_clk_set_rate()
379 return ERR_PTR(-ENOMEM); in cpg_z_clk_register()
388 zclk->reg = reg + CPG_FRQCRC0; in cpg_z_clk_register()
390 zclk->reg = reg + CPG_FRQCRC1; in cpg_z_clk_register()
391 offset -= 32; in cpg_z_clk_register()
393 zclk->reg = reg + CPG_FRQCRB; in cpg_z_clk_register()
394 offset -= 64; in cpg_z_clk_register()
396 return ERR_PTR(-EINVAL); in cpg_z_clk_register()
398 zclk->kick_reg = reg + CPG_FRQCRB; in cpg_z_clk_register()
399 zclk->hw.init = &init; in cpg_z_clk_register()
400 zclk->mask = GENMASK(offset + 4, offset); in cpg_z_clk_register()
401 zclk->fixed_div = div; /* PLLVCO x 1/div x SYS-CPU divider */ in cpg_z_clk_register()
403 clk = clk_register(NULL, &zclk->hw); in cpg_z_clk_register()
409 zclk->max_rate = clk_hw_get_rate(clk_hw_get_parent(&zclk->hw)) / in cpg_z_clk_register()
410 zclk->fixed_div; in cpg_z_clk_register()
425 struct raw_notifier_head *notifiers = &pub->notifiers; in rcar_gen4_cpg_clk_register()
426 void __iomem *base = pub->base0; in rcar_gen4_cpg_clk_register()
427 struct clk **clks = pub->clks; in rcar_gen4_cpg_clk_register()
433 parent = clks[core->parent & 0xffff]; /* some types use high bits */ in rcar_gen4_cpg_clk_register()
437 switch (core->type) { in rcar_gen4_cpg_clk_register()
439 div = cpg_pll_config->extal_div; in rcar_gen4_cpg_clk_register()
443 mult = cpg_pll_config->pll1_mult; in rcar_gen4_cpg_clk_register()
444 div = cpg_pll_config->pll1_div; in rcar_gen4_cpg_clk_register()
448 mult = cpg_pll_config->pll5_mult; in rcar_gen4_cpg_clk_register()
449 div = cpg_pll_config->pll5_div; in rcar_gen4_cpg_clk_register()
453 value = readl(base + core->offset); in rcar_gen4_cpg_clk_register()
458 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
459 base, core->offset, in rcar_gen4_cpg_clk_register()
463 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
464 base, core->offset, in rcar_gen4_cpg_clk_register()
471 return cpg_pll_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
472 base, core->offset, in rcar_gen4_cpg_clk_register()
476 return cpg_z_clk_register(core->name, __clk_get_name(parent), in rcar_gen4_cpg_clk_register()
477 base, core->div, core->offset); in rcar_gen4_cpg_clk_register()
485 return cpg_sdh_clk_register(core->name, base + core->offset, in rcar_gen4_cpg_clk_register()
489 return cpg_sd_clk_register(core->name, base + core->offset, in rcar_gen4_cpg_clk_register()
497 if (cpg_mode & BIT(core->offset)) { in rcar_gen4_cpg_clk_register()
498 div = core->div & 0xffff; in rcar_gen4_cpg_clk_register()
500 parent = clks[core->parent >> 16]; in rcar_gen4_cpg_clk_register()
503 div = core->div >> 16; in rcar_gen4_cpg_clk_register()
512 div = cpg_pll_config->osc_prediv * core->div; in rcar_gen4_cpg_clk_register()
516 return clk_register_divider_table(NULL, core->name, in rcar_gen4_cpg_clk_register()
523 return cpg_rpc_clk_register(core->name, base + CPG_RPCCKCR, in rcar_gen4_cpg_clk_register()
527 return cpg_rpcd2_clk_register(core->name, base + CPG_RPCCKCR, in rcar_gen4_cpg_clk_register()
531 return ERR_PTR(-EINVAL); in rcar_gen4_cpg_clk_register()
534 return clk_register_fixed_factor(NULL, core->name, in rcar_gen4_cpg_clk_register()