Skip to content

Commit 3f70795

Browse files
committed
clk: renesas: rcar-gen3: Add custom clock for PLLs
Currently the PLLs are modeled as fixed factor clocks, based on initial settings. However, enabling CPU boost clock rates requires increasing the PLL clock rates. Add a custom clock driver to model the PLL clocks. This will allow the Z (CPU) clock driver to request changing the PLL clock rate. Based on a patch in the BSP by Takeshi Kihara <[email protected]>. Signed-off-by: Geert Uytterhoeven <[email protected]> Acked-by: Stephen Boyd <[email protected]> Reviewed-by: Yoshihiro Shimoda <[email protected]> Tested-by: Yoshihiro Shimoda <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5008604 commit 3f70795

File tree

1 file changed

+128
-19
lines changed

1 file changed

+128
-19
lines changed

drivers/clk/renesas/rcar-gen3-cpg.c

Lines changed: 128 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,127 @@
2626
#include "rcar-cpg-lib.h"
2727
#include "rcar-gen3-cpg.h"
2828

29-
#define CPG_PLL0CR 0x00d8
29+
#define CPG_PLLECR 0x00d0 /* PLL Enable Control Register */
30+
31+
#define CPG_PLLECR_PLLST(n) BIT(8 + (n)) /* PLLn Circuit Status */
32+
33+
#define CPG_PLL0CR 0x00d8 /* PLLn Control Registers */
3034
#define CPG_PLL2CR 0x002c
3135
#define CPG_PLL4CR 0x01f4
3236

37+
#define CPG_PLLnCR_STC_MASK GENMASK(30, 24) /* PLL Circuit Mult. Ratio */
38+
3339
#define CPG_RCKCR_CKSEL BIT(15) /* RCLK Clock Source Select */
3440

41+
/* PLL Clocks */
42+
struct cpg_pll_clk {
43+
struct clk_hw hw;
44+
void __iomem *pllcr_reg;
45+
void __iomem *pllecr_reg;
46+
unsigned int fixed_mult;
47+
u32 pllecr_pllst_mask;
48+
};
49+
50+
#define to_pll_clk(_hw) container_of(_hw, struct cpg_pll_clk, hw)
51+
52+
static unsigned long cpg_pll_clk_recalc_rate(struct clk_hw *hw,
53+
unsigned long parent_rate)
54+
{
55+
struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
56+
unsigned int mult;
57+
u32 val;
58+
59+
val = readl(pll_clk->pllcr_reg) & CPG_PLLnCR_STC_MASK;
60+
mult = (val >> __ffs(CPG_PLLnCR_STC_MASK)) + 1;
61+
62+
return parent_rate * mult * pll_clk->fixed_mult;
63+
}
64+
65+
static int cpg_pll_clk_determine_rate(struct clk_hw *hw,
66+
struct clk_rate_request *req)
67+
{
68+
struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
69+
unsigned int min_mult, max_mult, mult;
70+
unsigned long prate;
71+
72+
prate = req->best_parent_rate * pll_clk->fixed_mult;
73+
min_mult = max(div64_ul(req->min_rate, prate), 1ULL);
74+
max_mult = min(div64_ul(req->max_rate, prate), 128ULL);
75+
if (max_mult < min_mult)
76+
return -EINVAL;
77+
78+
mult = DIV_ROUND_CLOSEST_ULL(req->rate, prate);
79+
mult = clamp(mult, min_mult, max_mult);
80+
81+
req->rate = prate * mult;
82+
return 0;
83+
}
84+
85+
static int cpg_pll_clk_set_rate(struct clk_hw *hw, unsigned long rate,
86+
unsigned long parent_rate)
87+
{
88+
struct cpg_pll_clk *pll_clk = to_pll_clk(hw);
89+
unsigned int mult, i;
90+
u32 val;
91+
92+
mult = DIV_ROUND_CLOSEST_ULL(rate, parent_rate * pll_clk->fixed_mult);
93+
mult = clamp(mult, 1U, 128U);
94+
95+
val = readl(pll_clk->pllcr_reg);
96+
val &= ~CPG_PLLnCR_STC_MASK;
97+
val |= (mult - 1) << __ffs(CPG_PLLnCR_STC_MASK);
98+
writel(val, pll_clk->pllcr_reg);
99+
100+
for (i = 1000; i; i--) {
101+
if (readl(pll_clk->pllecr_reg) & pll_clk->pllecr_pllst_mask)
102+
return 0;
103+
104+
cpu_relax();
105+
}
106+
107+
return -ETIMEDOUT;
108+
}
109+
110+
static const struct clk_ops cpg_pll_clk_ops = {
111+
.recalc_rate = cpg_pll_clk_recalc_rate,
112+
.determine_rate = cpg_pll_clk_determine_rate,
113+
.set_rate = cpg_pll_clk_set_rate,
114+
};
115+
116+
static struct clk * __init cpg_pll_clk_register(const char *name,
117+
const char *parent_name,
118+
void __iomem *base,
119+
unsigned int mult,
120+
unsigned int offset,
121+
unsigned int index)
122+
123+
{
124+
struct cpg_pll_clk *pll_clk;
125+
struct clk_init_data init = {};
126+
struct clk *clk;
127+
128+
pll_clk = kzalloc(sizeof(*pll_clk), GFP_KERNEL);
129+
if (!pll_clk)
130+
return ERR_PTR(-ENOMEM);
131+
132+
init.name = name;
133+
init.ops = &cpg_pll_clk_ops;
134+
init.parent_names = &parent_name;
135+
init.num_parents = 1;
136+
137+
pll_clk->hw.init = &init;
138+
pll_clk->pllcr_reg = base + offset;
139+
pll_clk->pllecr_reg = base + CPG_PLLECR;
140+
pll_clk->fixed_mult = mult; /* PLL refclk x (setting + 1) x mult */
141+
pll_clk->pllecr_pllst_mask = CPG_PLLECR_PLLST(index);
142+
143+
clk = clk_register(NULL, &pll_clk->hw);
144+
if (IS_ERR(clk))
145+
kfree(pll_clk);
146+
147+
return clk;
148+
}
149+
35150
/*
36151
* Z Clock & Z2 Clock
37152
*
@@ -314,16 +429,13 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
314429

315430
case CLK_TYPE_GEN3_PLL0:
316431
/*
317-
* PLL0 is a configurable multiplier clock. Register it as a
318-
* fixed factor clock for now as there's no generic multiplier
319-
* clock implementation and we currently have no need to change
320-
* the multiplier value.
432+
* PLL0 is implemented as a custom clock, to change the
433+
* multiplier when cpufreq changes between normal and boost
434+
* modes.
321435
*/
322-
value = readl(base + CPG_PLL0CR);
323-
mult = (((value >> 24) & 0x7f) + 1) * 2;
324-
if (cpg_quirks & PLL_ERRATA)
325-
mult *= 2;
326-
break;
436+
mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
437+
return cpg_pll_clk_register(core->name, __clk_get_name(parent),
438+
base, mult, CPG_PLL0CR, 0);
327439

328440
case CLK_TYPE_GEN3_PLL1:
329441
mult = cpg_pll_config->pll1_mult;
@@ -332,16 +444,13 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev,
332444

333445
case CLK_TYPE_GEN3_PLL2:
334446
/*
335-
* PLL2 is a configurable multiplier clock. Register it as a
336-
* fixed factor clock for now as there's no generic multiplier
337-
* clock implementation and we currently have no need to change
338-
* the multiplier value.
447+
* PLL2 is implemented as a custom clock, to change the
448+
* multiplier when cpufreq changes between normal and boost
449+
* modes.
339450
*/
340-
value = readl(base + CPG_PLL2CR);
341-
mult = (((value >> 24) & 0x7f) + 1) * 2;
342-
if (cpg_quirks & PLL_ERRATA)
343-
mult *= 2;
344-
break;
451+
mult = (cpg_quirks & PLL_ERRATA) ? 4 : 2;
452+
return cpg_pll_clk_register(core->name, __clk_get_name(parent),
453+
base, mult, CPG_PLL2CR, 2);
345454

346455
case CLK_TYPE_GEN3_PLL3:
347456
mult = cpg_pll_config->pll3_mult;

0 commit comments

Comments
 (0)