1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2023 Rockchip Electronics Co., Ltd
4 * Author: Finley Xiao <finley.xiao@rock-chips.com>
5 */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <syscon.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/cru_rk3506.h>
13 #include <asm/arch/grf_rk3506.h>
14 #include <asm/arch/hardware.h>
15 #include <asm/io.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rockchip,rk3506-cru.h>
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 #define RK3506_CRU_BASE 0xFF9A0000
22 #define RK3506_SCRU_BASE 0xFF9A8000
23
24 #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
25
26 /*
27 * [FRAC PLL]: GPLL, V0PLL, V1PLL
28 * - VCO Frequency: 950MHz to 3800MHZ
29 * - Output Frequency: 19MHz to 3800MHZ
30 * - refdiv: 1 to 63 (Int Mode), 1 to 2 (Frac Mode)
31 * - fbdiv: 16 to 3800 (Int Mode), 20 to 380 (Frac Mode)
32 * - post1div: 1 to 7
33 * - post2div: 1 to 7
34 */
35 static struct rockchip_pll_rate_table rk3506_pll_rates[] = {
36 /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
37 RK3036_PLL_RATE(1896000000, 1, 79, 1, 1, 1, 0),
38 RK3036_PLL_RATE(1800000000, 1, 75, 1, 1, 1, 0),
39 RK3036_PLL_RATE(1704000000, 1, 71, 1, 1, 1, 0),
40 RK3036_PLL_RATE(1608000000, 1, 67, 1, 1, 1, 0),
41 RK3036_PLL_RATE(1512000000, 1, 63, 1, 1, 1, 0),
42 RK3036_PLL_RATE(1416000000, 1, 59, 1, 1, 1, 0),
43 RK3036_PLL_RATE(1350000000, 4, 225, 1, 1, 1, 0),
44 RK3036_PLL_RATE(1296000000, 1, 54, 1, 1, 1, 0),
45 RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
46 RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
47 RK3036_PLL_RATE(1179648000, 1, 49, 1, 1, 0, 2550137),
48 RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
49 RK3036_PLL_RATE(1000000000, 3, 125, 1, 1, 1, 0),
50 RK3036_PLL_RATE(993484800, 1, 41, 1, 1, 0, 6630355),
51 RK3036_PLL_RATE(983040000, 1, 40, 1, 1, 0, 16106127),
52 RK3036_PLL_RATE(960000000, 1, 80, 2, 1, 1, 0),
53 RK3036_PLL_RATE(912000000, 1, 76, 2, 1, 1, 0),
54 RK3036_PLL_RATE(903168000, 1, 75, 2, 1, 0, 4429185),
55 RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
56 RK3036_PLL_RATE(800000000, 3, 200, 2, 1, 1, 0),
57 RK3036_PLL_RATE(600000000, 1, 50, 2, 1, 1, 0),
58 RK3036_PLL_RATE(594000000, 2, 99, 2, 1, 1, 0),
59 RK3036_PLL_RATE(408000000, 1, 68, 2, 2, 1, 0),
60 RK3036_PLL_RATE(312000000, 1, 78, 6, 1, 1, 0),
61 RK3036_PLL_RATE(216000000, 1, 72, 4, 2, 1, 0),
62 RK3036_PLL_RATE(96000000, 1, 48, 6, 2, 1, 0),
63 { /* sentinel */ },
64 };
65
66 static struct rockchip_pll_clock rk3506_pll_clks[] = {
67 [GPLL] = PLL(pll_rk3328, PLL_GPLL, RK3506_PLL_CON(0),
68 RK3506_MODE_CON, 0, 10, 0, rk3506_pll_rates),
69 [V0PLL] = PLL(pll_rk3328, PLL_V0PLL, RK3506_PLL_CON(8),
70 RK3506_MODE_CON, 2, 10, 0, rk3506_pll_rates),
71 [V1PLL] = PLL(pll_rk3328, PLL_V1PLL, RK3506_PLL_CON(16),
72 RK3506_MODE_CON, 4, 10, 0, rk3506_pll_rates),
73 };
74
75 #define RK3506_CPUCLK_RATE(_rate, _aclk_m_core, _pclk_dbg) \
76 { \
77 .rate = _rate##U, \
78 .aclk_div = _aclk_m_core, \
79 .pclk_div = _pclk_dbg, \
80 }
81
82 /* SIGN-OFF: aclk_core: 500M, pclk_core: 125M, */
83 static struct rockchip_cpu_rate_table rk3506_cpu_rates[] = {
84 RK3506_CPUCLK_RATE(1179648000, 1, 6),
85 RK3506_CPUCLK_RATE(903168000, 1, 5),
86 RK3506_CPUCLK_RATE(800000000, 1, 4),
87 RK3506_CPUCLK_RATE(589824000, 1, 3),
88 RK3506_CPUCLK_RATE(400000000, 1, 2),
89 RK3506_CPUCLK_RATE(200000000, 1, 1),
90 { /* sentinel */ },
91 };
92
93 #ifndef CONFIG_SPL_BUILD
94 #define RK3506_CLK_DUMP(_id, _name) \
95 { \
96 .id = _id, \
97 .name = _name, \
98 }
99
100 static const struct rk3506_clk_info clks_dump[] = {
101 RK3506_CLK_DUMP(PLL_GPLL, "gpll"),
102 RK3506_CLK_DUMP(PLL_V0PLL, "v0pll"),
103 RK3506_CLK_DUMP(PLL_V1PLL, "v1pll"),
104 RK3506_CLK_DUMP(CLK_GPLL_DIV, "clk_gpll_div"),
105 RK3506_CLK_DUMP(CLK_GPLL_DIV_100M, "clk_gpll_div_100m"),
106 RK3506_CLK_DUMP(CLK_V0PLL_DIV, "clk_v0pll_div"),
107 RK3506_CLK_DUMP(CLK_V1PLL_DIV, "clk_v1pll_div"),
108 RK3506_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root"),
109 RK3506_CLK_DUMP(HCLK_BUS_ROOT, "hclk_bus_root"),
110 RK3506_CLK_DUMP(PCLK_BUS_ROOT, "pclk_bus_root"),
111 RK3506_CLK_DUMP(ACLK_HSPERI_ROOT, "aclk_hsperi_root"),
112 RK3506_CLK_DUMP(HCLK_LSPERI_ROOT, "hclk_ksperi_root"),
113 };
114
115 /**
116 * soc_clk_dump() - Print clock frequencies
117 * Returns zero on success
118 *
119 * Implementation for the clk dump command.
120 */
soc_clk_dump(void)121 int soc_clk_dump(void)
122 {
123 const struct rk3506_clk_info *clk_dump;
124 struct rk3506_clk_priv *priv;
125 struct udevice *cru_dev;
126 struct clk clk;
127 ulong clk_count = ARRAY_SIZE(clks_dump);
128 ulong rate;
129 int i, ret;
130 u32 sel;
131
132 ret = uclass_get_device_by_driver(UCLASS_CLK,
133 DM_GET_DRIVER(rockchip_rk3506_cru),
134 &cru_dev);
135 if (ret) {
136 printf("%s failed to get cru device\n", __func__);
137 return ret;
138 }
139
140 priv = dev_get_priv(cru_dev);
141 sel = (readl(&priv->cru->clksel_con[15]) &
142 CLK_CORE_SRC_PVTMUX_SEL_MASK) >>
143 CLK_CORE_SRC_PVTMUX_SEL_SHIFT;
144 if (sel == CLK_CORE_PVTPLL_SRC)
145 printf("CLK: (arm clk use pvtpll, rate = 1200M)\n");
146 else
147 printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
148 priv->sync_kernel ? "sync kernel" : "uboot",
149 priv->armclk_enter_hz / 1000,
150 priv->armclk_init_hz / 1000,
151 priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
152 priv->set_armclk_rate ? " KHz" : "N/A");
153 for (i = 0; i < clk_count; i++) {
154 clk_dump = &clks_dump[i];
155 if (clk_dump->name) {
156 clk.id = clk_dump->id;
157 ret = clk_request(cru_dev, &clk);
158 if (ret < 0)
159 return ret;
160
161 rate = clk_get_rate(&clk);
162 clk_free(&clk);
163 if (i == 0) {
164 if (rate < 0)
165 printf(" %s %s\n", clk_dump->name,
166 "unknown");
167 else
168 printf(" %s %lu KHz\n", clk_dump->name,
169 rate / 1000);
170 } else {
171 if (rate < 0)
172 printf(" %s %s\n", clk_dump->name,
173 "unknown");
174 else
175 printf(" %s %lu KHz\n", clk_dump->name,
176 rate / 1000);
177 }
178 }
179 }
180
181 return 0;
182 }
183 #endif
184
rk3506_armclk_get_rate(struct rk3506_clk_priv * priv)185 static int rk3506_armclk_get_rate(struct rk3506_clk_priv *priv)
186 {
187 struct rk3506_cru *cru = priv->cru;
188 u32 sel, con, div;
189 ulong prate;
190
191 con = readl(&cru->clksel_con[15]);
192 sel = (con & CLK_CORE_SRC_SEL_MASK) >> CLK_CORE_SRC_SEL_SHIFT;
193 div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
194
195 if (sel == CLK_CORE_SEL_GPLL)
196 prate = priv->gpll_hz;
197 else if (sel == CLK_CORE_SEL_V0PLL)
198 prate = priv->v0pll_hz;
199 else if (sel == CLK_CORE_SEL_V1PLL)
200 prate = priv->v1pll_hz;
201 else
202 return -EINVAL;
203
204 return DIV_TO_RATE(prate, div);
205 }
206
rk3506_armclk_set_rate(struct rk3506_clk_priv * priv,ulong new_rate)207 static int rk3506_armclk_set_rate(struct rk3506_clk_priv *priv, ulong new_rate)
208 {
209 const struct rockchip_cpu_rate_table *rate;
210 struct rk3506_cru *cru = priv->cru;
211 ulong old_rate, prate;
212 u32 con, sel, div, old_div;
213
214 rate = rockchip_get_cpu_settings(rk3506_cpu_rates, new_rate);
215 if (!rate) {
216 printf("%s unsupported rate\n", __func__);
217 return -EINVAL;
218 }
219
220 /*
221 * set up dependent divisors for PCLK and ACLK clocks.
222 */
223 old_rate = rk3506_armclk_get_rate(priv);
224 if (new_rate >= old_rate) {
225 rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
226 rate->aclk_div << ACLK_CORE_DIV_SHIFT);
227 rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
228 rate->pclk_div << PCLK_CORE_DIV_SHIFT);
229 }
230
231 if (new_rate == 589824000 || new_rate == 1179648000) {
232 sel = CLK_CORE_SEL_V0PLL;
233 div = DIV_ROUND_UP(priv->v0pll_hz, new_rate);
234 prate = priv->v0pll_hz;
235 } else if (new_rate == 903168000) {
236 sel = CLK_CORE_SEL_V1PLL;
237 div = DIV_ROUND_UP(priv->v1pll_hz, new_rate);
238 prate = priv->v1pll_hz;
239 } else {
240 sel = CLK_CORE_SEL_GPLL;
241 div = DIV_ROUND_UP(priv->gpll_hz, new_rate);
242 prate = priv->gpll_hz;
243 }
244 assert(div - 1 <= 31);
245
246 con = readl(&cru->clksel_con[15]);
247 old_div = (con & CLK_CORE_SRC_DIV_MASK) >> CLK_CORE_SRC_DIV_SHIFT;
248 if (DIV_TO_RATE(prate, old_div) > new_rate) {
249 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
250 (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
251 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
252 sel << CLK_CORE_SRC_SEL_SHIFT);
253 } else {
254 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_SEL_MASK,
255 sel << CLK_CORE_SRC_SEL_SHIFT);
256 rk_clrsetreg(&cru->clksel_con[15], CLK_CORE_SRC_DIV_MASK,
257 (div - 1) << CLK_CORE_SRC_DIV_SHIFT);
258 }
259
260 if (new_rate < old_rate) {
261 rk_clrsetreg(&cru->clksel_con[15], ACLK_CORE_DIV_MASK,
262 rate->aclk_div << ACLK_CORE_DIV_SHIFT);
263 rk_clrsetreg(&cru->clksel_con[16], PCLK_CORE_DIV_MASK,
264 rate->pclk_div << PCLK_CORE_DIV_SHIFT);
265 }
266
267 return 0;
268 }
269
rk3506_pll_div_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)270 static ulong rk3506_pll_div_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
271 {
272 struct rk3506_cru *cru = priv->cru;
273 u32 con, div;
274 ulong prate;
275
276 switch (clk_id) {
277 case CLK_GPLL_DIV:
278 con = readl(&cru->clksel_con[0]);
279 div = (con & CLK_GPLL_DIV_MASK) >> CLK_GPLL_DIV_SHIFT;
280 prate = priv->gpll_hz;
281 break;
282 case CLK_GPLL_DIV_100M:
283 con = readl(&cru->clksel_con[0]);
284 div = (con & CLK_GPLL_DIV_100M_MASK) >> CLK_GPLL_DIV_100M_SHIFT;
285 prate = priv->gpll_div_hz;
286 break;
287 case CLK_V0PLL_DIV:
288 con = readl(&cru->clksel_con[1]);
289 div = (con & CLK_V0PLL_DIV_MASK) >> CLK_V0PLL_DIV_SHIFT;
290 prate = priv->v0pll_hz;
291 break;
292 case CLK_V1PLL_DIV:
293 con = readl(&cru->clksel_con[1]);
294 div = (con & CLK_V1PLL_DIV_MASK) >> CLK_V1PLL_DIV_SHIFT;
295 prate = priv->v1pll_hz;
296 break;
297 default:
298 return -ENOENT;
299 }
300
301 return DIV_TO_RATE(prate, div);
302 }
303
rk3506_pll_div_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)304 static ulong rk3506_pll_div_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
305 ulong rate)
306 {
307 struct rk3506_cru *cru = priv->cru;
308 u32 div;
309
310 switch (clk_id) {
311 case CLK_GPLL_DIV:
312 div = DIV_ROUND_UP(priv->gpll_hz, rate);
313 assert(div - 1 <= 15);
314 rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_MASK,
315 ((div - 1) << CLK_GPLL_DIV_SHIFT));
316 break;
317 case CLK_GPLL_DIV_100M:
318 div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
319 assert(div - 1 <= 15);
320 rk_clrsetreg(&cru->clksel_con[0], CLK_GPLL_DIV_100M_MASK,
321 ((div - 1) << CLK_GPLL_DIV_100M_SHIFT));
322 break;
323 case CLK_V0PLL_DIV:
324 div = DIV_ROUND_UP(priv->v0pll_hz, rate);
325 assert(div - 1 <= 15);
326 rk_clrsetreg(&cru->clksel_con[1], CLK_V0PLL_DIV_MASK,
327 ((div - 1) << CLK_V0PLL_DIV_SHIFT));
328 break;
329 case CLK_V1PLL_DIV:
330 div = DIV_ROUND_UP(priv->v1pll_hz, rate);
331 assert(div - 1 <= 15);
332 rk_clrsetreg(&cru->clksel_con[1], CLK_V1PLL_DIV_MASK,
333 ((div - 1) << CLK_V1PLL_DIV_SHIFT));
334 break;
335 default:
336 return -ENOENT;
337 }
338
339 return rk3506_pll_div_get_rate(priv, clk_id);
340 }
341
rk3506_bus_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)342 static ulong rk3506_bus_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
343 {
344 struct rk3506_cru *cru = priv->cru;
345 u32 sel, con, div;
346 ulong prate;
347
348 switch (clk_id) {
349 case ACLK_BUS_ROOT:
350 con = readl(&cru->clksel_con[21]);
351 sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
352 div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
353 break;
354 case HCLK_BUS_ROOT:
355 con = readl(&cru->clksel_con[21]);
356 sel = (con & HCLK_BUS_SEL_MASK) >> HCLK_BUS_SEL_SHIFT;
357 div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
358 break;
359 case PCLK_BUS_ROOT:
360 con = readl(&cru->clksel_con[22]);
361 sel = (con & PCLK_BUS_SEL_MASK) >> PCLK_BUS_SEL_SHIFT;
362 div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
363 break;
364 default:
365 return -ENOENT;
366 }
367
368 if (sel == ACLK_BUS_SEL_GPLL_DIV)
369 prate = priv->gpll_div_hz;
370 else if (sel == ACLK_BUS_SEL_V0PLL_DIV)
371 prate = priv->v0pll_div_hz;
372 else if (sel == ACLK_BUS_SEL_V1PLL_DIV)
373 prate = priv->v1pll_div_hz;
374 else
375 return -EINVAL;
376
377 return DIV_TO_RATE(prate, div);
378 }
379
rk3506_bus_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)380 static ulong rk3506_bus_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
381 ulong rate)
382 {
383 struct rk3506_cru *cru = priv->cru;
384 u32 sel, div;
385
386 if (priv->v0pll_div_hz % rate == 0) {
387 sel = ACLK_BUS_SEL_V0PLL_DIV;
388 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
389 } else if (priv->v1pll_div_hz % rate == 0) {
390 sel= ACLK_BUS_SEL_V1PLL_DIV;
391 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
392 } else {
393 sel= ACLK_BUS_SEL_GPLL_DIV;
394 div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
395 }
396 assert(div - 1 <= 31);
397
398 switch (clk_id) {
399 case ACLK_BUS_ROOT:
400 rk_clrsetreg(&cru->clksel_con[21],
401 ACLK_BUS_DIV_MASK | ACLK_BUS_SEL_MASK,
402 (sel << ACLK_BUS_SEL_SHIFT) |
403 ((div - 1) << ACLK_BUS_DIV_SHIFT));
404 break;
405 case HCLK_BUS_ROOT:
406 rk_clrsetreg(&cru->clksel_con[21],
407 HCLK_BUS_SEL_MASK | HCLK_BUS_DIV_MASK,
408 (sel << HCLK_BUS_SEL_SHIFT) |
409 ((div - 1) << HCLK_BUS_DIV_SHIFT));
410 break;
411 case PCLK_BUS_ROOT:
412 rk_clrsetreg(&cru->clksel_con[22],
413 PCLK_BUS_SEL_MASK | PCLK_BUS_DIV_MASK,
414 (sel << PCLK_BUS_SEL_SHIFT) |
415 ((div - 1) << PCLK_BUS_DIV_SHIFT));
416 break;
417 default:
418 return -ENOENT;
419 }
420
421 return rk3506_bus_get_rate(priv, clk_id);
422 }
423
rk3506_peri_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)424 static ulong rk3506_peri_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
425 {
426 struct rk3506_cru *cru = priv->cru;
427 u32 sel, con, div;
428 ulong prate;
429
430 switch (clk_id) {
431 case ACLK_HSPERI_ROOT:
432 con = readl(&cru->clksel_con[49]);
433 sel = (con & ACLK_HSPERI_SEL_MASK) >> ACLK_HSPERI_SEL_SHIFT;
434 div = (con & ACLK_HSPERI_DIV_MASK) >> ACLK_HSPERI_DIV_SHIFT;
435 break;
436 case HCLK_LSPERI_ROOT:
437 con = readl(&cru->clksel_con[29]);
438 sel = (con & HCLK_LSPERI_SEL_MASK) >> HCLK_LSPERI_SEL_SHIFT;
439 div = (con & HCLK_LSPERI_DIV_MASK) >> HCLK_LSPERI_DIV_SHIFT;
440 break;
441 default:
442 return -ENOENT;
443 }
444
445 if (sel == ACLK_HSPERI_SEL_GPLL_DIV)
446 prate = priv->gpll_div_hz;
447 else if (sel == ACLK_HSPERI_SEL_V0PLL_DIV)
448 prate = priv->v0pll_div_hz;
449 else if (sel == ACLK_HSPERI_SEL_V1PLL_DIV)
450 prate = priv->v1pll_div_hz;
451 else
452 return -EINVAL;
453
454 return DIV_TO_RATE(prate, div);
455 }
456
rk3506_peri_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)457 static ulong rk3506_peri_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
458 ulong rate)
459 {
460 struct rk3506_cru *cru = priv->cru;
461 u32 sel, div;
462
463 if (priv->v0pll_div_hz % rate == 0) {
464 sel = ACLK_BUS_SEL_V0PLL_DIV;
465 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
466 } else if (priv->v1pll_div_hz % rate == 0) {
467 sel = ACLK_BUS_SEL_V1PLL_DIV;
468 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
469 } else {
470 sel = ACLK_BUS_SEL_GPLL_DIV;
471 div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
472 }
473 assert(div - 1 <= 31);
474
475 switch (clk_id) {
476 case ACLK_HSPERI_ROOT:
477 rk_clrsetreg(&cru->clksel_con[49],
478 ACLK_HSPERI_SEL_MASK | ACLK_HSPERI_DIV_MASK,
479 (sel << ACLK_HSPERI_SEL_SHIFT) |
480 ((div - 1) << ACLK_HSPERI_DIV_SHIFT));
481 break;
482 case HCLK_LSPERI_ROOT:
483 rk_clrsetreg(&cru->clksel_con[29],
484 HCLK_LSPERI_SEL_MASK | HCLK_LSPERI_DIV_MASK,
485 (sel << HCLK_LSPERI_SEL_SHIFT) |
486 ((div - 1) << HCLK_LSPERI_DIV_SHIFT));
487 break;
488 default:
489 return -ENOENT;
490 }
491
492 return rk3506_peri_get_rate(priv, clk_id);
493 }
494
rk3506_sdmmc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)495 static ulong rk3506_sdmmc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
496 {
497 struct rk3506_cru *cru = priv->cru;
498 u32 sel, con, div;
499 ulong prate;
500
501 con = readl(&cru->clksel_con[49]);
502 sel = (con & CCLK_SDMMC_SEL_MASK) >> CCLK_SDMMC_SEL_SHIFT;
503 div = (con & CCLK_SDMMC_DIV_MASK) >> CCLK_SDMMC_DIV_SHIFT;
504
505 if (sel == CCLK_SDMMC_SEL_24M)
506 prate = OSC_HZ;
507 else if (sel == CCLK_SDMMC_SEL_GPLL)
508 prate = priv->gpll_hz;
509 else if (sel == CCLK_SDMMC_SEL_V0PLL)
510 prate = priv->v0pll_hz;
511 else if (sel == CCLK_SDMMC_SEL_V1PLL)
512 prate = priv->v1pll_hz;
513 else
514 return -EINVAL;
515
516 return DIV_TO_RATE(prate, div);
517 }
518
rk3506_sdmmc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)519 static ulong rk3506_sdmmc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
520 ulong rate)
521 {
522 struct rk3506_cru *cru = priv->cru;
523 u32 sel, div;
524
525 if (OSC_HZ % rate == 0) {
526 sel = CCLK_SDMMC_SEL_24M;
527 div = DIV_ROUND_UP(OSC_HZ, rate);
528 } else if (priv->v0pll_hz % rate == 0) {
529 sel = CCLK_SDMMC_SEL_V0PLL;
530 div = DIV_ROUND_UP(priv->v0pll_hz, rate);
531 } else if (priv->v1pll_hz % rate == 0) {
532 sel= CCLK_SDMMC_SEL_V1PLL;
533 div = DIV_ROUND_UP(priv->v1pll_hz, rate);
534 } else {
535 sel= CCLK_SDMMC_SEL_GPLL;
536 div = DIV_ROUND_UP(priv->gpll_hz, rate);
537 }
538 assert(div - 1 <= 63);
539
540 rk_clrsetreg(&cru->clksel_con[49],
541 CCLK_SDMMC_SEL_MASK | CCLK_SDMMC_DIV_MASK,
542 (sel << CCLK_SDMMC_SEL_SHIFT) |
543 ((div - 1) << CCLK_SDMMC_DIV_SHIFT));
544
545 return rk3506_sdmmc_get_rate(priv, clk_id);
546 }
547
rk3506_saradc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)548 static ulong rk3506_saradc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
549 {
550 struct rk3506_cru *cru = priv->cru;
551 u32 div, con, sel;
552 ulong prate;
553
554 con = readl(&cru->clksel_con[54]);
555 div = (con & CLK_SARADC_DIV_MASK) >> CLK_SARADC_DIV_SHIFT;
556 sel = (con & CLK_SARADC_SEL_MASK) >> CLK_SARADC_SEL_SHIFT;
557
558 if (sel == CLK_SARADC_SEL_24M)
559 prate = OSC_HZ;
560 else if (sel == CLK_SARADC_SEL_400K)
561 prate = 400000;
562 else if (sel == CLK_SARADC_SEL_32K)
563 prate = 32000;
564 else
565 return -EINVAL;
566
567 return DIV_TO_RATE(prate, div);
568 }
569
rk3506_saradc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)570 static ulong rk3506_saradc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
571 ulong rate)
572 {
573 struct rk3506_cru *cru = priv->cru;
574 u32 div, sel;
575
576 if (32000 % rate == 0) {
577 sel = CLK_SARADC_SEL_32K;
578 div = 1;
579 } else if (400000 % rate == 0) {
580 sel = CLK_SARADC_SEL_400K;
581 div = 1;
582 } else {
583 sel= CLK_SARADC_SEL_24M;
584 div = DIV_ROUND_UP(OSC_HZ, rate);
585 }
586 assert(div - 1 <= 15);
587
588 rk_clrsetreg(&cru->clksel_con[54],
589 CLK_SARADC_SEL_MASK | CLK_SARADC_DIV_MASK,
590 (sel << CLK_SARADC_SEL_SHIFT) |
591 ((div - 1) << CLK_SARADC_DIV_SHIFT));
592
593 return rk3506_saradc_get_rate(priv, clk_id);
594 }
595
rk3506_tsadc_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)596 static ulong rk3506_tsadc_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
597 {
598 struct rk3506_cru *cru = priv->cru;
599 u32 div, con;
600
601 con = readl(&cru->clksel_con[61]);
602 switch (clk_id) {
603 case CLK_TSADC_TSEN:
604 div = (con & CLK_TSADC_TSEN_DIV_MASK) >> CLK_TSADC_TSEN_DIV_SHIFT;
605 break;
606 case CLK_TSADC:
607 div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
608 break;
609 default:
610 return -ENOENT;
611 }
612
613 return DIV_TO_RATE(OSC_HZ, div);
614 }
615
rk3506_tsadc_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)616 static ulong rk3506_tsadc_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
617 ulong rate)
618 {
619 struct rk3506_cru *cru = priv->cru;
620 u32 div;
621
622 switch (clk_id) {
623 case CLK_TSADC_TSEN:
624 div = DIV_ROUND_UP(OSC_HZ, rate);
625 assert(div - 1 <= 7);
626 rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_TSEN_DIV_MASK,
627 (div - 1) << CLK_TSADC_TSEN_DIV_SHIFT);
628 break;
629 case CLK_TSADC:
630 div = DIV_ROUND_UP(OSC_HZ, rate);
631 assert(div - 1 <= 255);
632 rk_clrsetreg(&cru->clksel_con[61], CLK_TSADC_DIV_MASK,
633 (div - 1) << CLK_TSADC_DIV_SHIFT);
634 break;
635 default:
636 return -ENOENT;
637 }
638
639
640 return rk3506_tsadc_get_rate(priv, clk_id);
641 }
642
rk3506_i2c_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)643 static ulong rk3506_i2c_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
644 {
645 struct rk3506_cru *cru = priv->cru;
646 u32 sel, con, div;
647 ulong prate;
648
649 switch (clk_id) {
650 case CLK_I2C0:
651 con = readl(&cru->clksel_con[32]);
652 sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
653 div = (con & CLK_I2C0_DIV_MASK) >> CLK_I2C0_DIV_SHIFT;
654 case CLK_I2C1:
655 con = readl(&cru->clksel_con[32]);
656 sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
657 div = (con & CLK_I2C1_DIV_MASK) >> CLK_I2C1_DIV_SHIFT;
658 case CLK_I2C2:
659 con = readl(&cru->clksel_con[33]);
660 sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
661 div = (con & CLK_I2C2_DIV_MASK) >> CLK_I2C2_DIV_SHIFT;
662 break;
663 default:
664 return -ENOENT;
665 }
666
667 if (sel == CLK_I2C_SEL_GPLL)
668 prate = priv->gpll_hz;
669 else if (sel == CLK_I2C_SEL_V0PLL)
670 prate = priv->v0pll_hz;
671 else if (sel == CLK_I2C_SEL_V1PLL)
672 prate = priv->v1pll_hz;
673 else
674 return -EINVAL;
675
676 return DIV_TO_RATE(prate, div);
677 }
678
rk3506_i2c_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)679 static ulong rk3506_i2c_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
680 ulong rate)
681 {
682 struct rk3506_cru *cru = priv->cru;
683 u32 sel, div;
684
685 if (priv->v0pll_hz % rate == 0) {
686 sel = CLK_I2C_SEL_V0PLL;
687 div = DIV_ROUND_UP(priv->v0pll_hz, rate);
688 } else if (priv->v1pll_hz % rate == 0) {
689 sel = CLK_I2C_SEL_V1PLL;
690 div = DIV_ROUND_UP(priv->v1pll_hz, rate);
691 } else {
692 sel = CLK_I2C_SEL_GPLL;
693 div = DIV_ROUND_UP(priv->gpll_hz, rate);
694 }
695 assert(div - 1 <= 15);
696
697 switch (clk_id) {
698 case CLK_I2C0:
699 rk_clrsetreg(&cru->clksel_con[32],
700 CLK_I2C0_SEL_MASK | CLK_I2C0_DIV_MASK,
701 (sel << CLK_I2C0_SEL_SHIFT) |
702 ((div - 1) << CLK_I2C0_DIV_SHIFT));
703 break;
704 case CLK_I2C1:
705 rk_clrsetreg(&cru->clksel_con[32],
706 CLK_I2C1_SEL_MASK | CLK_I2C1_DIV_MASK,
707 (sel << CLK_I2C1_SEL_SHIFT) |
708 ((div - 1) << CLK_I2C1_DIV_SHIFT));
709 break;
710 case CLK_I2C2:
711 rk_clrsetreg(&cru->clksel_con[33],
712 CLK_I2C2_SEL_MASK | CLK_I2C2_DIV_MASK,
713 (sel << CLK_I2C2_SEL_SHIFT) |
714 ((div - 1) << CLK_I2C2_DIV_SHIFT));
715 break;
716 default:
717 return -ENOENT;
718 }
719
720
721 return rk3506_i2c_get_rate(priv, clk_id);
722 }
723
rk3506_pwm_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)724 static ulong rk3506_pwm_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
725 {
726 struct rk3506_cru *cru = priv->cru;
727 u32 sel, con, div;
728 ulong prate;
729
730 switch (clk_id) {
731 case CLK_PWM0:
732 con = readl(&cru->pmuclksel_con[0]);
733 div = (con & CLK_PWM0_DIV_MASK) >> CLK_PWM0_DIV_SHIFT;
734 prate = priv->gpll_div_100mhz;
735 break;
736 case CLK_PWM1:
737 con = readl(&cru->clksel_con[33]);
738 sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
739 div = (con & CLK_PWM1_DIV_MASK) >> CLK_PWM1_DIV_SHIFT;
740 if (sel == CLK_PWM1_SEL_GPLL_DIV)
741 prate = priv->gpll_div_hz;
742 else if (sel == CLK_PWM1_SEL_V0PLL_DIV)
743 prate = priv->v0pll_div_hz;
744 else if (sel == CLK_PWM1_SEL_V1PLL_DIV)
745 prate = priv->v1pll_div_hz;
746 else
747 return -EINVAL;
748 break;
749 default:
750 return -ENOENT;
751 }
752
753 return DIV_TO_RATE(prate, div);
754 }
755
rk3506_pwm_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)756 static ulong rk3506_pwm_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
757 ulong rate)
758 {
759 struct rk3506_cru *cru = priv->cru;
760 u32 sel, div;
761
762 switch (clk_id) {
763 case CLK_PWM0:
764 div = DIV_ROUND_UP(priv->gpll_div_100mhz, rate);
765 assert(div - 1 <= 15);
766 rk_clrsetreg(&cru->pmuclksel_con[0], CLK_PWM0_DIV_MASK,
767 (div - 1) << CLK_PWM0_DIV_SHIFT);
768 break;
769 case CLK_PWM1:
770 if (priv->v0pll_hz % rate == 0) {
771 sel = CLK_PWM1_SEL_V0PLL_DIV;
772 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
773 } else if (priv->v1pll_hz % rate == 0) {
774 sel = CLK_PWM1_SEL_V1PLL_DIV;
775 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
776 } else {
777 sel = CLK_PWM1_SEL_GPLL_DIV;
778 div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
779 }
780 assert(div - 1 <= 15);
781 rk_clrsetreg(&cru->clksel_con[33],
782 CLK_PWM1_SEL_MASK | CLK_PWM1_DIV_MASK,
783 (sel << CLK_PWM1_SEL_SHIFT) |
784 ((div - 1) << CLK_PWM1_DIV_SHIFT));
785 break;
786 default:
787 return -ENOENT;
788 }
789
790 return rk3506_pwm_get_rate(priv, clk_id);
791 }
792
rk3506_spi_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)793 static ulong rk3506_spi_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
794 {
795 struct rk3506_cru *cru = priv->cru;
796 u32 sel, con, div;
797 ulong prate;
798
799 switch (clk_id) {
800 case CLK_SPI0:
801 con = readl(&cru->clksel_con[34]);
802 sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
803 div = (con & CLK_SPI0_DIV_MASK) >> CLK_SPI0_DIV_SHIFT;
804 break;
805 case CLK_SPI1:
806 con = readl(&cru->clksel_con[34]);
807 sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
808 div = (con & CLK_SPI1_DIV_MASK) >> CLK_SPI1_DIV_SHIFT;
809 break;
810 default:
811 return -ENOENT;
812 }
813
814 if (sel == CLK_SPI_SEL_24M)
815 prate = OSC_HZ;
816 else if (sel == CLK_SPI_SEL_GPLL_DIV)
817 prate = priv->gpll_div_hz;
818 else if (sel == CLK_SPI_SEL_V0PLL_DIV)
819 prate = priv->v0pll_div_hz;
820 else if (sel == CLK_SPI_SEL_V1PLL_DIV)
821 prate = priv->v1pll_div_hz;
822 else
823 return -EINVAL;
824
825 return DIV_TO_RATE(prate, div);
826 }
827
rk3506_spi_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)828 static ulong rk3506_spi_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
829 ulong rate)
830 {
831 struct rk3506_cru *cru = priv->cru;
832 u32 sel, div;
833
834 if (OSC_HZ % rate == 0) {
835 sel = CLK_SPI_SEL_24M;
836 div = DIV_ROUND_UP(OSC_HZ, rate);
837 } else if (priv->v0pll_div_hz % rate == 0) {
838 sel = CLK_SPI_SEL_V0PLL_DIV;
839 div = DIV_ROUND_UP(priv->v0pll_div_hz, rate);
840 } else if (priv->v1pll_div_hz % rate == 0) {
841 sel = CLK_SPI_SEL_V1PLL_DIV;
842 div = DIV_ROUND_UP(priv->v1pll_div_hz, rate);
843 } else {
844 sel = CLK_SPI_SEL_GPLL_DIV;
845 div = DIV_ROUND_UP(priv->gpll_div_hz, rate);
846 }
847 assert(div - 1 <= 15);
848
849 switch (clk_id) {
850 case CLK_SPI0:
851 rk_clrsetreg(&cru->clksel_con[34],
852 CLK_SPI0_SEL_MASK | CLK_SPI0_DIV_MASK,
853 (sel << CLK_SPI0_SEL_SHIFT) |
854 ((div - 1) << CLK_SPI0_DIV_SHIFT));
855 break;
856 case CLK_SPI1:
857 rk_clrsetreg(&cru->clksel_con[34],
858 CLK_SPI1_SEL_MASK | CLK_SPI1_DIV_MASK,
859 (sel << CLK_SPI1_SEL_SHIFT) |
860 ((div - 1) << CLK_SPI1_DIV_SHIFT));
861 break;
862 default:
863 return -ENOENT;
864 }
865
866 return rk3506_spi_get_rate(priv, clk_id);
867 }
868
rk3506_fspi_get_rate(struct rk3506_clk_priv * priv)869 static ulong rk3506_fspi_get_rate(struct rk3506_clk_priv *priv)
870 {
871 struct rk3506_cru *cru = priv->cru;
872 u32 div, sel, con, prate;
873
874 con = readl(&cru->clksel_con[50]);
875 div = (con & SCLK_FSPI_DIV_MASK) >> SCLK_FSPI_DIV_SHIFT;
876 sel = (con & SCLK_FSPI_SEL_MASK) >> SCLK_FSPI_SEL_SHIFT;
877 if (sel == SCLK_FSPI_SEL_24M)
878 prate = OSC_HZ;
879 else if (sel == SCLK_FSPI_SEL_GPLL)
880 prate = priv->gpll_hz;
881 else if (sel == SCLK_FSPI_SEL_V0PLL)
882 prate = priv->v0pll_hz;
883 else if (sel == SCLK_FSPI_SEL_V1PLL)
884 prate = priv->v1pll_hz;
885 else
886 return -EINVAL;
887
888 return DIV_TO_RATE(prate, div);
889 }
890
rk3506_fspi_set_rate(struct rk3506_clk_priv * priv,ulong rate)891 static ulong rk3506_fspi_set_rate(struct rk3506_clk_priv *priv, ulong rate)
892 {
893 struct rk3506_cru *cru = priv->cru;
894 int div, sel;
895
896 if (OSC_HZ % rate == 0) {
897 sel = SCLK_FSPI_SEL_24M;
898 div = DIV_ROUND_UP(OSC_HZ, rate);
899 } else if ((priv->v0pll_hz % rate) == 0) {
900 sel = SCLK_FSPI_SEL_V0PLL;
901 div = DIV_ROUND_UP(priv->v0pll_hz, rate);
902 } else if ((priv->v1pll_hz % rate) == 0) {
903 sel = SCLK_FSPI_SEL_V1PLL;
904 div = DIV_ROUND_UP(priv->v1pll_hz, rate);
905 } else {
906 sel = SCLK_FSPI_SEL_GPLL;
907 div = DIV_ROUND_UP(priv->gpll_hz, rate);
908 }
909 assert(div - 1 <= 31);
910
911 rk_clrsetreg(&cru->clksel_con[50],
912 SCLK_FSPI_SEL_MASK | SCLK_FSPI_DIV_MASK,
913 sel << SCLK_FSPI_SEL_SHIFT |
914 (div - 1) << SCLK_FSPI_DIV_SHIFT);
915
916 return rk3506_fspi_get_rate(priv);
917 }
918
rk3506_vop_dclk_get_rate(struct rk3506_clk_priv * priv)919 static ulong rk3506_vop_dclk_get_rate(struct rk3506_clk_priv *priv)
920 {
921 struct rk3506_cru *cru = priv->cru;
922 u32 div, sel, con, prate;
923
924 con = readl(&cru->clksel_con[60]);
925 div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
926 sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
927
928 if (sel == DCLK_VOP_SEL_24M)
929 prate = OSC_HZ;
930 else if (sel == DCLK_VOP_SEL_GPLL)
931 prate = priv->gpll_hz;
932 else if (sel == DCLK_VOP_SEL_V0PLL)
933 prate = priv->v0pll_hz;
934 else if (sel == DCLK_VOP_SEL_V1PLL)
935 prate = priv->v1pll_hz;
936 else
937 return -EINVAL;
938
939 return DIV_TO_RATE(prate, div);
940 }
941
rk3506_vop_dclk_set_rate(struct rk3506_clk_priv * priv,ulong rate)942 static ulong rk3506_vop_dclk_set_rate(struct rk3506_clk_priv *priv, ulong rate)
943 {
944 struct rk3506_cru *cru = priv->cru;
945 int div, sel;
946
947 if (OSC_HZ % rate == 0) {
948 sel = DCLK_VOP_SEL_24M;
949 div = DIV_ROUND_UP(OSC_HZ, rate);
950 } else if ((priv->v0pll_hz % rate) == 0) {
951 sel = DCLK_VOP_SEL_V0PLL;
952 div = DIV_ROUND_UP(priv->v0pll_hz, rate);
953 } else if ((priv->v1pll_hz % rate) == 0) {
954 sel = DCLK_VOP_SEL_V1PLL;
955 div = DIV_ROUND_UP(priv->v1pll_hz, rate);
956 } else {
957 sel = DCLK_VOP_SEL_GPLL;
958 div = DIV_ROUND_UP(priv->gpll_hz, rate);
959 }
960 assert(div - 1 <= 255);
961
962 rk_clrsetreg(&cru->clksel_con[60],
963 DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_MASK,
964 sel << DCLK_VOP_SEL_SHIFT |
965 (div - 1) << DCLK_VOP_DIV_SHIFT);
966
967 return rk3506_vop_dclk_get_rate(priv);
968 }
969
rk3506_mac_get_rate(struct rk3506_clk_priv * priv,ulong clk_id)970 static ulong rk3506_mac_get_rate(struct rk3506_clk_priv *priv, ulong clk_id)
971 {
972 struct rk3506_cru *cru = priv->cru;
973 u32 div, con;
974
975 switch (clk_id) {
976 case CLK_MAC0:
977 case CLK_MAC1:
978 con = readl(&cru->clksel_con[50]);
979 div = (con & CLK_MAC_DIV_MASK) >> CLK_MAC_DIV_SHIFT;
980 break;
981 case CLK_MAC_OUT:
982 con = readl(&cru->pmuclksel_con[0]);
983 div = (con & CLK_MAC_OUT_DIV_MASK) >> CLK_MAC_OUT_DIV_SHIFT;
984 break;
985 default:
986 return -ENOENT;
987 }
988
989 return DIV_TO_RATE(priv->gpll_hz, div);
990 }
991
rk3506_mac_set_rate(struct rk3506_clk_priv * priv,ulong clk_id,ulong rate)992 static ulong rk3506_mac_set_rate(struct rk3506_clk_priv *priv, ulong clk_id,
993 ulong rate)
994 {
995 struct rk3506_cru *cru = priv->cru;
996 u32 div;
997
998 switch (clk_id) {
999 case CLK_MAC0:
1000 case CLK_MAC1:
1001 div = DIV_ROUND_UP(priv->gpll_hz, rate);
1002 rk_clrsetreg(&cru->clksel_con[50], CLK_MAC_DIV_MASK,
1003 ((div - 1) << CLK_MAC_DIV_SHIFT));
1004 break;
1005 case CLK_MAC_OUT:
1006 div = DIV_ROUND_UP(priv->gpll_hz, rate);
1007 rk_clrsetreg(&cru->pmuclksel_con[0], CLK_MAC_OUT_DIV_MASK,
1008 ((div - 1) << CLK_MAC_OUT_DIV_SHIFT));
1009 break;
1010 default:
1011 return -ENOENT;
1012 }
1013
1014 return rk3506_mac_get_rate(priv, clk_id);
1015 }
1016
rk3506_clk_get_rate(struct clk * clk)1017 static ulong rk3506_clk_get_rate(struct clk *clk)
1018 {
1019 struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
1020 ulong rate = 0;
1021
1022 if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
1023 printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
1024 __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
1025 return -ENOENT;
1026 }
1027
1028 switch (clk->id) {
1029 case PLL_GPLL:
1030 rate = priv->gpll_hz;
1031 break;
1032 case PLL_V0PLL:
1033 rate = priv->v0pll_hz;
1034 break;
1035 case PLL_V1PLL:
1036 rate = priv->v1pll_hz;
1037 break;
1038 case ARMCLK:
1039 rate = rk3506_armclk_get_rate(priv);
1040 break;
1041 case CLK_GPLL_DIV:
1042 case CLK_GPLL_DIV_100M:
1043 case CLK_V0PLL_DIV:
1044 case CLK_V1PLL_DIV:
1045 rate = rk3506_pll_div_get_rate(priv, clk->id);
1046 break;
1047 case ACLK_BUS_ROOT:
1048 case HCLK_BUS_ROOT:
1049 case PCLK_BUS_ROOT:
1050 rate = rk3506_bus_get_rate(priv, clk->id);
1051 break;
1052 case ACLK_HSPERI_ROOT:
1053 case HCLK_LSPERI_ROOT:
1054 rate = rk3506_peri_get_rate(priv, clk->id);
1055 break;
1056 case HCLK_SDMMC:
1057 case CCLK_SRC_SDMMC:
1058 rate = rk3506_sdmmc_get_rate(priv, clk->id);
1059 break;
1060 case CLK_SARADC:
1061 rate = rk3506_saradc_get_rate(priv, clk->id);
1062 break;
1063 case CLK_TSADC:
1064 case CLK_TSADC_TSEN:
1065 rate = rk3506_tsadc_get_rate(priv, clk->id);
1066 break;
1067 case CLK_I2C0:
1068 case CLK_I2C1:
1069 case CLK_I2C2:
1070 rate = rk3506_i2c_get_rate(priv, clk->id);
1071 break;
1072 case CLK_PWM0:
1073 case CLK_PWM1:
1074 rate = rk3506_pwm_get_rate(priv, clk->id);
1075 break;
1076 case CLK_SPI0:
1077 case CLK_SPI1:
1078 rate = rk3506_spi_get_rate(priv, clk->id);
1079 break;
1080 case SCLK_FSPI:
1081 rate = rk3506_fspi_get_rate(priv);
1082 break;
1083 case DCLK_VOP:
1084 rate = rk3506_vop_dclk_get_rate(priv);
1085 break;
1086 case CLK_MAC0:
1087 case CLK_MAC1:
1088 case CLK_MAC_OUT:
1089 rate = rk3506_mac_get_rate(priv, clk->id);
1090 break;
1091 default:
1092 return -ENOENT;
1093 }
1094
1095 return rate;
1096 };
1097
rk3506_clk_set_rate(struct clk * clk,ulong rate)1098 static ulong rk3506_clk_set_rate(struct clk *clk, ulong rate)
1099 {
1100 struct rk3506_clk_priv *priv = dev_get_priv(clk->dev);
1101 ulong ret = 0;
1102
1103 if (!priv->gpll_hz || !priv->v0pll_hz || !priv->v1pll_hz) {
1104 printf("%s: gpll=%lu, v0pll=%lu, v1pll=%lu\n",
1105 __func__, priv->gpll_hz, priv->v0pll_hz, priv->v1pll_hz);
1106 return -ENOENT;
1107 }
1108
1109 debug("%s: id=%ld, rate=%ld\n", __func__, clk->id, rate);
1110
1111 switch (clk->id) {
1112 case ARMCLK:
1113 if (priv->armclk_hz)
1114 rk3506_armclk_set_rate(priv, rate);
1115 priv->armclk_hz = rate;
1116 break;
1117 case CLK_GPLL_DIV:
1118 case CLK_GPLL_DIV_100M:
1119 case CLK_V0PLL_DIV:
1120 case CLK_V1PLL_DIV:
1121 ret = rk3506_pll_div_set_rate(priv, clk->id, rate);
1122 break;
1123 case ACLK_BUS_ROOT:
1124 case HCLK_BUS_ROOT:
1125 case PCLK_BUS_ROOT:
1126 ret = rk3506_bus_set_rate(priv, clk->id, rate);
1127 break;
1128 case ACLK_HSPERI_ROOT:
1129 case HCLK_LSPERI_ROOT:
1130 ret = rk3506_peri_set_rate(priv, clk->id, rate);
1131 break;
1132 case HCLK_SDMMC:
1133 case CCLK_SRC_SDMMC:
1134 ret = rk3506_sdmmc_set_rate(priv, clk->id, rate);
1135 break;
1136 case CLK_SARADC:
1137 ret = rk3506_saradc_set_rate(priv, clk->id, rate);
1138 break;
1139 case CLK_TSADC:
1140 case CLK_TSADC_TSEN:
1141 ret = rk3506_tsadc_set_rate(priv, clk->id, rate);
1142 break;
1143 case CLK_I2C0:
1144 case CLK_I2C1:
1145 case CLK_I2C2:
1146 ret = rk3506_i2c_set_rate(priv, clk->id, rate);
1147 break;
1148 case CLK_PWM0:
1149 case CLK_PWM1:
1150 ret = rk3506_pwm_set_rate(priv, clk->id, rate);
1151 break;
1152 case CLK_SPI0:
1153 case CLK_SPI1:
1154 ret = rk3506_spi_set_rate(priv, clk->id, rate);
1155 break;
1156 case HCLK_FSPI:
1157 case SCLK_FSPI:
1158 ret = rk3506_fspi_set_rate(priv, rate);
1159 break;
1160 case DCLK_VOP:
1161 ret = rk3506_vop_dclk_set_rate(priv, rate);
1162 break;
1163 case CLK_MAC0:
1164 case CLK_MAC1:
1165 case CLK_MAC_OUT:
1166 ret = rk3506_mac_set_rate(priv, clk->id, rate);
1167 break;
1168 default:
1169 return -ENOENT;
1170 }
1171
1172 return ret;
1173 };
1174
1175 static struct clk_ops rk3506_clk_ops = {
1176 .get_rate = rk3506_clk_get_rate,
1177 .set_rate = rk3506_clk_set_rate,
1178 };
1179
rk3506_clk_init(struct rk3506_clk_priv * priv)1180 static void rk3506_clk_init(struct rk3506_clk_priv *priv)
1181 {
1182 priv->sync_kernel = false;
1183
1184 if (!priv->gpll_hz) {
1185 priv->gpll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[GPLL],
1186 priv->cru, GPLL);
1187 priv->gpll_hz = roundup(priv->gpll_hz, 1000);
1188 }
1189 if (!priv->v0pll_hz) {
1190 priv->v0pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V0PLL],
1191 priv->cru, V0PLL);
1192 priv->v0pll_hz = roundup(priv->v0pll_hz, 1000);
1193 }
1194 if (!priv->v1pll_hz) {
1195 priv->v1pll_hz = rockchip_pll_get_rate(&rk3506_pll_clks[V1PLL],
1196 priv->cru, V1PLL);
1197 priv->v1pll_hz = roundup(priv->v1pll_hz, 1000);
1198 }
1199 if (!priv->gpll_div_hz) {
1200 priv->gpll_div_hz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV);
1201 priv->gpll_div_hz = roundup(priv->gpll_div_hz, 1000);
1202 }
1203 if (!priv->gpll_div_100mhz) {
1204 priv->gpll_div_100mhz = rk3506_pll_div_get_rate(priv, CLK_GPLL_DIV_100M);
1205 priv->gpll_div_100mhz = roundup(priv->gpll_div_100mhz, 1000);
1206 }
1207 if (!priv->v0pll_div_hz) {
1208 priv->v0pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V0PLL_DIV);
1209 priv->v0pll_div_hz = roundup(priv->v0pll_div_hz, 1000);
1210 }
1211 if (!priv->v1pll_div_hz) {
1212 priv->v1pll_div_hz = rk3506_pll_div_get_rate(priv, CLK_V1PLL_DIV);
1213 priv->v1pll_div_hz = roundup(priv->v1pll_div_hz, 1000);
1214 }
1215
1216 if (!priv->armclk_enter_hz) {
1217 priv->armclk_enter_hz = rk3506_armclk_get_rate(priv);
1218 priv->armclk_init_hz = priv->armclk_enter_hz;
1219 }
1220 }
1221
rk3506_clk_probe(struct udevice * dev)1222 static int rk3506_clk_probe(struct udevice *dev)
1223 {
1224 struct rk3506_clk_priv *priv = dev_get_priv(dev);
1225 int ret;
1226
1227 #ifdef CONFIG_SPL_BUILD
1228 /* Init pka crypto rate, sel=v0pll, div=3 */
1229 writel(0x3f801180, RK3506_SCRU_BASE + 0x0010);
1230 /* Change clk core src rate, sel=gpll, div=3 */
1231 writel(0x007f0003, RK3506_CRU_BASE + 0x033c);
1232 #endif
1233 rk3506_clk_init(priv);
1234
1235 /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1236 ret = clk_set_defaults(dev);
1237 if (ret)
1238 debug("%s clk_set_defaults failed %d\n", __func__, ret);
1239 else
1240 priv->sync_kernel = true;
1241
1242 return 0;
1243 }
1244
rk3506_clk_ofdata_to_platdata(struct udevice * dev)1245 static int rk3506_clk_ofdata_to_platdata(struct udevice *dev)
1246 {
1247 struct rk3506_clk_priv *priv = dev_get_priv(dev);
1248
1249 priv->cru = dev_read_addr_ptr(dev);
1250
1251 return 0;
1252 }
1253
rk3506_clk_bind(struct udevice * dev)1254 static int rk3506_clk_bind(struct udevice *dev)
1255 {
1256 struct udevice *sys_child, *sf_child;
1257 struct softreset_reg *sf_priv;
1258 struct sysreset_reg *priv;
1259 int ret;
1260
1261 /* The reset driver does not have a device node, so bind it here */
1262 ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1263 &sys_child);
1264 if (ret) {
1265 debug("Warning: No sysreset driver: ret=%d\n", ret);
1266 } else {
1267 priv = malloc(sizeof(struct sysreset_reg));
1268 priv->glb_srst_fst_value = offsetof(struct rk3506_cru,
1269 glb_srst_fst);
1270 priv->glb_srst_snd_value = offsetof(struct rk3506_cru,
1271 glb_srst_snd);
1272 sys_child->priv = priv;
1273 }
1274
1275 ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1276 dev_ofnode(dev), &sf_child);
1277 if (ret) {
1278 debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1279 } else {
1280 sf_priv = malloc(sizeof(struct softreset_reg));
1281 sf_priv->sf_reset_offset = offsetof(struct rk3506_cru,
1282 softrst_con[0]);
1283 sf_priv->sf_reset_num = 23;
1284 sf_child->priv = sf_priv;
1285 }
1286
1287 return 0;
1288 }
1289
1290 static const struct udevice_id rk3506_clk_ids[] = {
1291 { .compatible = "rockchip,rk3506-cru" },
1292 { }
1293 };
1294
1295 U_BOOT_DRIVER(rockchip_rk3506_cru) = {
1296 .name = "rockchip_rk3506_cru",
1297 .id = UCLASS_CLK,
1298 .of_match = rk3506_clk_ids,
1299 .priv_auto_alloc_size = sizeof(struct rk3506_clk_priv),
1300 .ofdata_to_platdata = rk3506_clk_ofdata_to_platdata,
1301 .ops = &rk3506_clk_ops,
1302 .bind = rk3506_clk_bind,
1303 .probe = rk3506_clk_probe,
1304 };
1305