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 DIVSPI3ASYNC CONF_PACK(SCKCR2, 16, 2)
50 #define DIVSCI5ASYNC CONF_PACK(SCKCR2, 18, 2)
51
52 #define DIVSPI0ASYNC CONF_PACK(SCKCR3, 0, 2)
53 #define DIVSPI1ASYNC CONF_PACK(SCKCR3, 2, 2)
54 #define DIVSPI2ASYNC CONF_PACK(SCKCR3, 4, 2)
55 #define DIVSCI0ASYNC CONF_PACK(SCKCR3, 6, 2)
56 #define DIVSCI1ASYNC CONF_PACK(SCKCR3, 8, 2)
57 #define DIVSCI2ASYNC CONF_PACK(SCKCR3, 10, 2)
58 #define DIVSCI3ASYNC CONF_PACK(SCKCR3, 12, 2)
59 #define DIVSCI4ASYNC CONF_PACK(SCKCR3, 14, 2)
60
61 #define SEL_PLL CONF_PACK(SCKCR, 22, 1)
62
63 enum rzt2h_clk_types {
64 CLK_TYPE_RZT2H_DIV = CLK_TYPE_CUSTOM, /* Clock with divider */
65 CLK_TYPE_RZT2H_MUX, /* Clock with clock source selector */
66 };
67
68 #define DEF_DIV(_name, _id, _parent, _conf, _dtable) \
69 DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_DIV, .conf = _conf, \
70 .parent = _parent, .dtable = _dtable, .flag = 0)
71 #define DEF_MUX(_name, _id, _conf, _parent_names, _num_parents, _mux_flags) \
72 DEF_TYPE(_name, _id, CLK_TYPE_RZT2H_MUX, .conf = _conf, \
73 .parent_names = _parent_names, .num_parents = _num_parents, \
74 .flag = 0, .mux_flags = _mux_flags)
75
76 enum clk_ids {
77 /* Core Clock Outputs exported to DT */
78 LAST_DT_CORE_CLK = R9A09G077_ETCLKE,
79
80 /* External Input Clocks */
81 CLK_EXTAL,
82
83 /* Internal Core Clocks */
84 CLK_LOCO,
85 CLK_PLL0,
86 CLK_PLL1,
87 CLK_PLL2,
88 CLK_PLL4,
89 CLK_SEL_CLK_PLL0,
90 CLK_SEL_CLK_PLL1,
91 CLK_SEL_CLK_PLL2,
92 CLK_SEL_CLK_PLL4,
93 CLK_PLL4D1,
94 CLK_SCI0ASYNC,
95 CLK_SCI1ASYNC,
96 CLK_SCI2ASYNC,
97 CLK_SCI3ASYNC,
98 CLK_SCI4ASYNC,
99 CLK_SCI5ASYNC,
100 CLK_SPI0ASYNC,
101 CLK_SPI1ASYNC,
102 CLK_SPI2ASYNC,
103 CLK_SPI3ASYNC,
104
105 /* Module Clocks */
106 MOD_CLK_BASE,
107 };
108
109 static const struct clk_div_table dtable_1_2[] = {
110 {0, 2},
111 {1, 1},
112 {0, 0},
113 };
114
115 static const struct clk_div_table dtable_24_25_30_32[] = {
116 {0, 32},
117 {1, 30},
118 {2, 25},
119 {3, 24},
120 {0, 0},
121 };
122
123 /* Mux clock tables */
124
125 static const char * const sel_clk_pll0[] = { ".loco", ".pll0" };
126 static const char * const sel_clk_pll1[] = { ".loco", ".pll1" };
127 static const char * const sel_clk_pll2[] = { ".loco", ".pll2" };
128 static const char * const sel_clk_pll4[] = { ".loco", ".pll4" };
129
130 static const struct cpg_core_clk r9a09g077_core_clks[] __initconst = {
131 /* External Clock Inputs */
132 DEF_INPUT("extal", CLK_EXTAL),
133
134 /* Internal Core Clocks */
135 DEF_RATE(".loco", CLK_LOCO, 1000 * 1000),
136 DEF_FIXED(".pll0", CLK_PLL0, CLK_EXTAL, 1, 48),
137 DEF_FIXED(".pll1", CLK_PLL1, CLK_EXTAL, 1, 40),
138 DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 1, 32),
139 DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 1, 96),
140
141 DEF_MUX(".sel_clk_pll0", CLK_SEL_CLK_PLL0, SEL_PLL,
142 sel_clk_pll0, ARRAY_SIZE(sel_clk_pll0), CLK_MUX_READ_ONLY),
143 DEF_MUX(".sel_clk_pll1", CLK_SEL_CLK_PLL1, SEL_PLL,
144 sel_clk_pll1, ARRAY_SIZE(sel_clk_pll1), CLK_MUX_READ_ONLY),
145 DEF_MUX(".sel_clk_pll2", CLK_SEL_CLK_PLL2, SEL_PLL,
146 sel_clk_pll2, ARRAY_SIZE(sel_clk_pll2), CLK_MUX_READ_ONLY),
147 DEF_MUX(".sel_clk_pll4", CLK_SEL_CLK_PLL4, SEL_PLL,
148 sel_clk_pll4, ARRAY_SIZE(sel_clk_pll4), CLK_MUX_READ_ONLY),
149
150 DEF_FIXED(".pll4d1", CLK_PLL4D1, CLK_SEL_CLK_PLL4, 1, 1),
151 DEF_DIV(".sci0async", CLK_SCI0ASYNC, CLK_PLL4D1, DIVSCI0ASYNC,
152 dtable_24_25_30_32),
153 DEF_DIV(".sci1async", CLK_SCI1ASYNC, CLK_PLL4D1, DIVSCI1ASYNC,
154 dtable_24_25_30_32),
155 DEF_DIV(".sci2async", CLK_SCI2ASYNC, CLK_PLL4D1, DIVSCI2ASYNC,
156 dtable_24_25_30_32),
157 DEF_DIV(".sci3async", CLK_SCI3ASYNC, CLK_PLL4D1, DIVSCI3ASYNC,
158 dtable_24_25_30_32),
159 DEF_DIV(".sci4async", CLK_SCI4ASYNC, CLK_PLL4D1, DIVSCI4ASYNC,
160 dtable_24_25_30_32),
161 DEF_DIV(".sci5async", CLK_SCI5ASYNC, CLK_PLL4D1, DIVSCI5ASYNC,
162 dtable_24_25_30_32),
163
164 DEF_DIV(".spi0async", CLK_SPI0ASYNC, CLK_PLL4D1, DIVSPI0ASYNC,
165 dtable_24_25_30_32),
166 DEF_DIV(".spi1async", CLK_SPI1ASYNC, CLK_PLL4D1, DIVSPI1ASYNC,
167 dtable_24_25_30_32),
168 DEF_DIV(".spi2async", CLK_SPI2ASYNC, CLK_PLL4D1, DIVSPI2ASYNC,
169 dtable_24_25_30_32),
170 DEF_DIV(".spi3async", CLK_SPI3ASYNC, CLK_PLL4D1, DIVSPI3ASYNC,
171 dtable_24_25_30_32),
172
173 /* Core output clk */
174 DEF_DIV("CA55C0", R9A09G077_CLK_CA55C0, CLK_SEL_CLK_PLL0, DIVCA55C0,
175 dtable_1_2),
176 DEF_DIV("CA55C1", R9A09G077_CLK_CA55C1, CLK_SEL_CLK_PLL0, DIVCA55C1,
177 dtable_1_2),
178 DEF_DIV("CA55C2", R9A09G077_CLK_CA55C2, CLK_SEL_CLK_PLL0, DIVCA55C2,
179 dtable_1_2),
180 DEF_DIV("CA55C3", R9A09G077_CLK_CA55C3, CLK_SEL_CLK_PLL0, DIVCA55C3,
181 dtable_1_2),
182 DEF_DIV("CA55S", R9A09G077_CLK_CA55S, CLK_SEL_CLK_PLL0, DIVCA55S,
183 dtable_1_2),
184 DEF_FIXED("PCLKGPTL", R9A09G077_CLK_PCLKGPTL, CLK_SEL_CLK_PLL1, 2, 1),
185 DEF_FIXED("PCLKH", R9A09G077_CLK_PCLKH, CLK_SEL_CLK_PLL1, 4, 1),
186 DEF_FIXED("PCLKM", R9A09G077_CLK_PCLKM, CLK_SEL_CLK_PLL1, 8, 1),
187 DEF_FIXED("PCLKL", R9A09G077_CLK_PCLKL, CLK_SEL_CLK_PLL1, 16, 1),
188 DEF_FIXED("PCLKAH", R9A09G077_CLK_PCLKAH, CLK_PLL4D1, 6, 1),
189 DEF_FIXED("PCLKAM", R9A09G077_CLK_PCLKAM, CLK_PLL4D1, 12, 1),
190 DEF_FIXED("SDHI_CLKHS", R9A09G077_SDHI_CLKHS, CLK_SEL_CLK_PLL2, 1, 1),
191 DEF_FIXED("USB_CLK", R9A09G077_USB_CLK, CLK_PLL4D1, 48, 1),
192 DEF_FIXED("ETCLKA", R9A09G077_ETCLKA, CLK_SEL_CLK_PLL1, 5, 1),
193 DEF_FIXED("ETCLKB", R9A09G077_ETCLKB, CLK_SEL_CLK_PLL1, 8, 1),
194 DEF_FIXED("ETCLKC", R9A09G077_ETCLKC, CLK_SEL_CLK_PLL1, 10, 1),
195 DEF_FIXED("ETCLKD", R9A09G077_ETCLKD, CLK_SEL_CLK_PLL1, 20, 1),
196 DEF_FIXED("ETCLKE", R9A09G077_ETCLKE, CLK_SEL_CLK_PLL1, 40, 1),
197 };
198
199 static const struct mssr_mod_clk r9a09g077_mod_clks[] __initconst = {
200 DEF_MOD("sci0fck", 8, CLK_SCI0ASYNC),
201 DEF_MOD("sci1fck", 9, CLK_SCI1ASYNC),
202 DEF_MOD("sci2fck", 10, CLK_SCI2ASYNC),
203 DEF_MOD("sci3fck", 11, CLK_SCI3ASYNC),
204 DEF_MOD("sci4fck", 12, CLK_SCI4ASYNC),
205 DEF_MOD("iic0", 100, R9A09G077_CLK_PCLKL),
206 DEF_MOD("iic1", 101, R9A09G077_CLK_PCLKL),
207 DEF_MOD("spi0", 104, CLK_SPI0ASYNC),
208 DEF_MOD("spi1", 105, CLK_SPI1ASYNC),
209 DEF_MOD("spi2", 106, CLK_SPI2ASYNC),
210 DEF_MOD("adc0", 206, R9A09G077_CLK_PCLKH),
211 DEF_MOD("adc1", 207, R9A09G077_CLK_PCLKH),
212 DEF_MOD("adc2", 225, R9A09G077_CLK_PCLKM),
213 DEF_MOD("tsu", 307, R9A09G077_CLK_PCLKL),
214 DEF_MOD("gmac0", 400, R9A09G077_CLK_PCLKM),
215 DEF_MOD("ethsw", 401, R9A09G077_CLK_PCLKM),
216 DEF_MOD("ethss", 403, R9A09G077_CLK_PCLKM),
217 DEF_MOD("usb", 408, R9A09G077_CLK_PCLKAM),
218 DEF_MOD("gmac1", 416, R9A09G077_CLK_PCLKAM),
219 DEF_MOD("gmac2", 417, R9A09G077_CLK_PCLKAM),
220 DEF_MOD("sci5fck", 600, CLK_SCI5ASYNC),
221 DEF_MOD("iic2", 601, R9A09G077_CLK_PCLKL),
222 DEF_MOD("spi3", 602, CLK_SPI3ASYNC),
223 DEF_MOD("sdhi0", 1212, R9A09G077_CLK_PCLKAM),
224 DEF_MOD("sdhi1", 1213, R9A09G077_CLK_PCLKAM),
225 };
226
227 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)228 r9a09g077_cpg_div_clk_register(struct device *dev,
229 const struct cpg_core_clk *core,
230 void __iomem *addr, struct cpg_mssr_pub *pub)
231 {
232 const struct clk *parent;
233 const char *parent_name;
234 struct clk_hw *clk_hw;
235
236 parent = pub->clks[core->parent];
237 if (IS_ERR(parent))
238 return ERR_CAST(parent);
239
240 parent_name = __clk_get_name(parent);
241
242 if (core->dtable)
243 clk_hw = devm_clk_hw_register_divider_table(dev, core->name,
244 parent_name,
245 CLK_SET_RATE_PARENT,
246 addr,
247 GET_SHIFT(core->conf),
248 GET_WIDTH(core->conf),
249 core->flag,
250 core->dtable,
251 &pub->rmw_lock);
252 else
253 clk_hw = devm_clk_hw_register_divider(dev, core->name,
254 parent_name,
255 CLK_SET_RATE_PARENT,
256 addr,
257 GET_SHIFT(core->conf),
258 GET_WIDTH(core->conf),
259 core->flag, &pub->rmw_lock);
260
261 if (IS_ERR(clk_hw))
262 return ERR_CAST(clk_hw);
263
264 return clk_hw->clk;
265 }
266
267 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)268 r9a09g077_cpg_mux_clk_register(struct device *dev,
269 const struct cpg_core_clk *core,
270 void __iomem *addr, struct cpg_mssr_pub *pub)
271 {
272 struct clk_hw *clk_hw;
273
274 clk_hw = devm_clk_hw_register_mux(dev, core->name,
275 core->parent_names, core->num_parents,
276 core->flag,
277 addr,
278 GET_SHIFT(core->conf),
279 GET_WIDTH(core->conf),
280 core->mux_flags, &pub->rmw_lock);
281 if (IS_ERR(clk_hw))
282 return ERR_CAST(clk_hw);
283
284 return clk_hw->clk;
285 }
286
287 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)288 r9a09g077_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core,
289 const struct cpg_mssr_info *info,
290 struct cpg_mssr_pub *pub)
291 {
292 u32 offset = GET_REG_OFFSET(core->conf);
293 void __iomem *base = RZT2H_REG_BLOCK(offset) ? pub->base1 : pub->base0;
294 void __iomem *addr = base + RZT2H_REG_OFFSET(offset);
295
296 switch (core->type) {
297 case CLK_TYPE_RZT2H_DIV:
298 return r9a09g077_cpg_div_clk_register(dev, core, addr, pub);
299 case CLK_TYPE_RZT2H_MUX:
300 return r9a09g077_cpg_mux_clk_register(dev, core, addr, pub);
301 default:
302 return ERR_PTR(-EINVAL);
303 }
304 }
305
306 const struct cpg_mssr_info r9a09g077_cpg_mssr_info = {
307 /* Core Clocks */
308 .core_clks = r9a09g077_core_clks,
309 .num_core_clks = ARRAY_SIZE(r9a09g077_core_clks),
310 .last_dt_core_clk = LAST_DT_CORE_CLK,
311 .num_total_core_clks = MOD_CLK_BASE,
312
313 /* Module Clocks */
314 .mod_clks = r9a09g077_mod_clks,
315 .num_mod_clks = ARRAY_SIZE(r9a09g077_mod_clks),
316 .num_hw_mod_clks = 14 * 32,
317
318 .reg_layout = CLK_REG_LAYOUT_RZ_T2H,
319 .cpg_clk_register = r9a09g077_cpg_clk_register,
320 };
321