xref: /linux/drivers/clk/renesas/r9a09g077-cpg.c (revision 522ba450b56fff29f868b1552bdc2965f55de7ed)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * r9a09g077 Clock Pulse Generator / Module Standby and Software Reset
4  *
5  * Copyright (C) 2025 Renesas Electronics Corp.
6  *
7  */
8 
9 #include <linux/bitfield.h>
10 #include <linux/clk-provider.h>
11 #include <linux/device.h>
12 #include <linux/init.h>
13 #include <linux/kernel.h>
14 
15 #include <dt-bindings/clock/renesas,r9a09g077-cpg-mssr.h>
16 #include <dt-bindings/clock/renesas,r9a09g087-cpg-mssr.h>
17 #include "renesas-cpg-mssr.h"
18 
19 #define RZT2H_REG_BLOCK_SHIFT	11
20 #define RZT2H_REG_OFFSET_MASK	GENMASK(10, 0)
21 #define RZT2H_REG_CONF(block, offset)	(((block) << RZT2H_REG_BLOCK_SHIFT) | \
22 					((offset) & RZT2H_REG_OFFSET_MASK))
23 
24 #define RZT2H_REG_BLOCK(x)		((x) >> RZT2H_REG_BLOCK_SHIFT)
25 #define RZT2H_REG_OFFSET(x)		((x) & RZT2H_REG_OFFSET_MASK)
26 
27 #define SCKCR		RZT2H_REG_CONF(0, 0x00)
28 #define SCKCR2		RZT2H_REG_CONF(1, 0x04)
29 #define SCKCR3		RZT2H_REG_CONF(0, 0x08)
30 
31 #define OFFSET_MASK	GENMASK(31, 20)
32 #define SHIFT_MASK	GENMASK(19, 12)
33 #define WIDTH_MASK	GENMASK(11, 8)
34 
35 #define CONF_PACK(offset, shift, width)  \
36 	(FIELD_PREP_CONST(OFFSET_MASK, (offset)) | \
37 	FIELD_PREP_CONST(SHIFT_MASK, (shift)) | \
38 	FIELD_PREP_CONST(WIDTH_MASK, (width)))
39 
40 #define GET_SHIFT(val)         FIELD_GET(SHIFT_MASK, val)
41 #define GET_WIDTH(val)         FIELD_GET(WIDTH_MASK, val)
42 #define GET_REG_OFFSET(val)    FIELD_GET(OFFSET_MASK, val)
43 
44 #define DIVCA55C0	CONF_PACK(SCKCR2, 8, 1)
45 #define DIVCA55C1	CONF_PACK(SCKCR2, 9, 1)
46 #define DIVCA55C2	CONF_PACK(SCKCR2, 10, 1)
47 #define DIVCA55C3	CONF_PACK(SCKCR2, 11, 1)
48 #define DIVCA55S	CONF_PACK(SCKCR2, 12, 1)
49 #define DIVSCI5ASYNC	CONF_PACK(SCKCR2, 18, 2)
50 
51 #define DIVSCI0ASYNC	CONF_PACK(SCKCR3, 6, 2)
52 #define DIVSCI1ASYNC	CONF_PACK(SCKCR3, 8, 2)
53 #define DIVSCI2ASYNC	CONF_PACK(SCKCR3, 10, 2)
54 #define DIVSCI3ASYNC	CONF_PACK(SCKCR3, 12, 2)
55 #define DIVSCI4ASYNC	CONF_PACK(SCKCR3, 14, 2)
56 
57 #define SEL_PLL		CONF_PACK(SCKCR, 22, 1)
58 
59 
60 enum rzt2h_clk_types {
61 	CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM,	/* Clock with divider */
62 	CLK_TYPE_RZT2H_MUX,			/* Clock with clock source selector */
63 };
64 
65 #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
66 	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \
67 		 .parent = _parent, .dtable = _dtable, .flag = 0)
68 #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \
69 	DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \
70 		 .parent_names = _parent_names, .num_parents = _num_parents, \
71 		 .flag = 0, .mux_flags = _mux_flags)
72 
73 enum clk_ids {
74 	/* Core Clock Outputs exported to DT */
75 	LAST_DT_CORE_CLK = R9A09G077_ETCLKE,
76 
77 	/* External Input Clocks */
78 	CLK_EXTAL,
79 
80 	/* Internal Core Clocks */
81 	CLK_LOCO,
82 	CLK_PLL0,
83 	CLK_PLL1,
84 	CLK_PLL2,
85 	CLK_PLL4,
86 	CLK_SEL_CLK_PLL0,
87 	CLK_SEL_CLK_PLL1,
88 	CLK_SEL_CLK_PLL2,
89 	CLK_SEL_CLK_PLL4,
90 	CLK_PLL4D1,
91 	CLK_SCI0ASYNC,
92 	CLK_SCI1ASYNC,
93 	CLK_SCI2ASYNC,
94 	CLK_SCI3ASYNC,
95 	CLK_SCI4ASYNC,
96 	CLK_SCI5ASYNC,
97 
98 	/* Module Clocks */
99 	MOD_CLK_BASE,
100 };
101 
102 static const struct clk_div_table dtable_1_2[] = {
103 	{0, 2},
104 	{1, 1},
105 	{0, 0},
106 };
107 
108 static const struct clk_div_table dtable_24_25_30_32[] = {
109 	{0, 32},
110 	{1, 30},
111 	{2, 25},
112 	{3, 24},
113 	{0, 0},
114 };
115 
116 /* Mux clock tables */
117 
118 static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
119 static const char * const sel_clk_pll1[] = { ".loco", ".pll1" };
120 static const char * const sel_clk_pll2[] = { ".loco", ".pll2" };
121 static const char * const sel_clk_pll4[] = { ".loco", ".pll4" };
122 
123 static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
124 	/* External Clock Inputs */
125 	DEF_INPUT("extal", CLK_EXTAL),
126 
127 	/* Internal Core Clocks */
128 	DEF_RATE(".loco", CLK_LOCO, 1000 * 1000),
129 	DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48),
130 	DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40),
131 	DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 1, 32),
132 	DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96),
133 
134 	DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL,
135 		sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY),
136 	DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL,
137 		sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY),
138 	DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL,
139 		sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY),
140 	DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL,
141 		sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY),
142 
143 	DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1),
144 	DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC,
145 		dtable_24_25_30_32),
146 	DEF_DIV(".sci1async", CLK_SCI1ASYNC, CLK_PLL4D1, DIVSCI1ASYNC,
147 		dtable_24_25_30_32),
148 	DEF_DIV(".sci2async", CLK_SCI2ASYNC, CLK_PLL4D1, DIVSCI2ASYNC,
149 		dtable_24_25_30_32),
150 	DEF_DIV(".sci3async", CLK_SCI3ASYNC, CLK_PLL4D1, DIVSCI3ASYNC,
151 		dtable_24_25_30_32),
152 	DEF_DIV(".sci4async", CLK_SCI4ASYNC, CLK_PLL4D1, DIVSCI4ASYNC,
153 		dtable_24_25_30_32),
154 	DEF_DIV(".sci5async", CLK_SCI5ASYNC, CLK_PLL4D1, DIVSCI5ASYNC,
155 		dtable_24_25_30_32),
156 
157 	/* Core output clk */
158 	DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0,
159 		dtable_1_2),
160 	DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1,
161 		dtable_1_2),
162 	DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2,
163 		dtable_1_2),
164 	DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3,
165 		dtable_1_2),
166 	DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S,
167 		dtable_1_2),
168 	DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1),
169 	DEF_FIXED("PCLKH", R9A09G077_CLK_PCLKH, CLK_SEL_CLK_PLL1, 4, 1),
170 	DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1),
171 	DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1),
172 	DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1),
173 	DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1),
174 	DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1),
175 	DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1),
176 	DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1),
177 	DEF_FIXED("ETCLKB", R9A09G077_ETCLKB, CLK_SEL_CLK_PLL1, 8, 1),
178 	DEF_FIXED("ETCLKC", R9A09G077_ETCLKC, CLK_SEL_CLK_PLL1, 10, 1),
179 	DEF_FIXED("ETCLKD", R9A09G077_ETCLKD, CLK_SEL_CLK_PLL1, 20, 1),
180 	DEF_FIXED("ETCLKE", R9A09G077_ETCLKE, CLK_SEL_CLK_PLL1, 40, 1),
181 };
182 
183 static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
184 	DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC),
185 	DEF_MOD("sci1fck", 9, CLK_SCI1ASYNC),
186 	DEF_MOD("sci2fck", 10, CLK_SCI2ASYNC),
187 	DEF_MOD("sci3fck", 11, CLK_SCI3ASYNC),
188 	DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC),
189 	DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL),
190 	DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL),
191 	DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM),
192 	DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM),
193 	DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM),
194 	DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM),
195 	DEF_MOD("gmac1", 416, R9A09G077_CLK_PCLKAM),
196 	DEF_MOD("gmac2", 417, R9A09G077_CLK_PCLKAM),
197 	DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC),
198 	DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL),
199 	DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM),
200 	DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM),
201 };
202 
203 static struct clk * __init
r9a09g077_cpg_div_clk_register(struct device * dev,const struct cpg_core_clk * core,void __iomem * addr,struct cpg_mssr_pub * pub)204 r9a09g077_cpg_div_clk_register(struct device *dev,
205 			       const struct cpg_core_clk *core,
206 			       void __iomem *addr, struct cpg_mssr_pub *pub)
207 {
208 	const struct clk *parent;
209 	const char *parent_name;
210 	struct clk_hw *clk_hw;
211 
212 	parent = pub->clks[core->parent];
213 	if (IS_ERR(parent))
214 		return ERR_CAST(parent);
215 
216 	parent_name = __clk_get_name(parent);
217 
218 	if (core->dtable)
219 		clk_hw = clk_hw_register_divider_table(dev, core->name,
220 						       parent_name, 0,
221 						       addr,
222 						       GET_SHIFT(core->conf),
223 						       GET_WIDTH(core->conf),
224 						       core->flag,
225 						       core->dtable,
226 						       &pub->rmw_lock);
227 	else
228 		clk_hw = clk_hw_register_divider(dev, core->name,
229 						 parent_name, 0,
230 						 addr,
231 						 GET_SHIFT(core->conf),
232 						 GET_WIDTH(core->conf),
233 						 core->flag, &pub->rmw_lock);
234 
235 	if (IS_ERR(clk_hw))
236 		return ERR_CAST(clk_hw);
237 
238 	return clk_hw->clk;
239 
240 }
241 
242 static struct clk * __init
r9a09g077_cpg_mux_clk_register(struct device * dev,const struct cpg_core_clk * core,void __iomem * addr,struct cpg_mssr_pub * pub)243 r9a09g077_cpg_mux_clk_register(struct device *dev,
244 			       const struct cpg_core_clk *core,
245 			       void __iomem *addr, struct cpg_mssr_pub *pub)
246 {
247 	struct clk_hw *clk_hw;
248 
249 	clk_hw = devm_clk_hw_register_mux(dev, core->name,
250 					  core->parent_names, core->num_parents,
251 					  core->flag,
252 					  addr,
253 					  GET_SHIFT(core->conf),
254 					  GET_WIDTH(core->conf),
255 					  core->mux_flags, &pub->rmw_lock);
256 	if (IS_ERR(clk_hw))
257 		return ERR_CAST(clk_hw);
258 
259 	return clk_hw->clk;
260 }
261 
262 static struct clk * __init
r9a09g077_cpg_clk_register(struct device * dev,const struct cpg_core_clk * core,const struct cpg_mssr_info * info,struct cpg_mssr_pub * pub)263 r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
264 			   const struct cpg_mssr_info *info,
265 			   struct cpg_mssr_pub *pub)
266 {
267 	u32 offset = GET_REG_OFFSET(core->conf);
268 	void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0;
269 	void __iomem *addr = base + RZT2H_REG_OFFSET(offset);
270 
271 	switch (core->type) {
272 	case CLK_TYPE_RZT2H_DIV:
273 		return r9a09g077_cpg_div_clk_register(dev, core, addr, pub);
274 	case CLK_TYPE_RZT2H_MUX:
275 		return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub);
276 	default:
277 		return ERR_PTR(-EINVAL);
278 	}
279 }
280 
281 const struct cpg_mssr_info r9a09g077_cpg_mssr_info = {
282 	/* Core Clocks */
283 	.core_clks = r9a09g077_core_clks,
284 	.num_core_clks = ARRAY_SIZE(r9a09g077_core_clks),
285 	.last_dt_core_clk = LAST_DT_CORE_CLK,
286 	.num_total_core_clks = MOD_CLK_BASE,
287 
288 	/* Module Clocks */
289 	.mod_clks = r9a09g077_mod_clks,
290 	.num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks),
291 	.num_hw_mod_clks = 14 * 32,
292 
293 	.reg_layout = CLK_REG_LAYOUT_RZ_T2H,
294 	.cpg_clk_register = r9a09g077_cpg_clk_register,
295 };
296