1a5a5ddb9SElaine Zhang // SPDX-License-Identifier: GPL-2.0
2a5a5ddb9SElaine Zhang /*
3a5a5ddb9SElaine Zhang * Copyright (c) 2021 Rockchip Electronics Co., Ltd
4a5a5ddb9SElaine Zhang * Author: Elaine Zhang <zhangqing@rock-chips.com>
5a5a5ddb9SElaine Zhang */
6a5a5ddb9SElaine Zhang
7a5a5ddb9SElaine Zhang #include <common.h>
8a5a5ddb9SElaine Zhang #include <bitfield.h>
9a5a5ddb9SElaine Zhang #include <clk-uclass.h>
10a5a5ddb9SElaine Zhang #include <dm.h>
11a5a5ddb9SElaine Zhang #include <errno.h>
12a5a5ddb9SElaine Zhang #include <syscon.h>
13a5a5ddb9SElaine Zhang #include <asm/arch/clock.h>
14a5a5ddb9SElaine Zhang #include <asm/arch/cru_rv1106.h>
1532914815SElaine Zhang #include <asm/arch/grf_rv1106.h>
16a5a5ddb9SElaine Zhang #include <asm/arch/hardware.h>
17a5a5ddb9SElaine Zhang #include <asm/io.h>
18a5a5ddb9SElaine Zhang #include <dm/lists.h>
19a5a5ddb9SElaine Zhang #include <dt-bindings/clock/rv1106-cru.h>
20a5a5ddb9SElaine Zhang
21a5a5ddb9SElaine Zhang DECLARE_GLOBAL_DATA_PTR;
22a5a5ddb9SElaine Zhang
23a5a5ddb9SElaine Zhang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
24a5a5ddb9SElaine Zhang
257d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
26a5a5ddb9SElaine Zhang static struct rockchip_pll_rate_table rv1106_pll_rates[] = {
27a5a5ddb9SElaine Zhang /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
28a5a5ddb9SElaine Zhang RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
2976534374SZiyuan Xu RK3036_PLL_RATE(1104000000, 1, 92, 2, 1, 1, 0),
30a5a5ddb9SElaine Zhang RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
31a5a5ddb9SElaine Zhang RK3036_PLL_RATE(1000000000, 3, 250, 2, 1, 1, 0),
32a5a5ddb9SElaine Zhang RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
33a5a5ddb9SElaine Zhang RK3036_PLL_RATE(600000000, 1, 100, 4, 1, 1, 0),
34a5a5ddb9SElaine Zhang RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
35a5a5ddb9SElaine Zhang { /* sentinel */ },
36a5a5ddb9SElaine Zhang };
37a5a5ddb9SElaine Zhang
38a5a5ddb9SElaine Zhang static struct rockchip_pll_clock rv1106_pll_clks[] = {
39a5a5ddb9SElaine Zhang [APLL] = PLL(pll_rk3328, PLL_APLL, RV1106_PLL_CON(0),
40a5a5ddb9SElaine Zhang RV1106_MODE_CON, 0, 10, 0, rv1106_pll_rates),
41a5a5ddb9SElaine Zhang [DPLL] = PLL(pll_rk3328, PLL_DPLL, RV1106_PLL_CON(16),
42a5a5ddb9SElaine Zhang RV1106_SUBDDRMODE_CON, 0, 10, 0, NULL),
43a5a5ddb9SElaine Zhang [CPLL] = PLL(pll_rk3328, PLL_CPLL, RV1106_PLL_CON(8),
44a5a5ddb9SElaine Zhang RV1106_MODE_CON, 2, 10, 0, rv1106_pll_rates),
45a5a5ddb9SElaine Zhang [GPLL] = PLL(pll_rk3328, PLL_GPLL, RV1106_PLL_CON(24),
46a5a5ddb9SElaine Zhang RV1106_MODE_CON, 4, 10, 0, rv1106_pll_rates),
47a5a5ddb9SElaine Zhang };
487d793375SElaine Zhang #endif
49a5a5ddb9SElaine Zhang
50a5a5ddb9SElaine Zhang #ifndef CONFIG_SPL_BUILD
51a5a5ddb9SElaine Zhang #define RV1106_CLK_DUMP(_id, _name, _iscru) \
52a5a5ddb9SElaine Zhang { \
53a5a5ddb9SElaine Zhang .id = _id, \
54a5a5ddb9SElaine Zhang .name = _name, \
55a5a5ddb9SElaine Zhang .is_cru = _iscru, \
56a5a5ddb9SElaine Zhang }
57a5a5ddb9SElaine Zhang
58a5a5ddb9SElaine Zhang static const struct rv1106_clk_info clks_dump[] = {
597d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
60a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PLL_APLL, "apll", true),
61a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PLL_DPLL, "dpll", true),
62a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PLL_GPLL, "gpll", true),
63a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PLL_CPLL, "cpll", true),
64a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(ACLK_PERI_ROOT, "aclk_peri_root", true),
65a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(HCLK_PERI_ROOT, "hclK_peri_root", true),
66a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PCLK_PERI_ROOT, "pclk_peri_root", true),
67a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(ACLK_BUS_ROOT, "aclk_bus_root", true),
68a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PCLK_TOP_ROOT, "pclk_top_root", true),
69a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(PCLK_PMU_ROOT, "pclk_pmu_root", true),
70a5a5ddb9SElaine Zhang RV1106_CLK_DUMP(HCLK_PMU_ROOT, "hclk_pmu_root", true),
717d793375SElaine Zhang #endif
72a5a5ddb9SElaine Zhang };
73a5a5ddb9SElaine Zhang #endif
74a5a5ddb9SElaine Zhang
757d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
rv1106_peri_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)76a5a5ddb9SElaine Zhang static ulong rv1106_peri_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
77a5a5ddb9SElaine Zhang {
78a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
79a5a5ddb9SElaine Zhang u32 con, sel, rate;
80a5a5ddb9SElaine Zhang
81a5a5ddb9SElaine Zhang switch (clk_id) {
82a5a5ddb9SElaine Zhang case ACLK_PERI_ROOT:
83a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
84a5a5ddb9SElaine Zhang sel = (con & ACLK_PERI_SEL_MASK) >> ACLK_PERI_SEL_SHIFT;
85a5a5ddb9SElaine Zhang if (sel == ACLK_PERI_SEL_400M)
86a5a5ddb9SElaine Zhang rate = 400 * MHz;
87a5a5ddb9SElaine Zhang else if (sel == ACLK_PERI_SEL_200M)
88a5a5ddb9SElaine Zhang rate = 200 * MHz;
89a5a5ddb9SElaine Zhang else if (sel == ACLK_PERI_SEL_100M)
90a5a5ddb9SElaine Zhang rate = 100 * MHz;
91a5a5ddb9SElaine Zhang else
92a5a5ddb9SElaine Zhang rate = OSC_HZ;
93a5a5ddb9SElaine Zhang break;
94a5a5ddb9SElaine Zhang case HCLK_PERI_ROOT:
95a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
96a5a5ddb9SElaine Zhang sel = (con & HCLK_PERI_SEL_MASK) >> HCLK_PERI_SEL_SHIFT;
97a5a5ddb9SElaine Zhang if (sel == HCLK_PERI_SEL_200M)
98a5a5ddb9SElaine Zhang rate = 200 * MHz;
99a5a5ddb9SElaine Zhang else if (sel == HCLK_PERI_SEL_100M)
100a5a5ddb9SElaine Zhang rate = 100 * MHz;
101a5a5ddb9SElaine Zhang else if (sel == HCLK_PERI_SEL_50M)
102a5a5ddb9SElaine Zhang rate = 50 * MHz;
103a5a5ddb9SElaine Zhang else
104a5a5ddb9SElaine Zhang rate = OSC_HZ;
105a5a5ddb9SElaine Zhang break;
106a5a5ddb9SElaine Zhang case PCLK_PERI_ROOT:
107a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
108a5a5ddb9SElaine Zhang sel = (con & PCLK_PERI_SEL_MASK) >> PCLK_PERI_SEL_SHIFT;
109a5a5ddb9SElaine Zhang if (sel == PCLK_PERI_SEL_100M)
110a5a5ddb9SElaine Zhang rate = 100 * MHz;
111a5a5ddb9SElaine Zhang else if (sel == PCLK_PERI_SEL_50M)
112a5a5ddb9SElaine Zhang rate = 50 * MHz;
113a5a5ddb9SElaine Zhang else
114a5a5ddb9SElaine Zhang rate = OSC_HZ;
115a5a5ddb9SElaine Zhang break;
116a5a5ddb9SElaine Zhang case ACLK_BUS_ROOT:
117a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[9]);
118a5a5ddb9SElaine Zhang sel = (con & ACLK_BUS_SEL_MASK) >> ACLK_BUS_SEL_SHIFT;
119a5a5ddb9SElaine Zhang if (sel == ACLK_BUS_SEL_300M)
120a5a5ddb9SElaine Zhang rate = 300 * MHz;
121a5a5ddb9SElaine Zhang else if (sel == ACLK_BUS_SEL_200M)
122a5a5ddb9SElaine Zhang rate = 200 * MHz;
123a5a5ddb9SElaine Zhang else if (sel == ACLK_BUS_SEL_100M)
124a5a5ddb9SElaine Zhang rate = 100 * MHz;
125a5a5ddb9SElaine Zhang else
126a5a5ddb9SElaine Zhang rate = OSC_HZ;
127a5a5ddb9SElaine Zhang break;
128a5a5ddb9SElaine Zhang case PCLK_TOP_ROOT:
129a5a5ddb9SElaine Zhang con = readl(&cru->clksel_con[24]);
130a5a5ddb9SElaine Zhang sel = (con & PCLK_TOP_SEL_MASK) >> PCLK_TOP_SEL_SHIFT;
131a5a5ddb9SElaine Zhang if (sel == PCLK_TOP_SEL_100M)
132a5a5ddb9SElaine Zhang rate = 100 * MHz;
133a5a5ddb9SElaine Zhang else if (sel == PCLK_TOP_SEL_50M)
134a5a5ddb9SElaine Zhang rate = 50 * MHz;
135a5a5ddb9SElaine Zhang else
136a5a5ddb9SElaine Zhang rate = OSC_HZ;
137a5a5ddb9SElaine Zhang break;
138a5a5ddb9SElaine Zhang case PCLK_PMU_ROOT:
139a5a5ddb9SElaine Zhang con = readl(&cru->pmu_clksel_con[0]);
140a5a5ddb9SElaine Zhang sel = (con & PCLK_PMU_SEL_MASK) >> PCLK_PMU_SEL_SHIFT;
141a5a5ddb9SElaine Zhang if (sel == PCLK_PMU_SEL_100M)
142a5a5ddb9SElaine Zhang rate = 100 * MHz;
143a5a5ddb9SElaine Zhang else
144a5a5ddb9SElaine Zhang rate = OSC_HZ;
145a5a5ddb9SElaine Zhang break;
146a5a5ddb9SElaine Zhang case HCLK_PMU_ROOT:
147a5a5ddb9SElaine Zhang con = readl(&cru->pmu_clksel_con[0]);
148a5a5ddb9SElaine Zhang sel = (con & HCLK_PMU_SEL_MASK) >> HCLK_PMU_SEL_SHIFT;
149a5a5ddb9SElaine Zhang if (sel == HCLK_PMU_SEL_200M)
150a5a5ddb9SElaine Zhang rate = 200 * MHz;
151a5a5ddb9SElaine Zhang else if (sel == HCLK_PMU_SEL_100M)
152a5a5ddb9SElaine Zhang rate = 100 * MHz;
153a5a5ddb9SElaine Zhang else
154a5a5ddb9SElaine Zhang rate = OSC_HZ;
155a5a5ddb9SElaine Zhang break;
156a5a5ddb9SElaine Zhang default:
157a5a5ddb9SElaine Zhang return -ENOENT;
158a5a5ddb9SElaine Zhang }
159a5a5ddb9SElaine Zhang
160a5a5ddb9SElaine Zhang return rate;
161a5a5ddb9SElaine Zhang }
162a5a5ddb9SElaine Zhang
rv1106_peri_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)163a5a5ddb9SElaine Zhang static ulong rv1106_peri_set_clk(struct rv1106_clk_priv *priv,
164a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
165a5a5ddb9SElaine Zhang {
166a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
167a5a5ddb9SElaine Zhang int src_clk;
168a5a5ddb9SElaine Zhang
169a5a5ddb9SElaine Zhang switch (clk_id) {
170a5a5ddb9SElaine Zhang case ACLK_PERI_ROOT:
171a5a5ddb9SElaine Zhang if (rate >= 396 * MHz)
172a5a5ddb9SElaine Zhang src_clk = ACLK_PERI_SEL_400M;
173a5a5ddb9SElaine Zhang else if (rate >= 198 * MHz)
174a5a5ddb9SElaine Zhang src_clk = ACLK_PERI_SEL_200M;
175a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
176a5a5ddb9SElaine Zhang src_clk = ACLK_PERI_SEL_100M;
177a5a5ddb9SElaine Zhang else
178a5a5ddb9SElaine Zhang src_clk = ACLK_PERI_SEL_24M;
179a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1],
180a5a5ddb9SElaine Zhang ACLK_PERI_SEL_MASK,
181a5a5ddb9SElaine Zhang src_clk << ACLK_PERI_SEL_SHIFT);
182a5a5ddb9SElaine Zhang break;
183a5a5ddb9SElaine Zhang case HCLK_PERI_ROOT:
184a5a5ddb9SElaine Zhang if (rate >= 198 * MHz)
185a5a5ddb9SElaine Zhang src_clk = HCLK_PERI_SEL_200M;
186a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
187a5a5ddb9SElaine Zhang src_clk = HCLK_PERI_SEL_100M;
188a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
189a5a5ddb9SElaine Zhang src_clk = HCLK_PERI_SEL_50M;
190a5a5ddb9SElaine Zhang else
191a5a5ddb9SElaine Zhang src_clk = HCLK_PERI_SEL_24M;
192a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1],
193a5a5ddb9SElaine Zhang HCLK_PERI_SEL_MASK,
194a5a5ddb9SElaine Zhang src_clk << HCLK_PERI_SEL_SHIFT);
195a5a5ddb9SElaine Zhang break;
196a5a5ddb9SElaine Zhang case PCLK_PERI_ROOT:
197a5a5ddb9SElaine Zhang if (rate >= 99 * MHz)
198a5a5ddb9SElaine Zhang src_clk = PCLK_PERI_SEL_100M;
199a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
200a5a5ddb9SElaine Zhang src_clk = PCLK_PERI_SEL_50M;
201a5a5ddb9SElaine Zhang else
202a5a5ddb9SElaine Zhang src_clk = PCLK_PERI_SEL_24M;
203a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1],
204a5a5ddb9SElaine Zhang PCLK_PERI_SEL_MASK,
205a5a5ddb9SElaine Zhang src_clk << PCLK_PERI_SEL_SHIFT);
206a5a5ddb9SElaine Zhang break;
207a5a5ddb9SElaine Zhang case ACLK_BUS_ROOT:
208a5a5ddb9SElaine Zhang if (rate >= 297 * MHz)
209a5a5ddb9SElaine Zhang src_clk = ACLK_BUS_SEL_300M;
210a5a5ddb9SElaine Zhang else if (rate >= 198 * MHz)
211a5a5ddb9SElaine Zhang src_clk = ACLK_BUS_SEL_200M;
212a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
213a5a5ddb9SElaine Zhang src_clk = ACLK_BUS_SEL_100M;
214a5a5ddb9SElaine Zhang else
215a5a5ddb9SElaine Zhang src_clk = ACLK_BUS_SEL_24M;
216a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[9],
217a5a5ddb9SElaine Zhang ACLK_BUS_SEL_MASK,
218a5a5ddb9SElaine Zhang src_clk << ACLK_BUS_SEL_SHIFT);
219a5a5ddb9SElaine Zhang break;
220a5a5ddb9SElaine Zhang case PCLK_TOP_ROOT:
221a5a5ddb9SElaine Zhang if (rate >= 99 * MHz)
222a5a5ddb9SElaine Zhang src_clk = PCLK_TOP_SEL_100M;
223a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
224a5a5ddb9SElaine Zhang src_clk = PCLK_TOP_SEL_50M;
225a5a5ddb9SElaine Zhang else
226a5a5ddb9SElaine Zhang src_clk = PCLK_TOP_SEL_24M;
227a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->clksel_con[24],
228a5a5ddb9SElaine Zhang PCLK_TOP_SEL_MASK,
229a5a5ddb9SElaine Zhang src_clk << PCLK_TOP_SEL_SHIFT);
230a5a5ddb9SElaine Zhang break;
231a5a5ddb9SElaine Zhang case PCLK_PMU_ROOT:
232a5a5ddb9SElaine Zhang if (rate >= 99 * MHz)
233a5a5ddb9SElaine Zhang src_clk = PCLK_PMU_SEL_100M;
234a5a5ddb9SElaine Zhang else
235a5a5ddb9SElaine Zhang src_clk = PCLK_PMU_SEL_24M;
236a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->pmu_clksel_con[0],
237a5a5ddb9SElaine Zhang PCLK_PMU_SEL_MASK,
238a5a5ddb9SElaine Zhang src_clk << PCLK_PMU_SEL_SHIFT);
239a5a5ddb9SElaine Zhang break;
240a5a5ddb9SElaine Zhang case HCLK_PMU_ROOT:
241a5a5ddb9SElaine Zhang if (rate >= 198 * MHz)
242a5a5ddb9SElaine Zhang src_clk = HCLK_PMU_SEL_200M;
243a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
244a5a5ddb9SElaine Zhang src_clk = HCLK_PMU_SEL_100M;
245a5a5ddb9SElaine Zhang else
246a5a5ddb9SElaine Zhang src_clk = HCLK_PMU_SEL_24M;
247a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->pmu_clksel_con[0],
248a5a5ddb9SElaine Zhang HCLK_PMU_SEL_MASK,
249a5a5ddb9SElaine Zhang src_clk << HCLK_PMU_SEL_SHIFT);
250a5a5ddb9SElaine Zhang break;
251a5a5ddb9SElaine Zhang default:
252a5a5ddb9SElaine Zhang printf("do not support this permid freq\n");
253a5a5ddb9SElaine Zhang return -EINVAL;
254a5a5ddb9SElaine Zhang }
255a5a5ddb9SElaine Zhang
256a5a5ddb9SElaine Zhang return rv1106_peri_get_clk(priv, clk_id);
257a5a5ddb9SElaine Zhang }
258a5a5ddb9SElaine Zhang
rv1106_i2c_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)259a5a5ddb9SElaine Zhang static ulong rv1106_i2c_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
260a5a5ddb9SElaine Zhang {
261a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
262a5a5ddb9SElaine Zhang u32 sel, con;
263a5a5ddb9SElaine Zhang ulong rate;
264a5a5ddb9SElaine Zhang
265a5a5ddb9SElaine Zhang switch (clk_id) {
266a5a5ddb9SElaine Zhang case CLK_I2C1:
267a5a5ddb9SElaine Zhang con = readl(&cru->pmu_clksel_con[0]);
268a5a5ddb9SElaine Zhang sel = (con & CLK_I2C1_SEL_MASK) >> CLK_I2C1_SEL_SHIFT;
269a5a5ddb9SElaine Zhang if (sel == CLK_I2C1_SEL_200M)
270a5a5ddb9SElaine Zhang rate = 200 * MHz;
271a5a5ddb9SElaine Zhang else if (sel == CLK_I2C1_SEL_100M)
272a5a5ddb9SElaine Zhang rate = 100 * MHz;
273a5a5ddb9SElaine Zhang else if (sel == CLK_I2C1_SEL_24M)
274a5a5ddb9SElaine Zhang rate = OSC_HZ;
275a5a5ddb9SElaine Zhang else
276a5a5ddb9SElaine Zhang rate = 32768;
277a5a5ddb9SElaine Zhang return rate;
278a5a5ddb9SElaine Zhang case CLK_I2C0:
279a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
280a5a5ddb9SElaine Zhang sel = (con & CLK_I2C0_SEL_MASK) >> CLK_I2C0_SEL_SHIFT;
281a5a5ddb9SElaine Zhang break;
282a5a5ddb9SElaine Zhang case CLK_I2C2:
283a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
284a5a5ddb9SElaine Zhang sel = (con & CLK_I2C2_SEL_MASK) >> CLK_I2C2_SEL_SHIFT;
285a5a5ddb9SElaine Zhang break;
286a5a5ddb9SElaine Zhang case CLK_I2C3:
287a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[1]);
288a5a5ddb9SElaine Zhang sel = (con & CLK_I2C3_SEL_MASK) >> CLK_I2C3_SEL_SHIFT;
289a5a5ddb9SElaine Zhang break;
290a5a5ddb9SElaine Zhang case CLK_I2C4:
291a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[2]);
292a5a5ddb9SElaine Zhang sel = (con & CLK_I2C4_SEL_MASK) >> CLK_I2C4_SEL_SHIFT;
293a5a5ddb9SElaine Zhang break;
294a5a5ddb9SElaine Zhang default:
295a5a5ddb9SElaine Zhang return -ENOENT;
296a5a5ddb9SElaine Zhang }
297a5a5ddb9SElaine Zhang
298a5a5ddb9SElaine Zhang if (sel == CLK_I2C0_SEL_200M)
299a5a5ddb9SElaine Zhang rate = 200 * MHz;
300a5a5ddb9SElaine Zhang else if (sel == CLK_I2C0_SEL_100M)
301a5a5ddb9SElaine Zhang rate = 100 * MHz;
302a5a5ddb9SElaine Zhang else if (sel == CLK_I2C0_SEL_50M)
303a5a5ddb9SElaine Zhang rate = 50 * MHz;
304a5a5ddb9SElaine Zhang else
305a5a5ddb9SElaine Zhang rate = OSC_HZ;
306a5a5ddb9SElaine Zhang
307a5a5ddb9SElaine Zhang return rate;
308a5a5ddb9SElaine Zhang }
3097d793375SElaine Zhang #endif
310a5a5ddb9SElaine Zhang
rv1106_crypto_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)311a5a5ddb9SElaine Zhang static ulong rv1106_crypto_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
312a5a5ddb9SElaine Zhang {
313a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
314a5a5ddb9SElaine Zhang u32 sel, con;
315a5a5ddb9SElaine Zhang
316a5a5ddb9SElaine Zhang switch (clk_id) {
317a5a5ddb9SElaine Zhang case CLK_CORE_CRYPTO:
318a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
319a5a5ddb9SElaine Zhang sel = (con & CLK_CORE_CRYPTO_SEL_MASK) >>
320a5a5ddb9SElaine Zhang CLK_CORE_CRYPTO_SEL_SHIFT;
321a5a5ddb9SElaine Zhang break;
322a5a5ddb9SElaine Zhang case CLK_PKA_CRYPTO:
323a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
324a5a5ddb9SElaine Zhang sel = (con & CLK_PKA_CRYPTO_SEL_MASK) >>
325a5a5ddb9SElaine Zhang CLK_PKA_CRYPTO_SEL_SHIFT;
326a5a5ddb9SElaine Zhang break;
327a5a5ddb9SElaine Zhang default:
328a5a5ddb9SElaine Zhang return -ENOENT;
329a5a5ddb9SElaine Zhang }
330a5a5ddb9SElaine Zhang switch (sel) {
331a5a5ddb9SElaine Zhang case CLK_CRYPTO_SEL_300M:
332a5a5ddb9SElaine Zhang return 300 * MHz;
333a5a5ddb9SElaine Zhang case CLK_CRYPTO_SEL_200M:
334a5a5ddb9SElaine Zhang return 200 * MHz;
335a5a5ddb9SElaine Zhang case CLK_CRYPTO_SEL_100M:
336a5a5ddb9SElaine Zhang return 100 * MHz;
337a5a5ddb9SElaine Zhang case CLK_CRYPTO_SEL_24M:
338a5a5ddb9SElaine Zhang return OSC_HZ;
339a5a5ddb9SElaine Zhang default:
340a5a5ddb9SElaine Zhang return -ENOENT;
341a5a5ddb9SElaine Zhang }
342a5a5ddb9SElaine Zhang }
343a5a5ddb9SElaine Zhang
rv1106_crypto_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)344a5a5ddb9SElaine Zhang static ulong rv1106_crypto_set_clk(struct rv1106_clk_priv *priv,
345a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
346a5a5ddb9SElaine Zhang {
347a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
348a5a5ddb9SElaine Zhang u32 sel;
349a5a5ddb9SElaine Zhang
350a5a5ddb9SElaine Zhang if (rate >= 297 * MHz)
351a5a5ddb9SElaine Zhang sel = CLK_CRYPTO_SEL_300M;
352a5a5ddb9SElaine Zhang else if (rate >= 198 * MHz)
353a5a5ddb9SElaine Zhang sel = CLK_CRYPTO_SEL_200M;
354a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
355a5a5ddb9SElaine Zhang sel = CLK_CRYPTO_SEL_100M;
356a5a5ddb9SElaine Zhang else
357a5a5ddb9SElaine Zhang sel = CLK_CRYPTO_SEL_24M;
358a5a5ddb9SElaine Zhang
359a5a5ddb9SElaine Zhang switch (clk_id) {
360a5a5ddb9SElaine Zhang case CLK_CORE_CRYPTO:
361a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6],
362a5a5ddb9SElaine Zhang CLK_CORE_CRYPTO_SEL_MASK,
363a5a5ddb9SElaine Zhang sel << CLK_CORE_CRYPTO_SEL_SHIFT);
364a5a5ddb9SElaine Zhang break;
365a5a5ddb9SElaine Zhang case CLK_PKA_CRYPTO:
366a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6],
367a5a5ddb9SElaine Zhang CLK_PKA_CRYPTO_SEL_MASK,
368a5a5ddb9SElaine Zhang sel << CLK_PKA_CRYPTO_SEL_SHIFT);
369a5a5ddb9SElaine Zhang break;
370a5a5ddb9SElaine Zhang default:
371a5a5ddb9SElaine Zhang return -ENOENT;
372a5a5ddb9SElaine Zhang }
373a5a5ddb9SElaine Zhang return rv1106_crypto_get_clk(priv, clk_id);
374a5a5ddb9SElaine Zhang }
375a5a5ddb9SElaine Zhang
rv1106_mmc_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)376a5a5ddb9SElaine Zhang static ulong rv1106_mmc_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
377a5a5ddb9SElaine Zhang {
378a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
379a5a5ddb9SElaine Zhang u32 div, sel, con, prate;
380a5a5ddb9SElaine Zhang
381a5a5ddb9SElaine Zhang switch (clk_id) {
382a5a5ddb9SElaine Zhang case CCLK_SRC_SDMMC:
383a5a5ddb9SElaine Zhang case HCLK_SDMMC:
384a5a5ddb9SElaine Zhang con = readl(&cru->vi_clksel_con[1]);
385a5a5ddb9SElaine Zhang sel = (con & CLK_SDMMC_SEL_MASK) >>
386a5a5ddb9SElaine Zhang CLK_SDMMC_SEL_SHIFT;
387a5a5ddb9SElaine Zhang div = (con & CLK_SDMMC_DIV_MASK) >>
388a5a5ddb9SElaine Zhang CLK_SDMMC_DIV_SHIFT;
389a5a5ddb9SElaine Zhang if (sel == CLK_MMC_SEL_400M)
390a5a5ddb9SElaine Zhang prate = 400 * MHz;
391a5a5ddb9SElaine Zhang else
392a5a5ddb9SElaine Zhang prate = OSC_HZ;
393a5a5ddb9SElaine Zhang return DIV_TO_RATE(prate, div);
394a5a5ddb9SElaine Zhang case CCLK_SRC_EMMC:
395a5a5ddb9SElaine Zhang case HCLK_EMMC:
396a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[7]);
397a5a5ddb9SElaine Zhang sel = (con & CLK_EMMC_SEL_MASK) >>
398a5a5ddb9SElaine Zhang CLK_EMMC_SEL_SHIFT;
399a5a5ddb9SElaine Zhang div = (con & CLK_EMMC_DIV_MASK) >>
400a5a5ddb9SElaine Zhang CLK_EMMC_DIV_SHIFT;
401a5a5ddb9SElaine Zhang if (sel)
402a5a5ddb9SElaine Zhang prate = OSC_HZ;
403a5a5ddb9SElaine Zhang else
404a5a5ddb9SElaine Zhang prate = 400 * MHz;
405a5a5ddb9SElaine Zhang return DIV_TO_RATE(prate, div);
406a5a5ddb9SElaine Zhang case SCLK_SFC:
407a5a5ddb9SElaine Zhang case HCLK_SFC:
408a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[7]);
409a5a5ddb9SElaine Zhang sel = (con & CLK_SFC_SEL_MASK) >>
410a5a5ddb9SElaine Zhang CLK_SFC_SEL_SHIFT;
411a5a5ddb9SElaine Zhang div = (con & CLK_SFC_DIV_MASK) >>
412a5a5ddb9SElaine Zhang CLK_SFC_DIV_SHIFT;
413a5a5ddb9SElaine Zhang if (sel == CLK_SFC_SEL_500M)
414a5a5ddb9SElaine Zhang prate = 500 * MHz;
415a5a5ddb9SElaine Zhang else if (sel == CLK_SFC_SEL_300M)
416a5a5ddb9SElaine Zhang prate = 300 * MHz;
417a5a5ddb9SElaine Zhang else if (sel == CLK_SFC_SEL_200M)
418a5a5ddb9SElaine Zhang prate = 200 * MHz;
419a5a5ddb9SElaine Zhang else
420a5a5ddb9SElaine Zhang prate = OSC_HZ;
421a5a5ddb9SElaine Zhang return DIV_TO_RATE(prate, div);
422a5a5ddb9SElaine Zhang default:
423a5a5ddb9SElaine Zhang return -ENOENT;
424a5a5ddb9SElaine Zhang }
425a5a5ddb9SElaine Zhang }
426a5a5ddb9SElaine Zhang
rv1106_mmc_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)427a5a5ddb9SElaine Zhang static ulong rv1106_mmc_set_clk(struct rv1106_clk_priv *priv,
428a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
429a5a5ddb9SElaine Zhang {
430a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
431a5a5ddb9SElaine Zhang u32 sel, src_clk_div;
432a5a5ddb9SElaine Zhang ulong prate = 0;
433a5a5ddb9SElaine Zhang
434a5a5ddb9SElaine Zhang if ((OSC_HZ % rate) == 0) {
435a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_24M;
436a5a5ddb9SElaine Zhang prate = OSC_HZ;
437a5a5ddb9SElaine Zhang } else {
438a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_400M;
439a5a5ddb9SElaine Zhang prate = 400 * MHz;
440a5a5ddb9SElaine Zhang }
441a5a5ddb9SElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
442a5a5ddb9SElaine Zhang
443a5a5ddb9SElaine Zhang switch (clk_id) {
444a5a5ddb9SElaine Zhang case CCLK_SRC_SDMMC:
445a5a5ddb9SElaine Zhang case HCLK_SDMMC:
446a5a5ddb9SElaine Zhang if ((OSC_HZ % rate) == 0) {
447a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_24M;
448a5a5ddb9SElaine Zhang prate = OSC_HZ;
449a5a5ddb9SElaine Zhang } else {
450a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_400M;
451a5a5ddb9SElaine Zhang prate = 400 * MHz;
452a5a5ddb9SElaine Zhang }
453a5a5ddb9SElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
454a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->vi_clksel_con[1],
455a5a5ddb9SElaine Zhang CLK_SDMMC_SEL_MASK |
456a5a5ddb9SElaine Zhang CLK_SDMMC_DIV_MASK,
457a5a5ddb9SElaine Zhang (sel << CLK_SDMMC_SEL_SHIFT) |
458a5a5ddb9SElaine Zhang ((src_clk_div - 1) <<
459a5a5ddb9SElaine Zhang CLK_SDMMC_DIV_SHIFT));
460a5a5ddb9SElaine Zhang break;
461a5a5ddb9SElaine Zhang case CCLK_SRC_EMMC:
462a5a5ddb9SElaine Zhang case HCLK_EMMC:
463a5a5ddb9SElaine Zhang if ((OSC_HZ % rate) == 0) {
464a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_24M;
465a5a5ddb9SElaine Zhang prate = OSC_HZ;
466a5a5ddb9SElaine Zhang } else {
467a5a5ddb9SElaine Zhang sel = CLK_MMC_SEL_400M;
468a5a5ddb9SElaine Zhang prate = 400 * MHz;
469a5a5ddb9SElaine Zhang }
470a5a5ddb9SElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
471a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[7],
472a5a5ddb9SElaine Zhang CLK_EMMC_SEL_MASK |
473a5a5ddb9SElaine Zhang CLK_EMMC_DIV_MASK,
474a5a5ddb9SElaine Zhang (sel << CLK_EMMC_SEL_SHIFT) |
475a5a5ddb9SElaine Zhang ((src_clk_div - 1) <<
476a5a5ddb9SElaine Zhang CLK_EMMC_DIV_SHIFT));
477a5a5ddb9SElaine Zhang break;
478a5a5ddb9SElaine Zhang case SCLK_SFC:
479a5a5ddb9SElaine Zhang case HCLK_SFC:
480a5a5ddb9SElaine Zhang if ((OSC_HZ % rate) == 0) {
481a5a5ddb9SElaine Zhang sel = CLK_SFC_SEL_24M;
482a5a5ddb9SElaine Zhang prate = OSC_HZ;
483a5a5ddb9SElaine Zhang } else if ((500 * MHz % rate) == 0) {
484a5a5ddb9SElaine Zhang sel = CLK_SFC_SEL_500M;
485a5a5ddb9SElaine Zhang prate = 500 * MHz;
486a5a5ddb9SElaine Zhang } else if ((300 * MHz % rate) == 0) {
487a5a5ddb9SElaine Zhang sel = CLK_SFC_SEL_300M;
488a5a5ddb9SElaine Zhang prate = 300 * MHz;
489a5a5ddb9SElaine Zhang } else {
490a5a5ddb9SElaine Zhang sel = CLK_SFC_SEL_200M;
491a5a5ddb9SElaine Zhang prate = 200 * MHz;
492a5a5ddb9SElaine Zhang }
493a5a5ddb9SElaine Zhang src_clk_div = DIV_ROUND_UP(prate, rate);
494a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[7],
495a5a5ddb9SElaine Zhang CLK_SFC_SEL_MASK |
496a5a5ddb9SElaine Zhang CLK_SFC_DIV_MASK,
497a5a5ddb9SElaine Zhang (sel << CLK_SFC_SEL_SHIFT) |
498a5a5ddb9SElaine Zhang ((src_clk_div - 1) <<
499a5a5ddb9SElaine Zhang CLK_SFC_DIV_SHIFT));
500a5a5ddb9SElaine Zhang break;
501a5a5ddb9SElaine Zhang default:
502a5a5ddb9SElaine Zhang return -ENOENT;
503a5a5ddb9SElaine Zhang }
504a5a5ddb9SElaine Zhang return rv1106_mmc_get_clk(priv, clk_id);
505a5a5ddb9SElaine Zhang }
506a5a5ddb9SElaine Zhang
5077d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
rv1106_i2c_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)508a5a5ddb9SElaine Zhang static ulong rv1106_i2c_set_clk(struct rv1106_clk_priv *priv, ulong clk_id,
509a5a5ddb9SElaine Zhang ulong rate)
510a5a5ddb9SElaine Zhang {
511a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
512a5a5ddb9SElaine Zhang int src_clk;
513a5a5ddb9SElaine Zhang
514a5a5ddb9SElaine Zhang if (rate >= 198 * MHz)
515a5a5ddb9SElaine Zhang src_clk = CLK_I2C0_SEL_200M;
516a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
517a5a5ddb9SElaine Zhang src_clk = CLK_I2C0_SEL_100M;
518a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
519a5a5ddb9SElaine Zhang src_clk = CLK_I2C0_SEL_50M;
520a5a5ddb9SElaine Zhang else
521a5a5ddb9SElaine Zhang src_clk = CLK_I2C0_SEL_24M;
522a5a5ddb9SElaine Zhang
523a5a5ddb9SElaine Zhang switch (clk_id) {
524a5a5ddb9SElaine Zhang case CLK_I2C1:
525a5a5ddb9SElaine Zhang if (rate >= 198 * MHz)
526a5a5ddb9SElaine Zhang src_clk = CLK_I2C1_SEL_200M;
527a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
528a5a5ddb9SElaine Zhang src_clk = CLK_I2C1_SEL_100M;
529a5a5ddb9SElaine Zhang else if (rate >= 24 * MHz)
530a5a5ddb9SElaine Zhang src_clk = CLK_I2C1_SEL_24M;
531a5a5ddb9SElaine Zhang else
532a5a5ddb9SElaine Zhang src_clk = CLK_I2C1_SEL_32K;
533a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->clksel_con[71], CLK_I2C1_SEL_MASK,
534a5a5ddb9SElaine Zhang src_clk << CLK_I2C1_SEL_SHIFT);
535a5a5ddb9SElaine Zhang return rv1106_i2c_get_clk(priv, clk_id);
536a5a5ddb9SElaine Zhang case CLK_I2C0:
537a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1], CLK_I2C0_SEL_MASK,
538a5a5ddb9SElaine Zhang src_clk << CLK_I2C0_SEL_SHIFT);
539a5a5ddb9SElaine Zhang break;
540a5a5ddb9SElaine Zhang case CLK_I2C2:
541a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1], CLK_I2C2_SEL_MASK,
542a5a5ddb9SElaine Zhang src_clk << CLK_I2C2_SEL_SHIFT);
543a5a5ddb9SElaine Zhang break;
544a5a5ddb9SElaine Zhang case CLK_I2C3:
545a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[1], CLK_I2C3_SEL_MASK,
546a5a5ddb9SElaine Zhang src_clk << CLK_I2C3_SEL_SHIFT);
547a5a5ddb9SElaine Zhang break;
548a5a5ddb9SElaine Zhang case CLK_I2C4:
549a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[2], CLK_I2C4_SEL_MASK,
550a5a5ddb9SElaine Zhang src_clk << CLK_I2C4_SEL_SHIFT);
551a5a5ddb9SElaine Zhang break;
552a5a5ddb9SElaine Zhang default:
553a5a5ddb9SElaine Zhang return -ENOENT;
554a5a5ddb9SElaine Zhang }
555a5a5ddb9SElaine Zhang
556a5a5ddb9SElaine Zhang return rv1106_i2c_get_clk(priv, clk_id);
557a5a5ddb9SElaine Zhang }
5587d793375SElaine Zhang #endif
559a5a5ddb9SElaine Zhang
rv1106_spi_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)560a5a5ddb9SElaine Zhang static ulong rv1106_spi_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
561a5a5ddb9SElaine Zhang {
562a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
563a5a5ddb9SElaine Zhang u32 sel, con, rate;
564a5a5ddb9SElaine Zhang
565a5a5ddb9SElaine Zhang switch (clk_id) {
566a5a5ddb9SElaine Zhang case CLK_SPI0:
567a5a5ddb9SElaine Zhang con = readl(&cru->vepu_clksel_con[0]);
568a5a5ddb9SElaine Zhang sel = (con & CLK_SPI0_SEL_MASK) >> CLK_SPI0_SEL_SHIFT;
569a5a5ddb9SElaine Zhang break;
570a5a5ddb9SElaine Zhang case CLK_SPI1:
571a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
572a5a5ddb9SElaine Zhang sel = (con & CLK_SPI1_SEL_MASK) >> CLK_SPI1_SEL_SHIFT;
573a5a5ddb9SElaine Zhang break;
574a5a5ddb9SElaine Zhang default:
575a5a5ddb9SElaine Zhang return -ENOENT;
576a5a5ddb9SElaine Zhang }
577a5a5ddb9SElaine Zhang if (sel == CLK_SPI0_SEL_200M)
578a5a5ddb9SElaine Zhang rate = 200 * MHz;
579a5a5ddb9SElaine Zhang else if (sel == CLK_SPI0_SEL_100M)
580a5a5ddb9SElaine Zhang rate = 100 * MHz;
581a5a5ddb9SElaine Zhang else if (sel == CLK_SPI0_SEL_50M)
582a5a5ddb9SElaine Zhang rate = 50 * MHz;
583a5a5ddb9SElaine Zhang else
584a5a5ddb9SElaine Zhang rate = OSC_HZ;
585a5a5ddb9SElaine Zhang
586a5a5ddb9SElaine Zhang return rate;
587a5a5ddb9SElaine Zhang }
588a5a5ddb9SElaine Zhang
rv1106_spi_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)589a5a5ddb9SElaine Zhang static ulong rv1106_spi_set_clk(struct rv1106_clk_priv *priv,
590a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
591a5a5ddb9SElaine Zhang {
592a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
593a5a5ddb9SElaine Zhang int src_clk;
594a5a5ddb9SElaine Zhang
595a5a5ddb9SElaine Zhang if (rate >= 198 * MHz)
596a5a5ddb9SElaine Zhang src_clk = CLK_SPI0_SEL_200M;
597a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
598a5a5ddb9SElaine Zhang src_clk = CLK_SPI0_SEL_100M;
599a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
600a5a5ddb9SElaine Zhang src_clk = CLK_SPI0_SEL_50M;
601a5a5ddb9SElaine Zhang else
602a5a5ddb9SElaine Zhang src_clk = CLK_SPI0_SEL_24M;
603a5a5ddb9SElaine Zhang
604a5a5ddb9SElaine Zhang switch (clk_id) {
605a5a5ddb9SElaine Zhang case CLK_SPI0:
606a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->vepu_clksel_con[0], CLK_SPI0_SEL_MASK,
607a5a5ddb9SElaine Zhang src_clk << CLK_SPI0_SEL_SHIFT);
608a5a5ddb9SElaine Zhang break;
609a5a5ddb9SElaine Zhang case CLK_SPI1:
610a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6], CLK_SPI1_SEL_MASK,
611a5a5ddb9SElaine Zhang src_clk << CLK_SPI1_SEL_SHIFT);
612a5a5ddb9SElaine Zhang break;
613a5a5ddb9SElaine Zhang default:
614a5a5ddb9SElaine Zhang return -ENOENT;
615a5a5ddb9SElaine Zhang }
616a5a5ddb9SElaine Zhang
617a5a5ddb9SElaine Zhang return rv1106_spi_get_clk(priv, clk_id);
618a5a5ddb9SElaine Zhang }
619a5a5ddb9SElaine Zhang
6207d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
rv1106_pwm_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)621a5a5ddb9SElaine Zhang static ulong rv1106_pwm_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
622a5a5ddb9SElaine Zhang {
623a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
624a5a5ddb9SElaine Zhang u32 sel, con;
625a5a5ddb9SElaine Zhang
626a5a5ddb9SElaine Zhang switch (clk_id) {
627a5a5ddb9SElaine Zhang case CLK_PWM0_PERI:
628a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[11]);
629a5a5ddb9SElaine Zhang sel = (con & CLK_PWM0_SEL_MASK) >> CLK_PWM0_SEL_SHIFT;
630a5a5ddb9SElaine Zhang break;
631a5a5ddb9SElaine Zhang case CLK_PWM1_PERI:
632a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
633a5a5ddb9SElaine Zhang sel = (con & CLK_PWM1_SEL_MASK) >> CLK_PWM1_SEL_SHIFT;
634a5a5ddb9SElaine Zhang break;
635a5a5ddb9SElaine Zhang case CLK_PWM2_PERI:
636a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
637a5a5ddb9SElaine Zhang sel = (con & CLK_PWM2_SEL_MASK) >> CLK_PWM2_SEL_SHIFT;
638a5a5ddb9SElaine Zhang break;
639a5a5ddb9SElaine Zhang default:
640a5a5ddb9SElaine Zhang return -ENOENT;
641a5a5ddb9SElaine Zhang }
642a5a5ddb9SElaine Zhang
643a5a5ddb9SElaine Zhang switch (sel) {
644a5a5ddb9SElaine Zhang case CLK_PWM_SEL_100M:
645a5a5ddb9SElaine Zhang return 100 * MHz;
646a5a5ddb9SElaine Zhang case CLK_PWM_SEL_50M:
647a5a5ddb9SElaine Zhang return 100 * MHz;
648a5a5ddb9SElaine Zhang case CLK_PWM_SEL_24M:
649a5a5ddb9SElaine Zhang return OSC_HZ;
650a5a5ddb9SElaine Zhang default:
651a5a5ddb9SElaine Zhang return -ENOENT;
652a5a5ddb9SElaine Zhang }
653a5a5ddb9SElaine Zhang }
654a5a5ddb9SElaine Zhang
rv1106_pwm_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)655a5a5ddb9SElaine Zhang static ulong rv1106_pwm_set_clk(struct rv1106_clk_priv *priv,
656a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
657a5a5ddb9SElaine Zhang {
658a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
659a5a5ddb9SElaine Zhang int src_clk;
660a5a5ddb9SElaine Zhang
661a5a5ddb9SElaine Zhang if (rate >= 99 * MHz)
662a5a5ddb9SElaine Zhang src_clk = CLK_PWM_SEL_100M;
663a5a5ddb9SElaine Zhang else if (rate >= 48 * MHz)
664a5a5ddb9SElaine Zhang src_clk = CLK_PWM_SEL_50M;
665a5a5ddb9SElaine Zhang else
666a5a5ddb9SElaine Zhang src_clk = CLK_PWM_SEL_24M;
667a5a5ddb9SElaine Zhang
668a5a5ddb9SElaine Zhang switch (clk_id) {
669a5a5ddb9SElaine Zhang case CLK_PWM0_PERI:
670a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[11],
671a5a5ddb9SElaine Zhang CLK_PWM0_SEL_MASK,
672a5a5ddb9SElaine Zhang src_clk << CLK_PWM0_SEL_SHIFT);
673a5a5ddb9SElaine Zhang break;
674a5a5ddb9SElaine Zhang case CLK_PWM1_PERI:
675a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6],
676a5a5ddb9SElaine Zhang CLK_PWM1_SEL_MASK,
677a5a5ddb9SElaine Zhang src_clk << CLK_PWM1_SEL_SHIFT);
678a5a5ddb9SElaine Zhang break;
679a5a5ddb9SElaine Zhang case CLK_PWM2_PERI:
680a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6],
681a5a5ddb9SElaine Zhang CLK_PWM2_SEL_MASK,
682a5a5ddb9SElaine Zhang src_clk << CLK_PWM2_SEL_SHIFT);
683a5a5ddb9SElaine Zhang break;
684a5a5ddb9SElaine Zhang default:
685a5a5ddb9SElaine Zhang return -ENOENT;
686a5a5ddb9SElaine Zhang }
687a5a5ddb9SElaine Zhang
688a5a5ddb9SElaine Zhang return rv1106_pwm_get_clk(priv, clk_id);
689a5a5ddb9SElaine Zhang }
6907d793375SElaine Zhang #endif
691a5a5ddb9SElaine Zhang
rv1106_adc_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)692a5a5ddb9SElaine Zhang static ulong rv1106_adc_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
693a5a5ddb9SElaine Zhang {
694a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
695a5a5ddb9SElaine Zhang u32 div, con;
696a5a5ddb9SElaine Zhang
697a5a5ddb9SElaine Zhang switch (clk_id) {
698a5a5ddb9SElaine Zhang case CLK_SARADC:
699a5a5ddb9SElaine Zhang con = readl(&cru->peri_clksel_con[6]);
700a5a5ddb9SElaine Zhang div = (con & CLK_SARADC_DIV_MASK) >>
701a5a5ddb9SElaine Zhang CLK_SARADC_DIV_SHIFT;
702a5a5ddb9SElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
703a5a5ddb9SElaine Zhang case CLK_TSADC_TSEN:
704a5a5ddb9SElaine Zhang con = readl(&cru->vo_clksel_con[3]);
705a5a5ddb9SElaine Zhang div = (con & CLK_TSADC_TSEN_DIV_MASK) >>
706a5a5ddb9SElaine Zhang CLK_TSADC_TSEN_DIV_SHIFT;
707a5a5ddb9SElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
708a5a5ddb9SElaine Zhang case CLK_TSADC:
709a5a5ddb9SElaine Zhang con = readl(&cru->vo_clksel_con[3]);
710a5a5ddb9SElaine Zhang div = (con & CLK_TSADC_DIV_MASK) >> CLK_TSADC_DIV_SHIFT;
711a5a5ddb9SElaine Zhang return DIV_TO_RATE(OSC_HZ, div);
712a5a5ddb9SElaine Zhang default:
713a5a5ddb9SElaine Zhang return -ENOENT;
714a5a5ddb9SElaine Zhang }
715a5a5ddb9SElaine Zhang }
716a5a5ddb9SElaine Zhang
rv1106_adc_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)717a5a5ddb9SElaine Zhang static ulong rv1106_adc_set_clk(struct rv1106_clk_priv *priv,
718a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
719a5a5ddb9SElaine Zhang {
720a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
721a5a5ddb9SElaine Zhang int src_clk_div;
722a5a5ddb9SElaine Zhang
723a5a5ddb9SElaine Zhang src_clk_div = DIV_ROUND_UP(OSC_HZ, rate);
724a5a5ddb9SElaine Zhang
725a5a5ddb9SElaine Zhang switch (clk_id) {
726a5a5ddb9SElaine Zhang case CLK_SARADC:
727a5a5ddb9SElaine Zhang assert(src_clk_div - 1 <= 7);
728a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[6],
729a5a5ddb9SElaine Zhang CLK_SARADC_DIV_MASK,
730a5a5ddb9SElaine Zhang (src_clk_div - 1) <<
731b6f99becSElaine Zhang CLK_SARADC_DIV_SHIFT);
732a5a5ddb9SElaine Zhang break;
733a5a5ddb9SElaine Zhang case CLK_TSADC_TSEN:
734a5a5ddb9SElaine Zhang assert(src_clk_div - 1 <= 128);
735a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->vo_clksel_con[3],
736a5a5ddb9SElaine Zhang CLK_TSADC_TSEN_DIV_MASK,
737a5a5ddb9SElaine Zhang (src_clk_div - 1) <<
738a5a5ddb9SElaine Zhang CLK_TSADC_TSEN_DIV_SHIFT);
739a5a5ddb9SElaine Zhang break;
740a5a5ddb9SElaine Zhang case CLK_TSADC:
741a5a5ddb9SElaine Zhang assert(src_clk_div - 1 <= 128);
742a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->vo_clksel_con[3],
743a5a5ddb9SElaine Zhang CLK_TSADC_DIV_MASK,
744a5a5ddb9SElaine Zhang (src_clk_div - 1) <<
745a5a5ddb9SElaine Zhang CLK_TSADC_DIV_SHIFT);
746a5a5ddb9SElaine Zhang break;
747a5a5ddb9SElaine Zhang default:
748a5a5ddb9SElaine Zhang return -ENOENT;
749a5a5ddb9SElaine Zhang }
750a5a5ddb9SElaine Zhang return rv1106_adc_get_clk(priv, clk_id);
751a5a5ddb9SElaine Zhang }
752a5a5ddb9SElaine Zhang
7537d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
754a5a5ddb9SElaine Zhang /*
755a5a5ddb9SElaine Zhang *
756a5a5ddb9SElaine Zhang * rational_best_approximation(31415, 10000,
757a5a5ddb9SElaine Zhang * (1 << 8) - 1, (1 << 5) - 1, &n, &d);
758a5a5ddb9SElaine Zhang *
759a5a5ddb9SElaine Zhang * you may look at given_numerator as a fixed point number,
760a5a5ddb9SElaine Zhang * with the fractional part size described in given_denominator.
761a5a5ddb9SElaine Zhang *
762a5a5ddb9SElaine Zhang * for theoretical background, see:
763a5a5ddb9SElaine Zhang * http://en.wikipedia.org/wiki/Continued_fraction
764a5a5ddb9SElaine Zhang */
rational_best_approximation(unsigned long given_numerator,unsigned long given_denominator,unsigned long max_numerator,unsigned long max_denominator,unsigned long * best_numerator,unsigned long * best_denominator)765a5a5ddb9SElaine Zhang static void rational_best_approximation(unsigned long given_numerator,
766a5a5ddb9SElaine Zhang unsigned long given_denominator,
767a5a5ddb9SElaine Zhang unsigned long max_numerator,
768a5a5ddb9SElaine Zhang unsigned long max_denominator,
769a5a5ddb9SElaine Zhang unsigned long *best_numerator,
770a5a5ddb9SElaine Zhang unsigned long *best_denominator)
771a5a5ddb9SElaine Zhang {
772a5a5ddb9SElaine Zhang unsigned long n, d, n0, d0, n1, d1;
773a5a5ddb9SElaine Zhang
774a5a5ddb9SElaine Zhang n = given_numerator;
775a5a5ddb9SElaine Zhang d = given_denominator;
776a5a5ddb9SElaine Zhang n0 = 0;
777a5a5ddb9SElaine Zhang d1 = 0;
778a5a5ddb9SElaine Zhang n1 = 1;
779a5a5ddb9SElaine Zhang d0 = 1;
780a5a5ddb9SElaine Zhang for (;;) {
781a5a5ddb9SElaine Zhang unsigned long t, a;
782a5a5ddb9SElaine Zhang
783a5a5ddb9SElaine Zhang if (n1 > max_numerator || d1 > max_denominator) {
784a5a5ddb9SElaine Zhang n1 = n0;
785a5a5ddb9SElaine Zhang d1 = d0;
786a5a5ddb9SElaine Zhang break;
787a5a5ddb9SElaine Zhang }
788a5a5ddb9SElaine Zhang if (d == 0)
789a5a5ddb9SElaine Zhang break;
790a5a5ddb9SElaine Zhang t = d;
791a5a5ddb9SElaine Zhang a = n / d;
792a5a5ddb9SElaine Zhang d = n % d;
793a5a5ddb9SElaine Zhang n = t;
794a5a5ddb9SElaine Zhang t = n0 + a * n1;
795a5a5ddb9SElaine Zhang n0 = n1;
796a5a5ddb9SElaine Zhang n1 = t;
797a5a5ddb9SElaine Zhang t = d0 + a * d1;
798a5a5ddb9SElaine Zhang d0 = d1;
799a5a5ddb9SElaine Zhang d1 = t;
800a5a5ddb9SElaine Zhang }
801a5a5ddb9SElaine Zhang *best_numerator = n1;
802a5a5ddb9SElaine Zhang *best_denominator = d1;
803a5a5ddb9SElaine Zhang }
804a5a5ddb9SElaine Zhang
rv1106_uart_get_rate(struct rv1106_clk_priv * priv,ulong clk_id)805a5a5ddb9SElaine Zhang static ulong rv1106_uart_get_rate(struct rv1106_clk_priv *priv, ulong clk_id)
806a5a5ddb9SElaine Zhang {
807a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
808a5a5ddb9SElaine Zhang u32 reg, con, fracdiv, div, src, p_src, p_rate;
809a5a5ddb9SElaine Zhang unsigned long m, n;
810a5a5ddb9SElaine Zhang
811a5a5ddb9SElaine Zhang switch (clk_id) {
812a5a5ddb9SElaine Zhang case SCLK_UART0:
813a5a5ddb9SElaine Zhang reg = 5;
814a5a5ddb9SElaine Zhang break;
815a5a5ddb9SElaine Zhang case SCLK_UART1:
816a5a5ddb9SElaine Zhang reg = 7;
817a5a5ddb9SElaine Zhang break;
818a5a5ddb9SElaine Zhang case SCLK_UART2:
819a5a5ddb9SElaine Zhang reg = 9;
820a5a5ddb9SElaine Zhang break;
821a5a5ddb9SElaine Zhang case SCLK_UART3:
822a5a5ddb9SElaine Zhang reg = 11;
823a5a5ddb9SElaine Zhang break;
824a5a5ddb9SElaine Zhang case SCLK_UART4:
825a5a5ddb9SElaine Zhang reg = 13;
826a5a5ddb9SElaine Zhang break;
827a5a5ddb9SElaine Zhang case SCLK_UART5:
828a5a5ddb9SElaine Zhang reg = 15;
829a5a5ddb9SElaine Zhang break;
830a5a5ddb9SElaine Zhang default:
831a5a5ddb9SElaine Zhang return -ENOENT;
832a5a5ddb9SElaine Zhang }
833a5a5ddb9SElaine Zhang con = readl(&cru->clksel_con[reg + 2]);
834a5a5ddb9SElaine Zhang src = (con & CLK_UART_SEL_MASK) >> CLK_UART_SEL_SHIFT;
835a5a5ddb9SElaine Zhang con = readl(&cru->clksel_con[reg]);
836a5a5ddb9SElaine Zhang div = (con & CLK_UART_SRC_DIV_MASK) >> CLK_UART_SRC_DIV_SHIFT;
837a5a5ddb9SElaine Zhang p_src = (con & CLK_UART_SRC_SEL_MASK) >> CLK_UART_SRC_SEL_SHIFT;
838a5a5ddb9SElaine Zhang if (p_src == CLK_UART_SRC_SEL_GPLL)
839a5a5ddb9SElaine Zhang p_rate = priv->gpll_hz;
840a5a5ddb9SElaine Zhang else if (p_src == CLK_UART_SRC_SEL_CPLL)
841a5a5ddb9SElaine Zhang p_rate = priv->cpll_hz;
842a5a5ddb9SElaine Zhang else
843a5a5ddb9SElaine Zhang p_rate = 480000000;
844a5a5ddb9SElaine Zhang if (src == CLK_UART_SEL_SRC) {
845a5a5ddb9SElaine Zhang return DIV_TO_RATE(p_rate, div);
846a5a5ddb9SElaine Zhang } else if (src == CLK_UART_SEL_FRAC) {
847a5a5ddb9SElaine Zhang fracdiv = readl(&cru->clksel_con[reg + 1]);
848a5a5ddb9SElaine Zhang n = fracdiv & CLK_UART_FRAC_NUMERATOR_MASK;
849a5a5ddb9SElaine Zhang n >>= CLK_UART_FRAC_NUMERATOR_SHIFT;
850a5a5ddb9SElaine Zhang m = fracdiv & CLK_UART_FRAC_DENOMINATOR_MASK;
851a5a5ddb9SElaine Zhang m >>= CLK_UART_FRAC_DENOMINATOR_SHIFT;
852a5a5ddb9SElaine Zhang return DIV_TO_RATE(p_rate, div) * n / m;
853a5a5ddb9SElaine Zhang } else {
854a5a5ddb9SElaine Zhang return OSC_HZ;
855a5a5ddb9SElaine Zhang }
856a5a5ddb9SElaine Zhang }
857a5a5ddb9SElaine Zhang
rv1106_uart_set_rate(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)858a5a5ddb9SElaine Zhang static ulong rv1106_uart_set_rate(struct rv1106_clk_priv *priv,
859a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
860a5a5ddb9SElaine Zhang {
861a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
862a5a5ddb9SElaine Zhang u32 reg, clk_src, uart_src, div;
863a5a5ddb9SElaine Zhang unsigned long m = 0, n = 0, val;
864a5a5ddb9SElaine Zhang
865a5a5ddb9SElaine Zhang if (priv->gpll_hz % rate == 0) {
866a5a5ddb9SElaine Zhang clk_src = CLK_UART_SRC_SEL_GPLL;
867a5a5ddb9SElaine Zhang uart_src = CLK_UART_SEL_SRC;
868a5a5ddb9SElaine Zhang div = DIV_ROUND_UP(priv->gpll_hz, rate);
869a5a5ddb9SElaine Zhang } else if (priv->cpll_hz % rate == 0) {
870a5a5ddb9SElaine Zhang clk_src = CLK_UART_SRC_SEL_CPLL;
871a5a5ddb9SElaine Zhang uart_src = CLK_UART_SEL_SRC;
872a5a5ddb9SElaine Zhang div = DIV_ROUND_UP(priv->gpll_hz, rate);
873a5a5ddb9SElaine Zhang } else if (rate == OSC_HZ) {
874a5a5ddb9SElaine Zhang clk_src = CLK_UART_SRC_SEL_GPLL;
875a5a5ddb9SElaine Zhang uart_src = CLK_UART_SEL_XIN24M;
876a5a5ddb9SElaine Zhang div = 2;
877a5a5ddb9SElaine Zhang } else {
878a5a5ddb9SElaine Zhang clk_src = CLK_UART_SRC_SEL_GPLL;
879a5a5ddb9SElaine Zhang uart_src = CLK_UART_SEL_FRAC;
880a5a5ddb9SElaine Zhang div = 2;
881a5a5ddb9SElaine Zhang rational_best_approximation(rate, priv->gpll_hz / div,
882a5a5ddb9SElaine Zhang GENMASK(16 - 1, 0),
883a5a5ddb9SElaine Zhang GENMASK(16 - 1, 0),
884a5a5ddb9SElaine Zhang &m, &n);
885a5a5ddb9SElaine Zhang }
886a5a5ddb9SElaine Zhang
887a5a5ddb9SElaine Zhang switch (clk_id) {
888a5a5ddb9SElaine Zhang case SCLK_UART0:
889a5a5ddb9SElaine Zhang reg = 5;
890a5a5ddb9SElaine Zhang break;
891a5a5ddb9SElaine Zhang case SCLK_UART1:
892a5a5ddb9SElaine Zhang reg = 7;
893a5a5ddb9SElaine Zhang break;
894a5a5ddb9SElaine Zhang case SCLK_UART2:
895a5a5ddb9SElaine Zhang reg = 9;
896a5a5ddb9SElaine Zhang break;
897a5a5ddb9SElaine Zhang case SCLK_UART3:
898a5a5ddb9SElaine Zhang reg = 11;
899a5a5ddb9SElaine Zhang break;
900a5a5ddb9SElaine Zhang case SCLK_UART4:
901a5a5ddb9SElaine Zhang reg = 13;
902a5a5ddb9SElaine Zhang break;
903a5a5ddb9SElaine Zhang case SCLK_UART5:
904a5a5ddb9SElaine Zhang reg = 15;
905a5a5ddb9SElaine Zhang break;
906a5a5ddb9SElaine Zhang default:
907a5a5ddb9SElaine Zhang return -ENOENT;
908a5a5ddb9SElaine Zhang }
909a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->clksel_con[reg],
910a5a5ddb9SElaine Zhang CLK_UART_SRC_SEL_MASK |
911a5a5ddb9SElaine Zhang CLK_UART_SRC_DIV_MASK,
912a5a5ddb9SElaine Zhang (clk_src << CLK_UART_SRC_SEL_SHIFT) |
913a5a5ddb9SElaine Zhang ((div - 1) << CLK_UART_SRC_DIV_SHIFT));
914a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->clksel_con[reg + 2],
915a5a5ddb9SElaine Zhang CLK_UART_SEL_MASK,
916a5a5ddb9SElaine Zhang uart_src << CLK_UART_SEL_SHIFT);
917a5a5ddb9SElaine Zhang if (m && n) {
918a5a5ddb9SElaine Zhang val = m << CLK_UART_FRAC_NUMERATOR_SHIFT | n;
919a5a5ddb9SElaine Zhang writel(val, &cru->clksel_con[reg + 1]);
920a5a5ddb9SElaine Zhang }
921a5a5ddb9SElaine Zhang
922a5a5ddb9SElaine Zhang return rv1106_uart_get_rate(priv, clk_id);
923a5a5ddb9SElaine Zhang }
924a5a5ddb9SElaine Zhang
rv1106_vop_get_clk(struct rv1106_clk_priv * priv,ulong clk_id)925a5a5ddb9SElaine Zhang static ulong rv1106_vop_get_clk(struct rv1106_clk_priv *priv, ulong clk_id)
926a5a5ddb9SElaine Zhang {
927a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
928a5a5ddb9SElaine Zhang u32 div, sel, con;
929a5a5ddb9SElaine Zhang
930a5a5ddb9SElaine Zhang switch (clk_id) {
931a5a5ddb9SElaine Zhang case ACLK_VOP_ROOT:
932a5a5ddb9SElaine Zhang case ACLK_VOP:
933a5a5ddb9SElaine Zhang con = readl(&cru->vo_clksel_con[1]);
934a5a5ddb9SElaine Zhang sel = (con & ACLK_VOP_SEL_MASK) >> ACLK_VOP_SEL_SHIFT;
935a5a5ddb9SElaine Zhang if (sel == ACLK_VOP_SEL_300M)
936a5a5ddb9SElaine Zhang return 300 * MHz;
937a5a5ddb9SElaine Zhang else if (sel == ACLK_VOP_SEL_200M)
938a5a5ddb9SElaine Zhang return 200 * MHz;
939a5a5ddb9SElaine Zhang else if (sel == ACLK_VOP_SEL_100M)
940a5a5ddb9SElaine Zhang return 100 * MHz;
941a5a5ddb9SElaine Zhang else
942a5a5ddb9SElaine Zhang return OSC_HZ;
943a5a5ddb9SElaine Zhang case DCLK_VOP_SRC:
944a5a5ddb9SElaine Zhang case DCLK_VOP:
945a5a5ddb9SElaine Zhang con = readl(&cru->clksel_con[23]);
946a5a5ddb9SElaine Zhang sel = (con & DCLK_VOP_SEL_MASK) >> DCLK_VOP_SEL_SHIFT;
947a5a5ddb9SElaine Zhang div = (con & DCLK_VOP_DIV_MASK) >> DCLK_VOP_DIV_SHIFT;
948a5a5ddb9SElaine Zhang if (sel == DCLK_VOP_SEL_GPLL)
949a5a5ddb9SElaine Zhang return DIV_TO_RATE(priv->gpll_hz, div);
950a5a5ddb9SElaine Zhang else
951a5a5ddb9SElaine Zhang return DIV_TO_RATE(priv->cpll_hz, div);
952a5a5ddb9SElaine Zhang default:
953a5a5ddb9SElaine Zhang return -ENOENT;
954a5a5ddb9SElaine Zhang }
955a5a5ddb9SElaine Zhang }
956a5a5ddb9SElaine Zhang
rv1106_vop_set_clk(struct rv1106_clk_priv * priv,ulong clk_id,ulong rate)957a5a5ddb9SElaine Zhang static ulong rv1106_vop_set_clk(struct rv1106_clk_priv *priv,
958a5a5ddb9SElaine Zhang ulong clk_id, ulong rate)
959a5a5ddb9SElaine Zhang {
960a5a5ddb9SElaine Zhang struct rv1106_cru *cru = priv->cru;
961a5a5ddb9SElaine Zhang int div, sel;
962a5a5ddb9SElaine Zhang
963a5a5ddb9SElaine Zhang switch (clk_id) {
964a5a5ddb9SElaine Zhang case ACLK_VOP_ROOT:
965a5a5ddb9SElaine Zhang case ACLK_VOP:
966a5a5ddb9SElaine Zhang if (rate >= 297 * MHz)
967a5a5ddb9SElaine Zhang sel = ACLK_VOP_SEL_300M;
968a5a5ddb9SElaine Zhang else if (rate >= 198 * MHz)
969a5a5ddb9SElaine Zhang sel = ACLK_VOP_SEL_200M;
970a5a5ddb9SElaine Zhang else if (rate >= 99 * MHz)
971a5a5ddb9SElaine Zhang sel = ACLK_VOP_SEL_100M;
972a5a5ddb9SElaine Zhang else
973a5a5ddb9SElaine Zhang sel = ACLK_VOP_SEL_24M;
974a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->vo_clksel_con[1],
975a5a5ddb9SElaine Zhang ACLK_VOP_SEL_MASK,
976a5a5ddb9SElaine Zhang sel << ACLK_VOP_SEL_SHIFT);
977a5a5ddb9SElaine Zhang break;
978a5a5ddb9SElaine Zhang case DCLK_VOP_SRC:
979a5a5ddb9SElaine Zhang case DCLK_VOP:
980a5a5ddb9SElaine Zhang if ((priv->cpll_hz % rate) == 0) {
981a5a5ddb9SElaine Zhang sel = DCLK_VOP_SEL_CPLL;
982a5a5ddb9SElaine Zhang div = DIV_ROUND_UP(priv->cpll_hz, rate);
983a5a5ddb9SElaine Zhang } else {
984a5a5ddb9SElaine Zhang sel = DCLK_VOP_SEL_GPLL;
985a5a5ddb9SElaine Zhang div = DIV_ROUND_UP(priv->gpll_hz, rate);
986a5a5ddb9SElaine Zhang }
987a5a5ddb9SElaine Zhang rk_clrsetreg(&cru->clksel_con[23],
988a5a5ddb9SElaine Zhang DCLK_VOP_SEL_MASK |
989a5a5ddb9SElaine Zhang DCLK_VOP_DIV_MASK,
990a5a5ddb9SElaine Zhang sel << DCLK_VOP_SEL_SHIFT |
991a5a5ddb9SElaine Zhang (div - 1) << DCLK_VOP_DIV_SHIFT);
992a5a5ddb9SElaine Zhang break;
993a5a5ddb9SElaine Zhang default:
994a5a5ddb9SElaine Zhang return -ENOENT;
995a5a5ddb9SElaine Zhang }
996a5a5ddb9SElaine Zhang
997a5a5ddb9SElaine Zhang return rv1106_vop_get_clk(priv, clk_id);
998a5a5ddb9SElaine Zhang }
999b81ef8b2SElaine Zhang
rv1106_decom_get_clk(struct rv1106_clk_priv * priv)1000b81ef8b2SElaine Zhang static ulong rv1106_decom_get_clk(struct rv1106_clk_priv *priv)
1001b81ef8b2SElaine Zhang {
1002b81ef8b2SElaine Zhang struct rv1106_cru *cru = priv->cru;
1003b81ef8b2SElaine Zhang u32 sel, con, prate;
1004b81ef8b2SElaine Zhang
1005b81ef8b2SElaine Zhang con = readl(&cru->peri_clksel_con[7]);
1006b81ef8b2SElaine Zhang sel = (con & DCLK_DECOM_SEL_MASK) >>
1007b81ef8b2SElaine Zhang DCLK_DECOM_SEL_SHIFT;
1008b81ef8b2SElaine Zhang if (sel == DCLK_DECOM_SEL_400M)
1009b81ef8b2SElaine Zhang prate = 400 * MHz;
1010b81ef8b2SElaine Zhang else if (sel == DCLK_DECOM_SEL_200M)
1011b81ef8b2SElaine Zhang prate = 200 * MHz;
1012b81ef8b2SElaine Zhang else if (sel == DCLK_DECOM_SEL_100M)
1013b81ef8b2SElaine Zhang prate = 100 * MHz;
1014b81ef8b2SElaine Zhang else
1015b81ef8b2SElaine Zhang prate = OSC_HZ;
1016b81ef8b2SElaine Zhang return prate;
1017b81ef8b2SElaine Zhang }
1018b81ef8b2SElaine Zhang
rv1106_decom_set_clk(struct rv1106_clk_priv * priv,ulong rate)1019b81ef8b2SElaine Zhang static ulong rv1106_decom_set_clk(struct rv1106_clk_priv *priv, ulong rate)
1020b81ef8b2SElaine Zhang {
1021b81ef8b2SElaine Zhang struct rv1106_cru *cru = priv->cru;
1022b81ef8b2SElaine Zhang u32 sel;
1023b81ef8b2SElaine Zhang
1024b81ef8b2SElaine Zhang if (rate >= 396 * MHz)
1025b81ef8b2SElaine Zhang sel = DCLK_DECOM_SEL_400M;
1026b81ef8b2SElaine Zhang else if (rate >= 198 * MHz)
1027b81ef8b2SElaine Zhang sel = DCLK_DECOM_SEL_200M;
1028b81ef8b2SElaine Zhang else if (rate >= 99 * MHz)
1029b81ef8b2SElaine Zhang sel = DCLK_DECOM_SEL_100M;
1030b81ef8b2SElaine Zhang else
1031b81ef8b2SElaine Zhang sel = DCLK_DECOM_SEL_24M;
1032b81ef8b2SElaine Zhang rk_clrsetreg(&cru->peri_clksel_con[7], DCLK_DECOM_SEL_MASK,
1033b81ef8b2SElaine Zhang (sel << DCLK_DECOM_SEL_SHIFT));
1034b81ef8b2SElaine Zhang
1035b81ef8b2SElaine Zhang return rv1106_decom_get_clk(priv);
1036b81ef8b2SElaine Zhang }
10377d793375SElaine Zhang #endif
1038a5a5ddb9SElaine Zhang
rv1106_clk_get_rate(struct clk * clk)1039a5a5ddb9SElaine Zhang static ulong rv1106_clk_get_rate(struct clk *clk)
1040a5a5ddb9SElaine Zhang {
1041a5a5ddb9SElaine Zhang struct rv1106_clk_priv *priv = dev_get_priv(clk->dev);
1042a5a5ddb9SElaine Zhang ulong rate = 0;
1043a5a5ddb9SElaine Zhang
1044a5a5ddb9SElaine Zhang if (!priv->gpll_hz) {
1045a5a5ddb9SElaine Zhang printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1046a5a5ddb9SElaine Zhang return -ENOENT;
1047a5a5ddb9SElaine Zhang }
1048a5a5ddb9SElaine Zhang
1049a5a5ddb9SElaine Zhang switch (clk->id) {
10507d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1051a5a5ddb9SElaine Zhang case PLL_APLL:
1052a5a5ddb9SElaine Zhang rate = rockchip_pll_get_rate(&rv1106_pll_clks[APLL], priv->cru,
1053a5a5ddb9SElaine Zhang APLL);
1054a5a5ddb9SElaine Zhang break;
10550d5d7ee2SElaine Zhang case PLL_DPLL:
10560d5d7ee2SElaine Zhang rate = rockchip_pll_get_rate(&rv1106_pll_clks[DPLL], priv->cru,
10570d5d7ee2SElaine Zhang DPLL);
10580d5d7ee2SElaine Zhang break;
1059a5a5ddb9SElaine Zhang case PLL_CPLL:
1060a5a5ddb9SElaine Zhang rate = rockchip_pll_get_rate(&rv1106_pll_clks[CPLL], priv->cru,
1061a5a5ddb9SElaine Zhang CPLL);
1062a5a5ddb9SElaine Zhang break;
1063a5a5ddb9SElaine Zhang case PLL_GPLL:
1064a5a5ddb9SElaine Zhang rate = rockchip_pll_get_rate(&rv1106_pll_clks[GPLL], priv->cru,
1065a5a5ddb9SElaine Zhang GPLL);
1066a5a5ddb9SElaine Zhang break;
1067a5a5ddb9SElaine Zhang case ACLK_PERI_ROOT:
1068a5a5ddb9SElaine Zhang case HCLK_PERI_ROOT:
1069a5a5ddb9SElaine Zhang case PCLK_PERI_ROOT:
1070a5a5ddb9SElaine Zhang case ACLK_BUS_ROOT:
1071a5a5ddb9SElaine Zhang case PCLK_TOP_ROOT:
1072a5a5ddb9SElaine Zhang case PCLK_PMU_ROOT:
1073a5a5ddb9SElaine Zhang case HCLK_PMU_ROOT:
1074a5a5ddb9SElaine Zhang rate = rv1106_peri_get_clk(priv, clk->id);
1075a5a5ddb9SElaine Zhang break;
10767d793375SElaine Zhang #endif
1077a5a5ddb9SElaine Zhang case CLK_CORE_CRYPTO:
1078a5a5ddb9SElaine Zhang case CLK_PKA_CRYPTO:
1079a5a5ddb9SElaine Zhang case ACLK_CRYPTO:
1080a5a5ddb9SElaine Zhang rate = rv1106_crypto_get_clk(priv, clk->id);
1081a5a5ddb9SElaine Zhang break;
1082a5a5ddb9SElaine Zhang case CCLK_SRC_SDMMC:
1083a5a5ddb9SElaine Zhang case CCLK_SRC_EMMC:
1084a5a5ddb9SElaine Zhang case SCLK_SFC:
1085a5a5ddb9SElaine Zhang case HCLK_SDMMC:
1086a5a5ddb9SElaine Zhang case HCLK_EMMC:
1087a5a5ddb9SElaine Zhang case HCLK_SFC:
1088a5a5ddb9SElaine Zhang rate = rv1106_mmc_get_clk(priv, clk->id);
1089a5a5ddb9SElaine Zhang break;
10907d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1091a5a5ddb9SElaine Zhang case CLK_I2C0:
1092a5a5ddb9SElaine Zhang case CLK_I2C1:
1093a5a5ddb9SElaine Zhang case CLK_I2C2:
1094a5a5ddb9SElaine Zhang case CLK_I2C3:
1095a5a5ddb9SElaine Zhang case CLK_I2C4:
1096a5a5ddb9SElaine Zhang rate = rv1106_i2c_get_clk(priv, clk->id);
1097a5a5ddb9SElaine Zhang break;
10987d793375SElaine Zhang #endif
1099a5a5ddb9SElaine Zhang case CLK_SPI0:
1100a5a5ddb9SElaine Zhang case CLK_SPI1:
1101a5a5ddb9SElaine Zhang rate = rv1106_spi_get_clk(priv, clk->id);
1102a5a5ddb9SElaine Zhang break;
11037d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1104a5a5ddb9SElaine Zhang case CLK_PWM0_PERI:
1105a5a5ddb9SElaine Zhang case CLK_PWM1_PERI:
1106a5a5ddb9SElaine Zhang case CLK_PWM2_PERI:
1107a5a5ddb9SElaine Zhang rate = rv1106_pwm_get_clk(priv, clk->id);
1108a5a5ddb9SElaine Zhang break;
11097d793375SElaine Zhang #endif
1110a5a5ddb9SElaine Zhang case CLK_SARADC:
1111a5a5ddb9SElaine Zhang case CLK_TSADC_TSEN:
1112a5a5ddb9SElaine Zhang case CLK_TSADC:
1113a5a5ddb9SElaine Zhang rate = rv1106_adc_get_clk(priv, clk->id);
1114a5a5ddb9SElaine Zhang break;
11157d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1116a5a5ddb9SElaine Zhang case SCLK_UART0:
1117a5a5ddb9SElaine Zhang case SCLK_UART1:
1118a5a5ddb9SElaine Zhang case SCLK_UART2:
1119a5a5ddb9SElaine Zhang case SCLK_UART3:
1120a5a5ddb9SElaine Zhang case SCLK_UART4:
1121a5a5ddb9SElaine Zhang case SCLK_UART5:
1122a5a5ddb9SElaine Zhang rate = rv1106_uart_get_rate(priv, clk->id);
1123a5a5ddb9SElaine Zhang break;
1124a5a5ddb9SElaine Zhang case DCLK_VOP_SRC:
1125a5a5ddb9SElaine Zhang case DCLK_VOP:
1126a5a5ddb9SElaine Zhang case ACLK_VOP_ROOT:
1127a5a5ddb9SElaine Zhang case ACLK_VOP:
1128a5a5ddb9SElaine Zhang rate = rv1106_vop_get_clk(priv, clk->id);
1129a5a5ddb9SElaine Zhang break;
1130b81ef8b2SElaine Zhang case DCLK_DECOM:
1131b81ef8b2SElaine Zhang rate = rv1106_decom_get_clk(priv);
1132b81ef8b2SElaine Zhang break;
11337d793375SElaine Zhang #endif
1134*ffd915f0SZiyuan Xu case TCLK_WDT_NS:
1135*ffd915f0SZiyuan Xu rate = OSC_HZ;
1136*ffd915f0SZiyuan Xu break;
1137a5a5ddb9SElaine Zhang default:
1138a5a5ddb9SElaine Zhang return -ENOENT;
1139a5a5ddb9SElaine Zhang }
1140a5a5ddb9SElaine Zhang
1141a5a5ddb9SElaine Zhang return rate;
1142a5a5ddb9SElaine Zhang };
1143a5a5ddb9SElaine Zhang
rv1106_clk_set_rate(struct clk * clk,ulong rate)1144a5a5ddb9SElaine Zhang static ulong rv1106_clk_set_rate(struct clk *clk, ulong rate)
1145a5a5ddb9SElaine Zhang {
1146a5a5ddb9SElaine Zhang struct rv1106_clk_priv *priv = dev_get_priv(clk->dev);
1147a5a5ddb9SElaine Zhang ulong ret = 0;
1148a5a5ddb9SElaine Zhang
1149a5a5ddb9SElaine Zhang if (!priv->gpll_hz) {
1150a5a5ddb9SElaine Zhang printf("%s gpll=%lu\n", __func__, priv->gpll_hz);
1151a5a5ddb9SElaine Zhang return -ENOENT;
1152a5a5ddb9SElaine Zhang }
1153a5a5ddb9SElaine Zhang
1154a5a5ddb9SElaine Zhang switch (clk->id) {
11557d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1156a5a5ddb9SElaine Zhang case PLL_APLL:
1157a5a5ddb9SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[APLL], priv->cru,
1158a5a5ddb9SElaine Zhang APLL, rate);
1159a5a5ddb9SElaine Zhang break;
1160a5a5ddb9SElaine Zhang case PLL_CPLL:
1161a5a5ddb9SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[CPLL], priv->cru,
1162a5a5ddb9SElaine Zhang CPLL, rate);
1163a5a5ddb9SElaine Zhang break;
1164a5a5ddb9SElaine Zhang case PLL_GPLL:
1165a5a5ddb9SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[GPLL], priv->cru,
1166a5a5ddb9SElaine Zhang GPLL, rate);
1167a5a5ddb9SElaine Zhang break;
1168a5a5ddb9SElaine Zhang case ACLK_PERI_ROOT:
1169a5a5ddb9SElaine Zhang case HCLK_PERI_ROOT:
1170a5a5ddb9SElaine Zhang case PCLK_PERI_ROOT:
1171a5a5ddb9SElaine Zhang case ACLK_BUS_ROOT:
1172a5a5ddb9SElaine Zhang case PCLK_TOP_ROOT:
1173a5a5ddb9SElaine Zhang case PCLK_PMU_ROOT:
1174a5a5ddb9SElaine Zhang case HCLK_PMU_ROOT:
1175a5a5ddb9SElaine Zhang ret = rv1106_peri_set_clk(priv, clk->id, rate);
1176a5a5ddb9SElaine Zhang break;
11777d793375SElaine Zhang #endif
1178a5a5ddb9SElaine Zhang case CLK_CORE_CRYPTO:
1179a5a5ddb9SElaine Zhang case CLK_PKA_CRYPTO:
1180a5a5ddb9SElaine Zhang case ACLK_CRYPTO:
1181a5a5ddb9SElaine Zhang ret = rv1106_crypto_set_clk(priv, clk->id, rate);
1182a5a5ddb9SElaine Zhang break;
1183a5a5ddb9SElaine Zhang case CCLK_SRC_SDMMC:
1184a5a5ddb9SElaine Zhang case CCLK_SRC_EMMC:
1185a5a5ddb9SElaine Zhang case SCLK_SFC:
1186a5a5ddb9SElaine Zhang case HCLK_SDMMC:
1187a5a5ddb9SElaine Zhang case HCLK_EMMC:
1188a5a5ddb9SElaine Zhang case HCLK_SFC:
1189a5a5ddb9SElaine Zhang ret = rv1106_mmc_set_clk(priv, clk->id, rate);
1190a5a5ddb9SElaine Zhang break;
11917d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1192a5a5ddb9SElaine Zhang case CLK_I2C0:
1193a5a5ddb9SElaine Zhang case CLK_I2C1:
1194a5a5ddb9SElaine Zhang case CLK_I2C2:
1195a5a5ddb9SElaine Zhang case CLK_I2C3:
1196a5a5ddb9SElaine Zhang case CLK_I2C4:
1197a5a5ddb9SElaine Zhang ret = rv1106_i2c_set_clk(priv, clk->id, rate);
1198a5a5ddb9SElaine Zhang break;
11997d793375SElaine Zhang #endif
1200a5a5ddb9SElaine Zhang case CLK_SPI0:
1201a5a5ddb9SElaine Zhang case CLK_SPI1:
1202a5a5ddb9SElaine Zhang ret = rv1106_spi_set_clk(priv, clk->id, rate);
1203a5a5ddb9SElaine Zhang break;
12047d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1205a5a5ddb9SElaine Zhang case CLK_PWM0_PERI:
1206a5a5ddb9SElaine Zhang case CLK_PWM1_PERI:
1207a5a5ddb9SElaine Zhang case CLK_PWM2_PERI:
1208a5a5ddb9SElaine Zhang ret = rv1106_pwm_set_clk(priv, clk->id, rate);
1209a5a5ddb9SElaine Zhang break;
12107d793375SElaine Zhang #endif
1211a5a5ddb9SElaine Zhang case CLK_SARADC:
1212a5a5ddb9SElaine Zhang case CLK_TSADC_TSEN:
1213a5a5ddb9SElaine Zhang case CLK_TSADC:
1214a5a5ddb9SElaine Zhang ret = rv1106_adc_set_clk(priv, clk->id, rate);
1215a5a5ddb9SElaine Zhang break;
12167d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1217a5a5ddb9SElaine Zhang case SCLK_UART0:
1218a5a5ddb9SElaine Zhang case SCLK_UART1:
1219a5a5ddb9SElaine Zhang case SCLK_UART2:
1220a5a5ddb9SElaine Zhang case SCLK_UART3:
1221a5a5ddb9SElaine Zhang case SCLK_UART4:
1222a5a5ddb9SElaine Zhang case SCLK_UART5:
1223a5a5ddb9SElaine Zhang ret = rv1106_uart_set_rate(priv, clk->id, rate);
1224a5a5ddb9SElaine Zhang break;
1225a5a5ddb9SElaine Zhang case DCLK_VOP_SRC:
1226a5a5ddb9SElaine Zhang case DCLK_VOP:
1227a5a5ddb9SElaine Zhang case ACLK_VOP_ROOT:
1228a5a5ddb9SElaine Zhang case ACLK_VOP:
1229a5a5ddb9SElaine Zhang rate = rv1106_vop_set_clk(priv, clk->id, rate);
1230a5a5ddb9SElaine Zhang break;
1231b81ef8b2SElaine Zhang case DCLK_DECOM:
1232b81ef8b2SElaine Zhang rate = rv1106_decom_set_clk(priv, rate);
1233b81ef8b2SElaine Zhang break;
12347d793375SElaine Zhang #endif
1235a5a5ddb9SElaine Zhang default:
1236a5a5ddb9SElaine Zhang return -ENOENT;
1237a5a5ddb9SElaine Zhang }
1238a5a5ddb9SElaine Zhang
1239a5a5ddb9SElaine Zhang return ret;
1240a5a5ddb9SElaine Zhang };
1241a5a5ddb9SElaine Zhang
rv1106_clk_set_parent(struct clk * clk,struct clk * parent)1242a5a5ddb9SElaine Zhang static int rv1106_clk_set_parent(struct clk *clk, struct clk *parent)
1243a5a5ddb9SElaine Zhang {
1244a5a5ddb9SElaine Zhang switch (clk->id) {
1245a5a5ddb9SElaine Zhang default:
1246a5a5ddb9SElaine Zhang return -ENOENT;
1247a5a5ddb9SElaine Zhang }
1248a5a5ddb9SElaine Zhang
1249a5a5ddb9SElaine Zhang return 0;
1250a5a5ddb9SElaine Zhang }
1251a5a5ddb9SElaine Zhang
1252a5a5ddb9SElaine Zhang static struct clk_ops rv1106_clk_ops = {
1253a5a5ddb9SElaine Zhang .get_rate = rv1106_clk_get_rate,
1254a5a5ddb9SElaine Zhang .set_rate = rv1106_clk_set_rate,
1255a5a5ddb9SElaine Zhang #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
1256a5a5ddb9SElaine Zhang .set_parent = rv1106_clk_set_parent,
1257a5a5ddb9SElaine Zhang #endif
1258a5a5ddb9SElaine Zhang };
1259a5a5ddb9SElaine Zhang
12607d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
rv1106_clk_init(struct rv1106_clk_priv * priv)1261a5a5ddb9SElaine Zhang static void rv1106_clk_init(struct rv1106_clk_priv *priv)
1262a5a5ddb9SElaine Zhang {
1263a5a5ddb9SElaine Zhang int ret;
1264a5a5ddb9SElaine Zhang
1265a5a5ddb9SElaine Zhang priv->sync_kernel = false;
1266a5a5ddb9SElaine Zhang if (!priv->armclk_enter_hz) {
1267a5a5ddb9SElaine Zhang priv->armclk_enter_hz =
1268a5a5ddb9SElaine Zhang rockchip_pll_get_rate(&rv1106_pll_clks[APLL],
1269a5a5ddb9SElaine Zhang priv->cru, APLL);
1270a5a5ddb9SElaine Zhang priv->armclk_init_hz = priv->armclk_enter_hz;
1271a5a5ddb9SElaine Zhang }
1272a5a5ddb9SElaine Zhang
12730d5d7ee2SElaine Zhang if (priv->armclk_init_hz != APLL_HZ) {
12740d5d7ee2SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[APLL], priv->cru,
12750d5d7ee2SElaine Zhang APLL, APLL_HZ);
12760d5d7ee2SElaine Zhang if (!ret)
12770d5d7ee2SElaine Zhang priv->armclk_init_hz = APLL_HZ;
12780d5d7ee2SElaine Zhang }
12790d5d7ee2SElaine Zhang
1280a5a5ddb9SElaine Zhang if (priv->cpll_hz != CPLL_HZ) {
1281a5a5ddb9SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[CPLL], priv->cru,
1282a5a5ddb9SElaine Zhang CPLL, CPLL_HZ);
1283a5a5ddb9SElaine Zhang if (!ret)
1284a5a5ddb9SElaine Zhang priv->cpll_hz = CPLL_HZ;
1285a5a5ddb9SElaine Zhang }
1286a5a5ddb9SElaine Zhang
1287a5a5ddb9SElaine Zhang if (priv->gpll_hz != GPLL_HZ) {
1288a5a5ddb9SElaine Zhang ret = rockchip_pll_set_rate(&rv1106_pll_clks[GPLL], priv->cru,
1289a5a5ddb9SElaine Zhang GPLL, GPLL_HZ);
1290a5a5ddb9SElaine Zhang if (!ret)
1291a5a5ddb9SElaine Zhang priv->gpll_hz = GPLL_HZ;
1292a5a5ddb9SElaine Zhang }
1293a5a5ddb9SElaine Zhang }
12947d793375SElaine Zhang #endif
1295a5a5ddb9SElaine Zhang
rv1106_clk_probe(struct udevice * dev)1296a5a5ddb9SElaine Zhang static int rv1106_clk_probe(struct udevice *dev)
1297a5a5ddb9SElaine Zhang {
1298a5a5ddb9SElaine Zhang struct rv1106_clk_priv *priv = dev_get_priv(dev);
12997d793375SElaine Zhang #ifndef CONFIG_ROCKCHIP_IMAGE_TINY
1300a5a5ddb9SElaine Zhang int ret;
1301a5a5ddb9SElaine Zhang
1302a5a5ddb9SElaine Zhang rv1106_clk_init(priv);
1303a5a5ddb9SElaine Zhang
1304a5a5ddb9SElaine Zhang /* Process 'assigned-{clocks/clock-parents/clock-rates}' properties */
1305a5a5ddb9SElaine Zhang ret = clk_set_defaults(dev);
1306a5a5ddb9SElaine Zhang if (ret)
1307a5a5ddb9SElaine Zhang debug("%s clk_set_defaults failed %d\n", __func__, ret);
1308a5a5ddb9SElaine Zhang else
1309a5a5ddb9SElaine Zhang priv->sync_kernel = true;
13107d793375SElaine Zhang #else
13117d793375SElaine Zhang priv->gpll_hz = GPLL_HZ;
13127d793375SElaine Zhang priv->cpll_hz = CPLL_HZ;
13137d793375SElaine Zhang #endif
131475bf999aSElaine Zhang rk_clrsetreg(&priv->cru->core_clksel_con[0],
131575bf999aSElaine Zhang CLK_CORE_DIV_MASK,
131675bf999aSElaine Zhang 0 << CLK_CORE_DIV_SHIFT);
13176bd560f3SJason Zhu
13186bd560f3SJason Zhu #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_KERNEL_BOOT)
13196bd560f3SJason Zhu /* increase the aclk_decom frequency */
13206bd560f3SJason Zhu rv1106_peri_set_clk(priv, ACLK_PERI_ROOT, 400 * MHz);
13216bd560f3SJason Zhu #endif
1322a5a5ddb9SElaine Zhang return 0;
1323a5a5ddb9SElaine Zhang }
1324a5a5ddb9SElaine Zhang
rv1106_clk_ofdata_to_platdata(struct udevice * dev)1325a5a5ddb9SElaine Zhang static int rv1106_clk_ofdata_to_platdata(struct udevice *dev)
1326a5a5ddb9SElaine Zhang {
1327a5a5ddb9SElaine Zhang struct rv1106_clk_priv *priv = dev_get_priv(dev);
1328a5a5ddb9SElaine Zhang
1329a5a5ddb9SElaine Zhang priv->cru = dev_read_addr_ptr(dev);
1330a5a5ddb9SElaine Zhang
1331a5a5ddb9SElaine Zhang return 0;
1332a5a5ddb9SElaine Zhang }
1333a5a5ddb9SElaine Zhang
rv1106_clk_bind(struct udevice * dev)1334a5a5ddb9SElaine Zhang static int rv1106_clk_bind(struct udevice *dev)
1335a5a5ddb9SElaine Zhang {
1336a5a5ddb9SElaine Zhang int ret;
1337a5a5ddb9SElaine Zhang struct udevice *sys_child, *sf_child;
1338a5a5ddb9SElaine Zhang struct sysreset_reg *priv;
1339a5a5ddb9SElaine Zhang struct softreset_reg *sf_priv;
1340a5a5ddb9SElaine Zhang
1341a5a5ddb9SElaine Zhang /* The reset driver does not have a device node, so bind it here */
1342a5a5ddb9SElaine Zhang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
1343a5a5ddb9SElaine Zhang &sys_child);
1344a5a5ddb9SElaine Zhang if (ret) {
1345a5a5ddb9SElaine Zhang debug("Warning: No sysreset driver: ret=%d\n", ret);
1346a5a5ddb9SElaine Zhang } else {
1347a5a5ddb9SElaine Zhang priv = malloc(sizeof(struct sysreset_reg));
1348a5a5ddb9SElaine Zhang priv->glb_srst_fst_value = offsetof(struct rv1106_cru,
1349a5a5ddb9SElaine Zhang glb_srst_fst);
1350a5a5ddb9SElaine Zhang priv->glb_srst_snd_value = offsetof(struct rv1106_cru,
1351a5a5ddb9SElaine Zhang glb_srst_snd);
1352a5a5ddb9SElaine Zhang sys_child->priv = priv;
1353a5a5ddb9SElaine Zhang }
1354a5a5ddb9SElaine Zhang
1355a5a5ddb9SElaine Zhang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
1356a5a5ddb9SElaine Zhang dev_ofnode(dev), &sf_child);
1357a5a5ddb9SElaine Zhang if (ret) {
1358a5a5ddb9SElaine Zhang debug("Warning: No rockchip reset driver: ret=%d\n", ret);
1359a5a5ddb9SElaine Zhang } else {
1360a5a5ddb9SElaine Zhang sf_priv = malloc(sizeof(struct softreset_reg));
1361a5a5ddb9SElaine Zhang sf_priv->sf_reset_offset = offsetof(struct rv1106_cru,
1362a5a5ddb9SElaine Zhang pmu_softrst_con[0]);
1363a5a5ddb9SElaine Zhang sf_priv->sf_reset_num = 31745;
1364a5a5ddb9SElaine Zhang sf_child->priv = sf_priv;
1365a5a5ddb9SElaine Zhang }
1366a5a5ddb9SElaine Zhang
1367a5a5ddb9SElaine Zhang return 0;
1368a5a5ddb9SElaine Zhang }
1369a5a5ddb9SElaine Zhang
1370a5a5ddb9SElaine Zhang static const struct udevice_id rv1106_clk_ids[] = {
1371a5a5ddb9SElaine Zhang { .compatible = "rockchip,rv1106-cru" },
1372a5a5ddb9SElaine Zhang { }
1373a5a5ddb9SElaine Zhang };
1374a5a5ddb9SElaine Zhang
1375a5a5ddb9SElaine Zhang U_BOOT_DRIVER(rockchip_rv1106_cru) = {
1376a5a5ddb9SElaine Zhang .name = "rockchip_rv1106_cru",
1377a5a5ddb9SElaine Zhang .id = UCLASS_CLK,
1378a5a5ddb9SElaine Zhang .of_match = rv1106_clk_ids,
1379a5a5ddb9SElaine Zhang .priv_auto_alloc_size = sizeof(struct rv1106_clk_priv),
1380a5a5ddb9SElaine Zhang .ofdata_to_platdata = rv1106_clk_ofdata_to_platdata,
1381a5a5ddb9SElaine Zhang .ops = &rv1106_clk_ops,
1382a5a5ddb9SElaine Zhang .bind = rv1106_clk_bind,
1383a5a5ddb9SElaine Zhang .probe = rv1106_clk_probe,
1384a5a5ddb9SElaine Zhang };
1385a5a5ddb9SElaine Zhang
rv1106_grfclk_get_rate(struct clk * clk)138632914815SElaine Zhang static ulong rv1106_grfclk_get_rate(struct clk *clk)
138732914815SElaine Zhang {
138832914815SElaine Zhang struct udevice *cru_dev;
138932914815SElaine Zhang struct rv1106_clk_priv *cru_priv;
139032914815SElaine Zhang int ret;
139132914815SElaine Zhang ulong rate = 0;
139232914815SElaine Zhang
139332914815SElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
139432914815SElaine Zhang DM_GET_DRIVER(rockchip_rv1106_cru),
139532914815SElaine Zhang &cru_dev);
139632914815SElaine Zhang if (ret) {
139732914815SElaine Zhang printf("%s: could not find cru device\n", __func__);
139832914815SElaine Zhang return ret;
139932914815SElaine Zhang }
140032914815SElaine Zhang cru_priv = dev_get_priv(cru_dev);
140132914815SElaine Zhang
140232914815SElaine Zhang switch (clk->id) {
140332914815SElaine Zhang case SCLK_EMMC_SAMPLE:
140432914815SElaine Zhang rate = rv1106_mmc_get_clk(cru_priv, CCLK_SRC_EMMC) / 2;
140532914815SElaine Zhang break;
140632914815SElaine Zhang case SCLK_SDMMC_SAMPLE:
140732914815SElaine Zhang rate = rv1106_mmc_get_clk(cru_priv, CCLK_SRC_SDMMC) / 2;
140832914815SElaine Zhang break;
140932914815SElaine Zhang case SCLK_SDIO_SAMPLE:
141032914815SElaine Zhang rate = rv1106_mmc_get_clk(cru_priv, CCLK_SRC_SDIO) / 2;
141132914815SElaine Zhang break;
141232914815SElaine Zhang default:
141332914815SElaine Zhang return -ENOENT;
141432914815SElaine Zhang }
141532914815SElaine Zhang
141632914815SElaine Zhang return rate;
141732914815SElaine Zhang };
141832914815SElaine Zhang
141932914815SElaine Zhang #define ROCKCHIP_MMC_DELAY_SEL BIT(10)
142032914815SElaine Zhang #define ROCKCHIP_MMC_DEGREE_MASK 0x3
142132914815SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
142232914815SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
142332914815SElaine Zhang
142432914815SElaine Zhang #define PSECS_PER_SEC 1000000000000LL
142532914815SElaine Zhang /*
142632914815SElaine Zhang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
142732914815SElaine Zhang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
142832914815SElaine Zhang */
142932914815SElaine Zhang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
143032914815SElaine Zhang
rv1106_mmc_get_phase(struct clk * clk)143132914815SElaine Zhang int rv1106_mmc_get_phase(struct clk *clk)
143232914815SElaine Zhang {
143332914815SElaine Zhang struct rv1106_grf_clk_priv *priv = dev_get_priv(clk->dev);
143432914815SElaine Zhang u32 raw_value = 0, delay_num;
143532914815SElaine Zhang u16 degrees = 0;
143632914815SElaine Zhang ulong rate;
143732914815SElaine Zhang
143832914815SElaine Zhang rate = rv1106_grfclk_get_rate(clk);
143932914815SElaine Zhang if (rate < 0)
144032914815SElaine Zhang return rate;
144132914815SElaine Zhang
144232914815SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
144332914815SElaine Zhang raw_value = readl(&priv->grf->emmc_con1);
144432914815SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
144532914815SElaine Zhang raw_value = readl(&priv->grf->sdmmc_con1);
144632914815SElaine Zhang else if (clk->id == SCLK_SDIO_SAMPLE)
144732914815SElaine Zhang raw_value = readl(&priv->grf->sdio_con1);
144832914815SElaine Zhang
144932914815SElaine Zhang raw_value >>= 1;
145032914815SElaine Zhang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
145132914815SElaine Zhang
145232914815SElaine Zhang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
145332914815SElaine Zhang /* degrees/delaynum * 10000 */
145432914815SElaine Zhang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
145532914815SElaine Zhang 36 * (rate / 1000000);
145632914815SElaine Zhang
145732914815SElaine Zhang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
145832914815SElaine Zhang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
145932914815SElaine Zhang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
146032914815SElaine Zhang }
146132914815SElaine Zhang
146232914815SElaine Zhang return degrees % 360;
146332914815SElaine Zhang }
146432914815SElaine Zhang
rv1106_mmc_set_phase(struct clk * clk,u32 degrees)146532914815SElaine Zhang int rv1106_mmc_set_phase(struct clk *clk, u32 degrees)
146632914815SElaine Zhang {
146732914815SElaine Zhang struct rv1106_grf_clk_priv *priv = dev_get_priv(clk->dev);
146832914815SElaine Zhang u8 nineties, remainder, delay_num;
146932914815SElaine Zhang u32 raw_value, delay;
147032914815SElaine Zhang ulong rate;
147132914815SElaine Zhang
147232914815SElaine Zhang rate = rv1106_grfclk_get_rate(clk);
147332914815SElaine Zhang if (rate < 0)
147432914815SElaine Zhang return rate;
147532914815SElaine Zhang
147632914815SElaine Zhang nineties = degrees / 90;
147732914815SElaine Zhang remainder = (degrees % 90);
147832914815SElaine Zhang
147932914815SElaine Zhang /*
148032914815SElaine Zhang * Convert to delay; do a little extra work to make sure we
148132914815SElaine Zhang * don't overflow 32-bit / 64-bit numbers.
148232914815SElaine Zhang */
148332914815SElaine Zhang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
148432914815SElaine Zhang delay *= remainder;
148532914815SElaine Zhang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
148632914815SElaine Zhang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
148732914815SElaine Zhang
148832914815SElaine Zhang delay_num = (u8)min_t(u32, delay, 255);
148932914815SElaine Zhang
149032914815SElaine Zhang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
149132914815SElaine Zhang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
149232914815SElaine Zhang raw_value |= nineties;
149332914815SElaine Zhang
149432914815SElaine Zhang raw_value <<= 1;
149532914815SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
149632914815SElaine Zhang writel(raw_value | 0xffff0000, &priv->grf->emmc_con1);
149732914815SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
149832914815SElaine Zhang writel(raw_value | 0xffff0000, &priv->grf->sdmmc_con1);
149932914815SElaine Zhang else if (clk->id == SCLK_SDIO_SAMPLE)
150032914815SElaine Zhang writel(raw_value | 0xffff0000, &priv->grf->sdio_con1);
150132914815SElaine Zhang
150232914815SElaine Zhang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
150332914815SElaine Zhang degrees, delay_num, raw_value, rv1106_mmc_get_phase(clk));
150432914815SElaine Zhang
150532914815SElaine Zhang return 0;
150632914815SElaine Zhang }
150732914815SElaine Zhang
rv1106_grfclk_get_phase(struct clk * clk)150832914815SElaine Zhang static int rv1106_grfclk_get_phase(struct clk *clk)
150932914815SElaine Zhang {
151032914815SElaine Zhang int ret;
151132914815SElaine Zhang
151232914815SElaine Zhang debug("%s %ld\n", __func__, clk->id);
151332914815SElaine Zhang switch (clk->id) {
151432914815SElaine Zhang case SCLK_EMMC_SAMPLE:
151532914815SElaine Zhang case SCLK_SDMMC_SAMPLE:
151632914815SElaine Zhang case SCLK_SDIO_SAMPLE:
151732914815SElaine Zhang ret = rv1106_mmc_get_phase(clk);
151832914815SElaine Zhang break;
151932914815SElaine Zhang default:
152032914815SElaine Zhang return -ENOENT;
152132914815SElaine Zhang }
152232914815SElaine Zhang return ret;
152332914815SElaine Zhang }
152432914815SElaine Zhang
rv1106_grfclk_set_phase(struct clk * clk,int degrees)152532914815SElaine Zhang static int rv1106_grfclk_set_phase(struct clk *clk, int degrees)
152632914815SElaine Zhang {
152732914815SElaine Zhang int ret;
152832914815SElaine Zhang
152932914815SElaine Zhang debug("%s %ld\n", __func__, clk->id);
153032914815SElaine Zhang switch (clk->id) {
153132914815SElaine Zhang case SCLK_EMMC_SAMPLE:
153232914815SElaine Zhang case SCLK_SDMMC_SAMPLE:
153332914815SElaine Zhang case SCLK_SDIO_SAMPLE:
153432914815SElaine Zhang ret = rv1106_mmc_set_phase(clk, degrees);
153532914815SElaine Zhang break;
153632914815SElaine Zhang default:
153732914815SElaine Zhang return -ENOENT;
153832914815SElaine Zhang }
153932914815SElaine Zhang
154032914815SElaine Zhang return ret;
154132914815SElaine Zhang }
154232914815SElaine Zhang
154332914815SElaine Zhang static struct clk_ops rv1106_grfclk_ops = {
154432914815SElaine Zhang .get_rate = rv1106_grfclk_get_rate,
154532914815SElaine Zhang .get_phase = rv1106_grfclk_get_phase,
154632914815SElaine Zhang .set_phase = rv1106_grfclk_set_phase,
154732914815SElaine Zhang };
154832914815SElaine Zhang
rv1106_grfclk_probe(struct udevice * dev)154932914815SElaine Zhang static int rv1106_grfclk_probe(struct udevice *dev)
155032914815SElaine Zhang {
155132914815SElaine Zhang struct rv1106_grf_clk_priv *priv = dev_get_priv(dev);
155232914815SElaine Zhang
155332914815SElaine Zhang priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
155432914815SElaine Zhang if (IS_ERR(priv->grf))
155532914815SElaine Zhang return PTR_ERR(priv->grf);
155632914815SElaine Zhang
155732914815SElaine Zhang return 0;
155832914815SElaine Zhang }
155932914815SElaine Zhang
rv1106_grfclk_ofdata_to_platdata(struct udevice * dev)156032914815SElaine Zhang static int rv1106_grfclk_ofdata_to_platdata(struct udevice *dev)
156132914815SElaine Zhang {
156232914815SElaine Zhang return 0;
156332914815SElaine Zhang }
156432914815SElaine Zhang
rv1106_grfclk_bind(struct udevice * dev)156532914815SElaine Zhang static int rv1106_grfclk_bind(struct udevice *dev)
156632914815SElaine Zhang {
156732914815SElaine Zhang return 0;
156832914815SElaine Zhang }
156932914815SElaine Zhang
157032914815SElaine Zhang static const struct udevice_id rv1106_grfclk_ids[] = {
157132914815SElaine Zhang { .compatible = "rockchip,rv1106-grf-cru" },
157232914815SElaine Zhang { }
157332914815SElaine Zhang };
157432914815SElaine Zhang
157532914815SElaine Zhang U_BOOT_DRIVER(rockchip_rv1106_grf_cru) = {
157632914815SElaine Zhang .name = "rockchip_rv1106_grf_cru",
157732914815SElaine Zhang .id = UCLASS_CLK,
157832914815SElaine Zhang .of_match = rv1106_grfclk_ids,
157932914815SElaine Zhang .priv_auto_alloc_size = sizeof(struct rv1106_grf_clk_priv),
158032914815SElaine Zhang .ofdata_to_platdata = rv1106_grfclk_ofdata_to_platdata,
158132914815SElaine Zhang .ops = &rv1106_grfclk_ops,
158232914815SElaine Zhang .bind = rv1106_grfclk_bind,
158332914815SElaine Zhang .probe = rv1106_grfclk_probe,
158432914815SElaine Zhang };
158532914815SElaine Zhang
1586a5a5ddb9SElaine Zhang #ifndef CONFIG_SPL_BUILD
1587a5a5ddb9SElaine Zhang /**
1588a5a5ddb9SElaine Zhang * soc_clk_dump() - Print clock frequencies
1589a5a5ddb9SElaine Zhang * Returns zero on success
1590a5a5ddb9SElaine Zhang *
1591a5a5ddb9SElaine Zhang * Implementation for the clk dump command.
1592a5a5ddb9SElaine Zhang */
soc_clk_dump(void)1593a5a5ddb9SElaine Zhang int soc_clk_dump(void)
1594a5a5ddb9SElaine Zhang {
1595a5a5ddb9SElaine Zhang struct udevice *cru_dev;
1596a5a5ddb9SElaine Zhang struct rv1106_clk_priv *priv;
1597a5a5ddb9SElaine Zhang const struct rv1106_clk_info *clk_dump;
1598a5a5ddb9SElaine Zhang struct clk clk;
1599a5a5ddb9SElaine Zhang unsigned long clk_count = ARRAY_SIZE(clks_dump);
1600a5a5ddb9SElaine Zhang unsigned long rate;
1601a5a5ddb9SElaine Zhang int i, ret;
1602a5a5ddb9SElaine Zhang
1603a5a5ddb9SElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
1604a5a5ddb9SElaine Zhang DM_GET_DRIVER(rockchip_rv1106_cru),
1605a5a5ddb9SElaine Zhang &cru_dev);
1606a5a5ddb9SElaine Zhang if (ret) {
1607a5a5ddb9SElaine Zhang printf("%s failed to get cru device\n", __func__);
1608a5a5ddb9SElaine Zhang return ret;
1609a5a5ddb9SElaine Zhang }
1610a5a5ddb9SElaine Zhang
1611a5a5ddb9SElaine Zhang priv = dev_get_priv(cru_dev);
1612a5a5ddb9SElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
1613a5a5ddb9SElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
1614a5a5ddb9SElaine Zhang priv->armclk_enter_hz / 1000,
1615a5a5ddb9SElaine Zhang priv->armclk_init_hz / 1000,
1616a5a5ddb9SElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
1617a5a5ddb9SElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
1618a5a5ddb9SElaine Zhang for (i = 0; i < clk_count; i++) {
1619a5a5ddb9SElaine Zhang clk_dump = &clks_dump[i];
1620a5a5ddb9SElaine Zhang if (clk_dump->name) {
1621a5a5ddb9SElaine Zhang clk.id = clk_dump->id;
1622a5a5ddb9SElaine Zhang if (clk_dump->is_cru)
1623a5a5ddb9SElaine Zhang ret = clk_request(cru_dev, &clk);
1624a5a5ddb9SElaine Zhang if (ret < 0)
1625a5a5ddb9SElaine Zhang return ret;
1626a5a5ddb9SElaine Zhang
1627a5a5ddb9SElaine Zhang rate = clk_get_rate(&clk);
1628a5a5ddb9SElaine Zhang clk_free(&clk);
1629a5a5ddb9SElaine Zhang if (i == 0) {
1630a5a5ddb9SElaine Zhang if (rate < 0)
1631a5a5ddb9SElaine Zhang printf(" %s %s\n", clk_dump->name,
1632a5a5ddb9SElaine Zhang "unknown");
1633a5a5ddb9SElaine Zhang else
1634a5a5ddb9SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1635a5a5ddb9SElaine Zhang rate / 1000);
1636a5a5ddb9SElaine Zhang } else {
1637a5a5ddb9SElaine Zhang if (rate < 0)
1638a5a5ddb9SElaine Zhang printf(" %s %s\n", clk_dump->name,
1639a5a5ddb9SElaine Zhang "unknown");
1640a5a5ddb9SElaine Zhang else
1641a5a5ddb9SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
1642a5a5ddb9SElaine Zhang rate / 1000);
1643a5a5ddb9SElaine Zhang }
1644a5a5ddb9SElaine Zhang }
1645a5a5ddb9SElaine Zhang }
1646a5a5ddb9SElaine Zhang
1647a5a5ddb9SElaine Zhang return 0;
1648a5a5ddb9SElaine Zhang }
1649a5a5ddb9SElaine Zhang #endif
1650