xref: /linux/drivers/clk/renesas/r9a09g077-cpg.c (revision 065fe720eec6e627afa24da387ff970afd9a8dcb)
1*065fe720SThierry Bultel // SPDX-License-Identifier: GPL-2.0
2*065fe720SThierry Bultel /*
3*065fe720SThierry Bultel  * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset
4*065fe720SThierry Bultel  *
5*065fe720SThierry Bultel  * Copyright (C) 2025 Renesas Electronics Corp.
6*065fe720SThierry Bultel  *
7*065fe720SThierry Bultel  */
8*065fe720SThierry Bultel 
9*065fe720SThierry Bultel #include <linux/bitfield.h>
10*065fe720SThierry Bultel #include <linux/clk-provider.h>
11*065fe720SThierry Bultel #include <linux/device.h>
12*065fe720SThierry Bultel #include <linux/init.h>
13*065fe720SThierry Bultel #include <linux/kernel.h>
14*065fe720SThierry Bultel 
15*065fe720SThierry Bultel #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
16*065fe720SThierry Bultel #include "renesas-cpg-mssr.h"
17*065fe720SThierry Bultel 
18*065fe720SThierry Bultel #define RZT2H_REG_BLOCK_SHIFT	11
19*065fe720SThierry Bultel #define RZT2H_REG_OFFSET_MASK	GENMASK(10, 0)
20*065fe720SThierry Bultel #define RZT2H_REG_CONF(block, offset)	(((block) << RZT2H_REG_BLOCK_SHIFT) | \
21*065fe720SThierry Bultel 					((offset) & RZT2H_REG_OFFSET_MASK))
22*065fe720SThierry Bultel 
23*065fe720SThierry Bultel #define RZT2H_REG_BLOCK(x)		((x) >> RZT2H_REG_BLOCK_SHIFT)
24*065fe720SThierry Bultel #define RZT2H_REG_OFFSET(x)		((x) & RZT2H_REG_OFFSET_MASK)
25*065fe720SThierry Bultel 
26*065fe720SThierry Bultel #define SCKCR		RZT2H_REG_CONF(0, 0x00)
27*065fe720SThierry Bultel #define SCKCR2		RZT2H_REG_CONF(1, 0x04)
28*065fe720SThierry Bultel #define SCKCR3		RZT2H_REG_CONF(0, 0x08)
29*065fe720SThierry Bultel 
30*065fe720SThierry Bultel #define OFFSET_MASK	GENMASK(31, 20)
31*065fe720SThierry Bultel #define SHIFT_MASK	GENMASK(19, 12)
32*065fe720SThierry Bultel #define WIDTH_MASK	GENMASK(11, 8)
33*065fe720SThierry Bultel 
34*065fe720SThierry Bultel #define CONF_PACK(offset, shift, width)  \
35*065fe720SThierry Bultel 	(FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \
36*065fe720SThierry Bultel 	FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \
37*065fe720SThierry Bultel 	FIELD_PREP_CONST(WIDTH_MASK, (width)))
38*065fe720SThierry Bultel 
39*065fe720SThierry Bultel #define GET_SHIFT(val)         FIELD_GET(SHIFT_MASK, val)
40*065fe720SThierry Bultel #define GET_WIDTH(val)         FIELD_GET(WIDTH_MASK, val)
41*065fe720SThierry Bultel #define GET_REG_OFFSET(val)    FIELD_GET(OFFSET_MASK, val)
42*065fe720SThierry Bultel 
43*065fe720SThierry Bultel #define DIVCA55C0	CONF_PACK(SCKCR2, 8, 1)
44*065fe720SThierry Bultel #define DIVCA55C1	CONF_PACK(SCKCR2, 9, 1)
45*065fe720SThierry Bultel #define DIVCA55C2	CONF_PACK(SCKCR2, 10, 1)
46*065fe720SThierry Bultel #define DIVCA55C3	CONF_PACK(SCKCR2, 11, 1)
47*065fe720SThierry Bultel #define DIVCA55S	CONF_PACK(SCKCR2, 12, 1)
48*065fe720SThierry Bultel 
49*065fe720SThierry Bultel #define DIVSCI0ASYNC	CONF_PACK(SCKCR3, 6, 2)
50*065fe720SThierry Bultel 
51*065fe720SThierry Bultel #define SEL_PLL		CONF_PACK(SCKCR, 22, 1)
52*065fe720SThierry Bultel 
53*065fe720SThierry Bultel 
54*065fe720SThierry Bultel enum rzt2h_clk_types {
55*065fe720SThierry Bultel 	CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM,	/* Clock with divider */
56*065fe720SThierry Bultel 	CLK_TYPE_RZT2H_MUX,			/* Clock with clock source selector */
57*065fe720SThierry Bultel };
58*065fe720SThierry Bultel 
59*065fe720SThierry Bultel #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
60*065fe720SThierry Bultel 	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \
61*065fe720SThierry Bultel 		 .parent = _parent, .dtable = _dtable, .flag = 0)
62*065fe720SThierry Bultel #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \
63*065fe720SThierry Bultel 	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \
64*065fe720SThierry Bultel 		 .parent_names = _parent_names, .num_parents = _num_parents, \
65*065fe720SThierry Bultel 		 .flag = 0, .mux_flags = _mux_flags)
66*065fe720SThierry Bultel 
67*065fe720SThierry Bultel enum clk_ids {
68*065fe720SThierry Bultel 	/* Core Clock Outputs exported to DT */
69*065fe720SThierry Bultel 	LAST_DT_CORE_CLK = R9A09G077_CLK_PCLKM,
70*065fe720SThierry Bultel 
71*065fe720SThierry Bultel 	/* External Input Clocks */
72*065fe720SThierry Bultel 	CLK_EXTAL,
73*065fe720SThierry Bultel 
74*065fe720SThierry Bultel 	/* Internal Core Clocks */
75*065fe720SThierry Bultel 	CLK_LOCO,
76*065fe720SThierry Bultel 	CLK_PLL0,
77*065fe720SThierry Bultel 	CLK_PLL1,
78*065fe720SThierry Bultel 	CLK_PLL4,
79*065fe720SThierry Bultel 	CLK_SEL_CLK_PLL0,
80*065fe720SThierry Bultel 	CLK_SEL_CLK_PLL1,
81*065fe720SThierry Bultel 	CLK_SEL_CLK_PLL4,
82*065fe720SThierry Bultel 	CLK_PLL4D1,
83*065fe720SThierry Bultel 	CLK_SCI0ASYNC,
84*065fe720SThierry Bultel 
85*065fe720SThierry Bultel 	/* Module Clocks */
86*065fe720SThierry Bultel 	MOD_CLK_BASE,
87*065fe720SThierry Bultel };
88*065fe720SThierry Bultel 
89*065fe720SThierry Bultel static const struct clk_div_table dtable_1_2[] = {
90*065fe720SThierry Bultel 	{0, 2},
91*065fe720SThierry Bultel 	{1, 1},
92*065fe720SThierry Bultel 	{0, 0},
93*065fe720SThierry Bultel };
94*065fe720SThierry Bultel 
95*065fe720SThierry Bultel static const struct clk_div_table dtable_24_25_30_32[] = {
96*065fe720SThierry Bultel 	{0, 32},
97*065fe720SThierry Bultel 	{1, 30},
98*065fe720SThierry Bultel 	{2, 25},
99*065fe720SThierry Bultel 	{3, 24},
100*065fe720SThierry Bultel 	{0, 0},
101*065fe720SThierry Bultel };
102*065fe720SThierry Bultel 
103*065fe720SThierry Bultel /* Mux clock tables */
104*065fe720SThierry Bultel 
105*065fe720SThierry Bultel static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
106*065fe720SThierry Bultel static const char * const sel_clk_pll1[] = { ".loco", ".pll1" };
107*065fe720SThierry Bultel static const char * const sel_clk_pll4[] = { ".loco", ".pll4" };
108*065fe720SThierry Bultel 
109*065fe720SThierry Bultel static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
110*065fe720SThierry Bultel 	/* External Clock Inputs */
111*065fe720SThierry Bultel 	DEF_INPUT("extal", CLK_EXTAL),
112*065fe720SThierry Bultel 
113*065fe720SThierry Bultel 	/* Internal Core Clocks */
114*065fe720SThierry Bultel 	DEF_RATE(".loco", CLK_LOCO, 1000 * 1000),
115*065fe720SThierry Bultel 	DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48),
116*065fe720SThierry Bultel 	DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40),
117*065fe720SThierry Bultel 	DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96),
118*065fe720SThierry Bultel 
119*065fe720SThierry Bultel 	DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL,
120*065fe720SThierry Bultel 		sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY),
121*065fe720SThierry Bultel 	DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL,
122*065fe720SThierry Bultel 		sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY),
123*065fe720SThierry Bultel 	DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL,
124*065fe720SThierry Bultel 		sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY),
125*065fe720SThierry Bultel 
126*065fe720SThierry Bultel 	DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1),
127*065fe720SThierry Bultel 	DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC,
128*065fe720SThierry Bultel 		dtable_24_25_30_32),
129*065fe720SThierry Bultel 
130*065fe720SThierry Bultel 	/* Core output clk */
131*065fe720SThierry Bultel 	DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0,
132*065fe720SThierry Bultel 		dtable_1_2),
133*065fe720SThierry Bultel 	DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1,
134*065fe720SThierry Bultel 		dtable_1_2),
135*065fe720SThierry Bultel 	DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2,
136*065fe720SThierry Bultel 		dtable_1_2),
137*065fe720SThierry Bultel 	DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3,
138*065fe720SThierry Bultel 		dtable_1_2),
139*065fe720SThierry Bultel 	DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S,
140*065fe720SThierry Bultel 		dtable_1_2),
141*065fe720SThierry Bultel 	DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1),
142*065fe720SThierry Bultel 	DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1),
143*065fe720SThierry Bultel };
144*065fe720SThierry Bultel 
145*065fe720SThierry Bultel static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
146*065fe720SThierry Bultel 	DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC),
147*065fe720SThierry Bultel };
148*065fe720SThierry Bultel 
149*065fe720SThierry Bultel static struct clk * __init
150*065fe720SThierry Bultel r9a09g077_cpg_div_clk_register(struct device *dev,
151*065fe720SThierry Bultel 			       const struct cpg_core_clk *core,
152*065fe720SThierry Bultel 			       void __iomem *addr, struct cpg_mssr_pub *pub)
153*065fe720SThierry Bultel {
154*065fe720SThierry Bultel 	const struct clk *parent;
155*065fe720SThierry Bultel 	const char *parent_name;
156*065fe720SThierry Bultel 	struct clk_hw *clk_hw;
157*065fe720SThierry Bultel 
158*065fe720SThierry Bultel 	parent = pub->clks[core->parent];
159*065fe720SThierry Bultel 	if (IS_ERR(parent))
160*065fe720SThierry Bultel 		return ERR_CAST(parent);
161*065fe720SThierry Bultel 
162*065fe720SThierry Bultel 	parent_name = __clk_get_name(parent);
163*065fe720SThierry Bultel 
164*065fe720SThierry Bultel 	if (core->dtable)
165*065fe720SThierry Bultel 		clk_hw = clk_hw_register_divider_table(dev, core->name,
166*065fe720SThierry Bultel 						       parent_name, 0,
167*065fe720SThierry Bultel 						       addr,
168*065fe720SThierry Bultel 						       GET_SHIFT(core->conf),
169*065fe720SThierry Bultel 						       GET_WIDTH(core->conf),
170*065fe720SThierry Bultel 						       core->flag,
171*065fe720SThierry Bultel 						       core->dtable,
172*065fe720SThierry Bultel 						       &pub->rmw_lock);
173*065fe720SThierry Bultel 	else
174*065fe720SThierry Bultel 		clk_hw = clk_hw_register_divider(dev, core->name,
175*065fe720SThierry Bultel 						 parent_name, 0,
176*065fe720SThierry Bultel 						 addr,
177*065fe720SThierry Bultel 						 GET_SHIFT(core->conf),
178*065fe720SThierry Bultel 						 GET_WIDTH(core->conf),
179*065fe720SThierry Bultel 						 core->flag, &pub->rmw_lock);
180*065fe720SThierry Bultel 
181*065fe720SThierry Bultel 	if (IS_ERR(clk_hw))
182*065fe720SThierry Bultel 		return ERR_CAST(clk_hw);
183*065fe720SThierry Bultel 
184*065fe720SThierry Bultel 	return clk_hw->clk;
185*065fe720SThierry Bultel 
186*065fe720SThierry Bultel }
187*065fe720SThierry Bultel 
188*065fe720SThierry Bultel static struct clk * __init
189*065fe720SThierry Bultel r9a09g077_cpg_mux_clk_register(struct device *dev,
190*065fe720SThierry Bultel 			       const struct cpg_core_clk *core,
191*065fe720SThierry Bultel 			       void __iomem *addr, struct cpg_mssr_pub *pub)
192*065fe720SThierry Bultel {
193*065fe720SThierry Bultel 	struct clk_hw *clk_hw;
194*065fe720SThierry Bultel 
195*065fe720SThierry Bultel 	clk_hw = devm_clk_hw_register_mux(dev, core->name,
196*065fe720SThierry Bultel 					  core->parent_names, core->num_parents,
197*065fe720SThierry Bultel 					  core->flag,
198*065fe720SThierry Bultel 					  addr,
199*065fe720SThierry Bultel 					  GET_SHIFT(core->conf),
200*065fe720SThierry Bultel 					  GET_WIDTH(core->conf),
201*065fe720SThierry Bultel 					  core->mux_flags, &pub->rmw_lock);
202*065fe720SThierry Bultel 	if (IS_ERR(clk_hw))
203*065fe720SThierry Bultel 		return ERR_CAST(clk_hw);
204*065fe720SThierry Bultel 
205*065fe720SThierry Bultel 	return clk_hw->clk;
206*065fe720SThierry Bultel }
207*065fe720SThierry Bultel 
208*065fe720SThierry Bultel static struct clk * __init
209*065fe720SThierry Bultel r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
210*065fe720SThierry Bultel 			   const struct cpg_mssr_info *info,
211*065fe720SThierry Bultel 			   struct cpg_mssr_pub *pub)
212*065fe720SThierry Bultel {
213*065fe720SThierry Bultel 	u32 offset = GET_REG_OFFSET(core->conf);
214*065fe720SThierry Bultel 	void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0;
215*065fe720SThierry Bultel 	void __iomem *addr = base + RZT2H_REG_OFFSET(offset);
216*065fe720SThierry Bultel 
217*065fe720SThierry Bultel 	switch (core->type) {
218*065fe720SThierry Bultel 	case CLK_TYPE_RZT2H_DIV:
219*065fe720SThierry Bultel 		return r9a09g077_cpg_div_clk_register(dev, core, addr, pub);
220*065fe720SThierry Bultel 	case CLK_TYPE_RZT2H_MUX:
221*065fe720SThierry Bultel 		return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub);
222*065fe720SThierry Bultel 	default:
223*065fe720SThierry Bultel 		return ERR_PTR(-EINVAL);
224*065fe720SThierry Bultel 	}
225*065fe720SThierry Bultel }
226*065fe720SThierry Bultel 
227*065fe720SThierry Bultel const struct cpg_mssr_info r9a09g077_cpg_mssr_info = {
228*065fe720SThierry Bultel 	/* Core Clocks */
229*065fe720SThierry Bultel 	.core_clks = r9a09g077_core_clks,
230*065fe720SThierry Bultel 	.num_core_clks = ARRAY_SIZE(r9a09g077_core_clks),
231*065fe720SThierry Bultel 	.last_dt_core_clk = LAST_DT_CORE_CLK,
232*065fe720SThierry Bultel 	.num_total_core_clks = MOD_CLK_BASE,
233*065fe720SThierry Bultel 
234*065fe720SThierry Bultel 	/* Module Clocks */
235*065fe720SThierry Bultel 	.mod_clks = r9a09g077_mod_clks,
236*065fe720SThierry Bultel 	.num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks),
237*065fe720SThierry Bultel 	.num_hw_mod_clks = 14 * 32,
238*065fe720SThierry Bultel 
239*065fe720SThierry Bultel 	.reg_layout = CLK_REG_LAYOUT_RZ_T2H,
240*065fe720SThierry Bultel 	.cpg_clk_register = r9a09g077_cpg_clk_register,
241*065fe720SThierry Bultel };
242