1de4fa243SKever Yang /*
2de4fa243SKever Yang * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3de4fa243SKever Yang *
4de4fa243SKever Yang * SPDX-License-Identifier: GPL-2.0
5de4fa243SKever Yang */
6de4fa243SKever Yang
7de4fa243SKever Yang #include <common.h>
8de4fa243SKever Yang #include <clk-uclass.h>
9de4fa243SKever Yang #include <dm.h>
10de4fa243SKever Yang #include <errno.h>
11de4fa243SKever Yang #include <syscon.h>
12de4fa243SKever Yang #include <asm/io.h>
13de4fa243SKever Yang #include <asm/arch/clock.h>
14de4fa243SKever Yang #include <asm/arch/cru_rk3128.h>
15de4fa243SKever Yang #include <asm/arch/hardware.h>
16eb4fc8a1SDavid Wu #include <bitfield.h>
17de4fa243SKever Yang #include <dm/lists.h>
18de4fa243SKever Yang #include <dt-bindings/clock/rk3128-cru.h>
19de4fa243SKever Yang #include <linux/log2.h>
20de4fa243SKever Yang
21de4fa243SKever Yang DECLARE_GLOBAL_DATA_PTR;
22de4fa243SKever Yang
23de4fa243SKever Yang #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1))
24de4fa243SKever Yang
25efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
26efb944b6SElaine Zhang #define RK3128_CLK_DUMP(_id, _name, _iscru) \
27efb944b6SElaine Zhang { \
28efb944b6SElaine Zhang .id = _id, \
29efb944b6SElaine Zhang .name = _name, \
30efb944b6SElaine Zhang .is_cru = _iscru, \
31efb944b6SElaine Zhang }
32efb944b6SElaine Zhang #endif
33de4fa243SKever Yang
34efb944b6SElaine Zhang static struct rockchip_pll_rate_table rk3128_pll_rates[] = {
35efb944b6SElaine Zhang /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac */
36efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
37efb944b6SElaine Zhang RK3036_PLL_RATE(1200000000, 1, 50, 1, 1, 1, 0),
38efb944b6SElaine Zhang RK3036_PLL_RATE(1188000000, 1, 99, 2, 1, 1, 0),
39efb944b6SElaine Zhang RK3036_PLL_RATE(1008000000, 1, 84, 2, 1, 1, 0),
40efb944b6SElaine Zhang #endif
41efb944b6SElaine Zhang RK3036_PLL_RATE(816000000, 1, 68, 2, 1, 1, 0),
42efb944b6SElaine Zhang RK3036_PLL_RATE(800000000, 1, 200, 6, 1, 1, 0),
43efb944b6SElaine Zhang RK3036_PLL_RATE(600000000, 1, 75, 3, 1, 1, 0),
44efb944b6SElaine Zhang RK3036_PLL_RATE(594000000, 1, 99, 4, 1, 1, 0),
45efb944b6SElaine Zhang RK3036_PLL_RATE(500000000, 1, 125, 6, 1, 1, 0),
46ba5fededSElaine Zhang RK3036_PLL_RATE(400000000, 1, 100, 6, 1, 1, 0),
47efb944b6SElaine Zhang { /* sentinel */ },
48efb944b6SElaine Zhang };
49de4fa243SKever Yang
50efb944b6SElaine Zhang #define RK3128_CPUCLK_RATE(_rate, _aclk_div, _pclk_div) \
51efb944b6SElaine Zhang { \
52efb944b6SElaine Zhang .rate = _rate##U, \
53efb944b6SElaine Zhang .aclk_div = _aclk_div, \
54efb944b6SElaine Zhang .pclk_div = _pclk_div, \
55efb944b6SElaine Zhang }
56efb944b6SElaine Zhang
57efb944b6SElaine Zhang static struct rockchip_cpu_rate_table rk3128_cpu_rates[] = {
58efb944b6SElaine Zhang RK3128_CPUCLK_RATE(1200000000, 1, 5),
59efb944b6SElaine Zhang RK3128_CPUCLK_RATE(1008000000, 1, 5),
60efb944b6SElaine Zhang RK3128_CPUCLK_RATE(816000000, 1, 3),
61efb944b6SElaine Zhang RK3128_CPUCLK_RATE(600000000, 1, 3),
62efb944b6SElaine Zhang };
63efb944b6SElaine Zhang
64efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
65efb944b6SElaine Zhang static const struct rk3128_clk_info clks_dump[] = {
66efb944b6SElaine Zhang RK3128_CLK_DUMP(PLL_APLL, "apll", true),
67efb944b6SElaine Zhang RK3128_CLK_DUMP(PLL_DPLL, "dpll", true),
68efb944b6SElaine Zhang RK3128_CLK_DUMP(PLL_CPLL, "cpll", true),
69efb944b6SElaine Zhang RK3128_CLK_DUMP(PLL_GPLL, "gpll", true),
70efb944b6SElaine Zhang RK3128_CLK_DUMP(ARMCLK, "armclk", true),
71efb944b6SElaine Zhang RK3128_CLK_DUMP(ACLK_CPU, "aclk_cpu", true),
72efb944b6SElaine Zhang RK3128_CLK_DUMP(HCLK_CPU, "hclk_cpu", true),
73efb944b6SElaine Zhang RK3128_CLK_DUMP(PCLK_CPU, "pclk_cpu", true),
74efb944b6SElaine Zhang RK3128_CLK_DUMP(ACLK_PERI, "aclk_peri", true),
75efb944b6SElaine Zhang RK3128_CLK_DUMP(HCLK_PERI, "hclk_peri", true),
76efb944b6SElaine Zhang RK3128_CLK_DUMP(PCLK_PERI, "pclk_peri", true),
77efb944b6SElaine Zhang };
78efb944b6SElaine Zhang #endif
79efb944b6SElaine Zhang
80efb944b6SElaine Zhang static struct rockchip_pll_clock rk3128_pll_clks[] = {
81efb944b6SElaine Zhang [APLL] = PLL(pll_rk3036, PLL_APLL, RK2928_PLL_CON(0),
82efb944b6SElaine Zhang RK2928_MODE_CON, 0, 10, 0, rk3128_pll_rates),
83efb944b6SElaine Zhang [DPLL] = PLL(pll_rk3036, PLL_DPLL, RK2928_PLL_CON(4),
84efb944b6SElaine Zhang RK2928_MODE_CON, 4, 10, 0, NULL),
85efb944b6SElaine Zhang [CPLL] = PLL(pll_rk3036, PLL_CPLL, RK2928_PLL_CON(8),
86efb944b6SElaine Zhang RK2928_MODE_CON, 8, 10, 0, rk3128_pll_rates),
87efb944b6SElaine Zhang [GPLL] = PLL(pll_rk3036, PLL_GPLL, RK2928_PLL_CON(12),
88efb944b6SElaine Zhang RK2928_MODE_CON, 12, 10, 0, rk3128_pll_rates),
89efb944b6SElaine Zhang };
90efb944b6SElaine Zhang
rk3128_armclk_set_clk(struct rk3128_clk_priv * priv,ulong hz)91efb944b6SElaine Zhang static ulong rk3128_armclk_set_clk(struct rk3128_clk_priv *priv, ulong hz)
92de4fa243SKever Yang {
93efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
94efb944b6SElaine Zhang const struct rockchip_cpu_rate_table *rate;
95efb944b6SElaine Zhang ulong old_rate;
96de4fa243SKever Yang
97efb944b6SElaine Zhang rate = rockchip_get_cpu_settings(rk3128_cpu_rates, hz);
98efb944b6SElaine Zhang if (!rate) {
99efb944b6SElaine Zhang printf("%s unsupported rate\n", __func__);
100efb944b6SElaine Zhang return -EINVAL;
101de4fa243SKever Yang }
102de4fa243SKever Yang
103de4fa243SKever Yang /*
104de4fa243SKever Yang * select apll as cpu/core clock pll source and
105de4fa243SKever Yang * set up dependent divisors for PERI and ACLK clocks.
106de4fa243SKever Yang * core hz : apll = 1:1
107de4fa243SKever Yang */
108efb944b6SElaine Zhang old_rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
109efb944b6SElaine Zhang priv->cru, APLL);
110efb944b6SElaine Zhang if (old_rate > hz) {
111efb944b6SElaine Zhang if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL],
112efb944b6SElaine Zhang priv->cru, APLL, hz))
113efb944b6SElaine Zhang return -EINVAL;
114de4fa243SKever Yang rk_clrsetreg(&cru->cru_clksel_con[0],
115de4fa243SKever Yang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
116de4fa243SKever Yang CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
117de4fa243SKever Yang 0 << CORE_DIV_CON_SHIFT);
118de4fa243SKever Yang rk_clrsetreg(&cru->cru_clksel_con[1],
119efb944b6SElaine Zhang CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
120efb944b6SElaine Zhang rate->aclk_div << CORE_ACLK_DIV_SHIFT |
121efb944b6SElaine Zhang rate->pclk_div << CORE_DBG_DIV_SHIFT);
122efb944b6SElaine Zhang } else if (old_rate < hz) {
123efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[1],
124efb944b6SElaine Zhang CORE_ACLK_DIV_MASK | CORE_DBG_DIV_MASK,
125efb944b6SElaine Zhang rate->aclk_div << CORE_ACLK_DIV_SHIFT |
126efb944b6SElaine Zhang rate->pclk_div << CORE_DBG_DIV_SHIFT);
127de4fa243SKever Yang rk_clrsetreg(&cru->cru_clksel_con[0],
128efb944b6SElaine Zhang CORE_CLK_PLL_SEL_MASK | CORE_DIV_CON_MASK,
129efb944b6SElaine Zhang CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
130efb944b6SElaine Zhang 0 << CORE_DIV_CON_SHIFT);
131efb944b6SElaine Zhang if (rockchip_pll_set_rate(&rk3128_pll_clks[APLL],
132efb944b6SElaine Zhang priv->cru, APLL, hz))
133efb944b6SElaine Zhang return -EINVAL;
134de4fa243SKever Yang }
135de4fa243SKever Yang
136efb944b6SElaine Zhang return rockchip_pll_get_rate(&rk3128_pll_clks[APLL], priv->cru, APLL);
137de4fa243SKever Yang }
138de4fa243SKever Yang
rockchip_mmc_get_clk(struct rk3128_clk_priv * priv,int periph)139efb944b6SElaine Zhang static ulong rockchip_mmc_get_clk(struct rk3128_clk_priv *priv,
140de4fa243SKever Yang int periph)
141de4fa243SKever Yang {
142efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
143de4fa243SKever Yang uint src_rate;
144de4fa243SKever Yang uint div, mux;
145de4fa243SKever Yang u32 con;
146de4fa243SKever Yang
147de4fa243SKever Yang switch (periph) {
148de4fa243SKever Yang case HCLK_EMMC:
149de4fa243SKever Yang case SCLK_EMMC:
150de4fa243SKever Yang case SCLK_EMMC_SAMPLE:
151de4fa243SKever Yang con = readl(&cru->cru_clksel_con[12]);
152de4fa243SKever Yang mux = (con & EMMC_PLL_MASK) >> EMMC_PLL_SHIFT;
153de4fa243SKever Yang div = (con & EMMC_DIV_MASK) >> EMMC_DIV_SHIFT;
154de4fa243SKever Yang break;
155de4fa243SKever Yang case HCLK_SDMMC:
156de4fa243SKever Yang case SCLK_SDMMC:
157efb944b6SElaine Zhang case SCLK_SDMMC_SAMPLE:
158de4fa243SKever Yang con = readl(&cru->cru_clksel_con[11]);
159de4fa243SKever Yang mux = (con & MMC0_PLL_MASK) >> MMC0_PLL_SHIFT;
160de4fa243SKever Yang div = (con & MMC0_DIV_MASK) >> MMC0_DIV_SHIFT;
161de4fa243SKever Yang break;
162efb944b6SElaine Zhang case HCLK_SDIO:
163efb944b6SElaine Zhang case SCLK_SDIO:
164efb944b6SElaine Zhang case SCLK_SDIO_SAMPLE:
165efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[12]);
166efb944b6SElaine Zhang mux = (con & SDIO_PLL_MASK) >> SDIO_PLL_SHIFT;
167efb944b6SElaine Zhang div = (con & SDIO_DIV_MASK) >> SDIO_DIV_SHIFT;
168efb944b6SElaine Zhang break;
169de4fa243SKever Yang default:
170de4fa243SKever Yang return -EINVAL;
171de4fa243SKever Yang }
172de4fa243SKever Yang
173efb944b6SElaine Zhang src_rate = mux == EMMC_SEL_24M ? OSC_HZ : priv->gpll_hz;
174de4fa243SKever Yang return DIV_TO_RATE(src_rate, div);
175de4fa243SKever Yang }
176de4fa243SKever Yang
rockchip_mmc_set_clk(struct rk3128_clk_priv * priv,int periph,uint freq)177efb944b6SElaine Zhang static ulong rockchip_mmc_set_clk(struct rk3128_clk_priv *priv,
178de4fa243SKever Yang int periph, uint freq)
179de4fa243SKever Yang {
180efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
181de4fa243SKever Yang int src_clk_div;
182de4fa243SKever Yang int mux;
183de4fa243SKever Yang
184de4fa243SKever Yang /* mmc clock defaulg div 2 internal, need provide double in cru */
185efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz / 2, freq);
186de4fa243SKever Yang
187de4fa243SKever Yang if (src_clk_div > 128) {
188de4fa243SKever Yang src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, freq);
189de4fa243SKever Yang mux = EMMC_SEL_24M;
190de4fa243SKever Yang } else {
191de4fa243SKever Yang mux = EMMC_SEL_GPLL;
192de4fa243SKever Yang }
193de4fa243SKever Yang
194de4fa243SKever Yang switch (periph) {
195de4fa243SKever Yang case HCLK_EMMC:
196efb944b6SElaine Zhang case SCLK_EMMC:
197de4fa243SKever Yang rk_clrsetreg(&cru->cru_clksel_con[12],
198de4fa243SKever Yang EMMC_PLL_MASK | EMMC_DIV_MASK,
199de4fa243SKever Yang mux << EMMC_PLL_SHIFT |
200de4fa243SKever Yang (src_clk_div - 1) << EMMC_DIV_SHIFT);
201de4fa243SKever Yang break;
202de4fa243SKever Yang case HCLK_SDMMC:
203de4fa243SKever Yang case SCLK_SDMMC:
204de4fa243SKever Yang rk_clrsetreg(&cru->cru_clksel_con[11],
205de4fa243SKever Yang MMC0_PLL_MASK | MMC0_DIV_MASK,
206de4fa243SKever Yang mux << MMC0_PLL_SHIFT |
207de4fa243SKever Yang (src_clk_div - 1) << MMC0_DIV_SHIFT);
208de4fa243SKever Yang break;
209efb944b6SElaine Zhang case HCLK_SDIO:
210efb944b6SElaine Zhang case SCLK_SDIO:
211efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[12],
212efb944b6SElaine Zhang SDIO_PLL_MASK | SDIO_DIV_MASK,
213efb944b6SElaine Zhang mux << SDIO_PLL_SHIFT |
214efb944b6SElaine Zhang (src_clk_div - 1) << SDIO_DIV_SHIFT);
215efb944b6SElaine Zhang break;
216de4fa243SKever Yang default:
217de4fa243SKever Yang return -EINVAL;
218de4fa243SKever Yang }
219de4fa243SKever Yang
220efb944b6SElaine Zhang return rockchip_mmc_get_clk(priv, periph);
221de4fa243SKever Yang }
222de4fa243SKever Yang
rk3128_peri_get_clk(struct rk3128_clk_priv * priv,ulong clk_id)223efb944b6SElaine Zhang static ulong rk3128_peri_get_clk(struct rk3128_clk_priv *priv, ulong clk_id)
2249a872265SElaine Zhang {
225efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
226efb944b6SElaine Zhang u32 div, con, parent;
2279a872265SElaine Zhang
2289a872265SElaine Zhang switch (clk_id) {
229efb944b6SElaine Zhang case ACLK_PERI:
230efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[10]);
231efb944b6SElaine Zhang div = (con & ACLK_PERI_DIV_MASK) >> ACLK_PERI_DIV_SHIFT;
232efb944b6SElaine Zhang parent = priv->gpll_hz;
233efb944b6SElaine Zhang break;
234efb944b6SElaine Zhang case PCLK_PERI:
2359a872265SElaine Zhang case PCLK_I2C0:
2369a872265SElaine Zhang case PCLK_I2C1:
2379a872265SElaine Zhang case PCLK_I2C2:
2389a872265SElaine Zhang case PCLK_I2C3:
239bab2d2c3SDavid Wu case PCLK_PWM:
24033a03efdSElaine Zhang case PCLK_WDT:
2419a872265SElaine Zhang con = readl(&cru->cru_clksel_con[10]);
242efb944b6SElaine Zhang div = (con & PCLK_PERI_DIV_MASK) >> PCLK_PERI_DIV_SHIFT;
243efb944b6SElaine Zhang parent = rk3128_peri_get_clk(priv, ACLK_PERI);
244efb944b6SElaine Zhang break;
245efb944b6SElaine Zhang case HCLK_PERI:
246efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[10]);
247efb944b6SElaine Zhang div = (con & HCLK_PERI_DIV_MASK) >> HCLK_PERI_DIV_SHIFT;
248efb944b6SElaine Zhang parent = rk3128_peri_get_clk(priv, ACLK_PERI);
2499a872265SElaine Zhang break;
2509a872265SElaine Zhang default:
251bab2d2c3SDavid Wu printf("do not support this peripheral bus\n");
2529a872265SElaine Zhang return -EINVAL;
2539a872265SElaine Zhang }
2549a872265SElaine Zhang
255efb944b6SElaine Zhang return DIV_TO_RATE(parent, div);
2569a872265SElaine Zhang }
2579a872265SElaine Zhang
rk3128_peri_set_clk(struct rk3128_clk_priv * priv,ulong clk_id,uint hz)258efb944b6SElaine Zhang static ulong rk3128_peri_set_clk(struct rk3128_clk_priv *priv,
259efb944b6SElaine Zhang ulong clk_id, uint hz)
2609a872265SElaine Zhang {
261efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
2629a872265SElaine Zhang int src_clk_div;
2639a872265SElaine Zhang
2649a872265SElaine Zhang switch (clk_id) {
265efb944b6SElaine Zhang case ACLK_PERI:
266efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
267efb944b6SElaine Zhang assert(src_clk_div - 1 < 32);
268efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[10],
269efb944b6SElaine Zhang PERI_PLL_SEL_MASK | ACLK_PERI_DIV_MASK,
270efb944b6SElaine Zhang PERI_PLL_SEL_GPLL << PERI_PLL_SEL_SHIFT |
271efb944b6SElaine Zhang (src_clk_div - 1) << ACLK_PERI_DIV_SHIFT);
272efb944b6SElaine Zhang break;
2739a872265SElaine Zhang case PCLK_I2C0:
2749a872265SElaine Zhang case PCLK_I2C1:
2759a872265SElaine Zhang case PCLK_I2C2:
2769a872265SElaine Zhang case PCLK_I2C3:
277bab2d2c3SDavid Wu case PCLK_PWM:
278efb944b6SElaine Zhang case PCLK_PERI:
279efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv,
280efb944b6SElaine Zhang ACLK_PERI),
281efb944b6SElaine Zhang hz);
282efb944b6SElaine Zhang assert(src_clk_div - 1 < 3);
283efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[10],
284efb944b6SElaine Zhang PCLK_PERI_DIV_MASK,
285efb944b6SElaine Zhang (src_clk_div - 1) << PCLK_PERI_DIV_SHIFT);
286efb944b6SElaine Zhang break;
287efb944b6SElaine Zhang case HCLK_PERI:
288efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(rk3128_peri_get_clk(priv,
289efb944b6SElaine Zhang ACLK_PERI),
290efb944b6SElaine Zhang hz);
291efb944b6SElaine Zhang assert(src_clk_div - 1 < 7);
292efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[10],
293efb944b6SElaine Zhang HCLK_PERI_DIV_MASK,
294efb944b6SElaine Zhang (src_clk_div - 1) << HCLK_PERI_DIV_SHIFT);
2959a872265SElaine Zhang break;
2969a872265SElaine Zhang default:
297bab2d2c3SDavid Wu printf("do not support this peripheral bus\n");
2989a872265SElaine Zhang return -EINVAL;
2999a872265SElaine Zhang }
3009a872265SElaine Zhang
301efb944b6SElaine Zhang return rk3128_peri_get_clk(priv, clk_id);
3029a872265SElaine Zhang }
303eb4fc8a1SDavid Wu
rk3128_bus_get_clk(struct rk3128_clk_priv * priv,ulong clk_id)304efb944b6SElaine Zhang static ulong rk3128_bus_get_clk(struct rk3128_clk_priv *priv, ulong clk_id)
305eb4fc8a1SDavid Wu {
306efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
307efb944b6SElaine Zhang u32 div, con, parent;
308efb944b6SElaine Zhang
309efb944b6SElaine Zhang switch (clk_id) {
310efb944b6SElaine Zhang case ACLK_CPU:
311efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[0]);
312efb944b6SElaine Zhang div = (con & ACLK_BUS_DIV_MASK) >> ACLK_BUS_DIV_SHIFT;
313efb944b6SElaine Zhang parent = priv->gpll_hz;
314efb944b6SElaine Zhang break;
315efb944b6SElaine Zhang case PCLK_CPU:
316efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[1]);
317efb944b6SElaine Zhang div = (con & PCLK_BUS_DIV_MASK) >> PCLK_BUS_DIV_SHIFT;
318efb944b6SElaine Zhang parent = rk3128_bus_get_clk(priv, ACLK_CPU);
319efb944b6SElaine Zhang break;
320efb944b6SElaine Zhang case HCLK_CPU:
321efb944b6SElaine Zhang con = readl(&cru->cru_clksel_con[1]);
322efb944b6SElaine Zhang div = (con & HCLK_BUS_DIV_MASK) >> HCLK_BUS_DIV_SHIFT;
323efb944b6SElaine Zhang parent = rk3128_bus_get_clk(priv, ACLK_CPU);
324efb944b6SElaine Zhang break;
325efb944b6SElaine Zhang default:
326efb944b6SElaine Zhang printf("do not support this peripheral bus\n");
327efb944b6SElaine Zhang return -EINVAL;
328efb944b6SElaine Zhang }
329efb944b6SElaine Zhang
330efb944b6SElaine Zhang return DIV_TO_RATE(parent, div);
331efb944b6SElaine Zhang }
332efb944b6SElaine Zhang
rk3128_bus_set_clk(struct rk3128_clk_priv * priv,ulong clk_id,uint hz)333efb944b6SElaine Zhang static ulong rk3128_bus_set_clk(struct rk3128_clk_priv *priv,
334efb944b6SElaine Zhang ulong clk_id, uint hz)
335efb944b6SElaine Zhang {
336efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
337efb944b6SElaine Zhang int src_clk_div;
338efb944b6SElaine Zhang
339efb944b6SElaine Zhang switch (clk_id) {
340efb944b6SElaine Zhang case ACLK_CPU:
341efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(priv->gpll_hz, hz);
342efb944b6SElaine Zhang assert(src_clk_div - 1 < 32);
343efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[0],
344efb944b6SElaine Zhang BUS_PLL_SEL_MASK | ACLK_BUS_DIV_MASK,
345efb944b6SElaine Zhang BUS_PLL_SEL_GPLL << BUS_PLL_SEL_SHIFT |
346efb944b6SElaine Zhang (src_clk_div - 1) << ACLK_BUS_DIV_SHIFT);
347efb944b6SElaine Zhang break;
348efb944b6SElaine Zhang case PCLK_CPU:
349efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv,
350efb944b6SElaine Zhang ACLK_CPU),
351efb944b6SElaine Zhang hz);
352efb944b6SElaine Zhang assert(src_clk_div - 1 < 3);
353efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[1],
354efb944b6SElaine Zhang PCLK_BUS_DIV_MASK,
355efb944b6SElaine Zhang (src_clk_div - 1) << PCLK_BUS_DIV_SHIFT);
356efb944b6SElaine Zhang break;
357efb944b6SElaine Zhang case HCLK_CPU:
358efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(rk3128_bus_get_clk(priv,
359efb944b6SElaine Zhang ACLK_CPU),
360efb944b6SElaine Zhang hz);
361efb944b6SElaine Zhang assert(src_clk_div - 1 < 7);
362efb944b6SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[1],
363efb944b6SElaine Zhang HCLK_BUS_DIV_MASK,
364efb944b6SElaine Zhang (src_clk_div - 1) << HCLK_BUS_DIV_SHIFT);
365efb944b6SElaine Zhang break;
366efb944b6SElaine Zhang default:
367efb944b6SElaine Zhang printf("do not support this peripheral bus\n");
368efb944b6SElaine Zhang return -EINVAL;
369efb944b6SElaine Zhang }
370efb944b6SElaine Zhang
371efb944b6SElaine Zhang return rk3128_bus_get_clk(priv, clk_id);
372efb944b6SElaine Zhang }
373efb944b6SElaine Zhang
rk3128_spi_get_clk(struct rk3128_clk_priv * priv)3747f619f26SElaine Zhang static ulong rk3128_spi_get_clk(struct rk3128_clk_priv *priv)
3757f619f26SElaine Zhang {
3767f619f26SElaine Zhang struct rk3128_cru *cru = priv->cru;
3777f619f26SElaine Zhang u32 div, con, parent;
3787f619f26SElaine Zhang
3797f619f26SElaine Zhang con = readl(&cru->cru_clksel_con[25]);
3807f619f26SElaine Zhang div = (con & SPI_DIV_MASK) >> SPI_DIV_SHIFT;
3817f619f26SElaine Zhang parent = priv->gpll_hz;
3827f619f26SElaine Zhang
3837f619f26SElaine Zhang return DIV_TO_RATE(parent, div);
3847f619f26SElaine Zhang }
3857f619f26SElaine Zhang
rk3128_spi_set_clk(struct rk3128_clk_priv * priv,ulong hz)3867f619f26SElaine Zhang static ulong rk3128_spi_set_clk(struct rk3128_clk_priv *priv, ulong hz)
3877f619f26SElaine Zhang {
3887f619f26SElaine Zhang struct rk3128_cru *cru = priv->cru;
3897f619f26SElaine Zhang int div;
3907f619f26SElaine Zhang
3917f619f26SElaine Zhang div = DIV_ROUND_UP(priv->gpll_hz, hz);
3927f619f26SElaine Zhang assert(div - 1 < 128);
3937f619f26SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[25],
3947f619f26SElaine Zhang SPI_PLL_SEL_MASK | SPI_DIV_MASK,
3957f619f26SElaine Zhang SPI_PLL_SEL_GPLL << SPI_PLL_SEL_SHIFT |
3967f619f26SElaine Zhang (div - 1) << SPI_DIV_SHIFT);
3977f619f26SElaine Zhang return rk3128_spi_get_clk(priv);
3987f619f26SElaine Zhang }
3997f619f26SElaine Zhang
400efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
rk3128_saradc_get_clk(struct rk3128_clk_priv * priv)401efb944b6SElaine Zhang static ulong rk3128_saradc_get_clk(struct rk3128_clk_priv *priv)
402efb944b6SElaine Zhang {
403efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
404eb4fc8a1SDavid Wu u32 div, val;
405eb4fc8a1SDavid Wu
406eb4fc8a1SDavid Wu val = readl(&cru->cru_clksel_con[24]);
407eb4fc8a1SDavid Wu div = bitfield_extract(val, SARADC_DIV_CON_SHIFT,
408eb4fc8a1SDavid Wu SARADC_DIV_CON_WIDTH);
409eb4fc8a1SDavid Wu
410eb4fc8a1SDavid Wu return DIV_TO_RATE(OSC_HZ, div);
411eb4fc8a1SDavid Wu }
412eb4fc8a1SDavid Wu
rk3128_saradc_set_clk(struct rk3128_clk_priv * priv,uint hz)413efb944b6SElaine Zhang static ulong rk3128_saradc_set_clk(struct rk3128_clk_priv *priv, uint hz)
414eb4fc8a1SDavid Wu {
415efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
416eb4fc8a1SDavid Wu int src_clk_div;
417eb4fc8a1SDavid Wu
418eb4fc8a1SDavid Wu src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1;
419eb4fc8a1SDavid Wu assert(src_clk_div < 128);
420eb4fc8a1SDavid Wu
421eb4fc8a1SDavid Wu rk_clrsetreg(&cru->cru_clksel_con[24],
422eb4fc8a1SDavid Wu SARADC_DIV_CON_MASK,
423eb4fc8a1SDavid Wu src_clk_div << SARADC_DIV_CON_SHIFT);
424eb4fc8a1SDavid Wu
425efb944b6SElaine Zhang return rk3128_saradc_get_clk(priv);
426eb4fc8a1SDavid Wu }
427eb4fc8a1SDavid Wu
428efb944b6SElaine Zhang #define RK3128_LCDC_PLL_LIMIT 600000000
429efb944b6SElaine Zhang
rk3128_vop_set_clk(struct rk3128_clk_priv * priv,ulong clk_id,uint hz)430efb944b6SElaine Zhang static ulong rk3128_vop_set_clk(struct rk3128_clk_priv *priv,
431efb944b6SElaine Zhang ulong clk_id, uint hz)
4323e3a3170SElaine Zhang {
433efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
4343e3a3170SElaine Zhang int src_clk_div;
4353e3a3170SElaine Zhang
4363e3a3170SElaine Zhang src_clk_div = GPLL_HZ / hz;
4373e3a3170SElaine Zhang assert(src_clk_div - 1 < 31);
4383e3a3170SElaine Zhang
4393e3a3170SElaine Zhang switch (clk_id) {
440efb944b6SElaine Zhang case ACLK_LCDC0:
4413e3a3170SElaine Zhang case ACLK_VIO0:
4423e3a3170SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[31],
4433e3a3170SElaine Zhang VIO0_PLL_MASK | VIO0_DIV_MASK,
4443e3a3170SElaine Zhang VIO0_SEL_GPLL << VIO0_PLL_SHIFT |
4453e3a3170SElaine Zhang (src_clk_div - 1) << VIO0_DIV_SHIFT);
4463e3a3170SElaine Zhang break;
4473e3a3170SElaine Zhang case ACLK_VIO1:
4483e3a3170SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[31],
4493e3a3170SElaine Zhang VIO1_PLL_MASK | VIO1_DIV_MASK,
4503e3a3170SElaine Zhang VIO1_SEL_GPLL << VIO1_PLL_SHIFT |
4513e3a3170SElaine Zhang (src_clk_div - 1) << VIO1_DIV_SHIFT);
4523e3a3170SElaine Zhang break;
453efb944b6SElaine Zhang case DCLK_VOP:
454efb944b6SElaine Zhang src_clk_div = DIV_ROUND_UP(RK3128_LCDC_PLL_LIMIT, hz);
455efb944b6SElaine Zhang rockchip_pll_set_rate(&rk3128_pll_clks[CPLL],
456efb944b6SElaine Zhang priv->cru, CPLL, src_clk_div * hz);
4573e3a3170SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[27],
4583e3a3170SElaine Zhang DCLK_VOP_SEL_MASK | DCLK_VOP_DIV_CON_MASK,
4593e3a3170SElaine Zhang DCLK_VOP_PLL_SEL_CPLL << DCLK_VOP_SEL_SHIFT |
460efb944b6SElaine Zhang (src_clk_div - 1) << DCLK_VOP_DIV_CON_SHIFT);
4613e3a3170SElaine Zhang break;
4623e3a3170SElaine Zhang default:
4633e3a3170SElaine Zhang printf("do not support this vop freq\n");
4643e3a3170SElaine Zhang return -EINVAL;
4653e3a3170SElaine Zhang }
4663e3a3170SElaine Zhang
4673e3a3170SElaine Zhang return hz;
4683e3a3170SElaine Zhang }
4693e3a3170SElaine Zhang
rk3128_vop_get_rate(struct rk3128_clk_priv * priv,ulong clk_id)470efb944b6SElaine Zhang static ulong rk3128_vop_get_rate(struct rk3128_clk_priv *priv, ulong clk_id)
4713e3a3170SElaine Zhang {
472efb944b6SElaine Zhang struct rk3128_cru *cru = priv->cru;
4733e3a3170SElaine Zhang u32 div, con, parent;
4743e3a3170SElaine Zhang
4753e3a3170SElaine Zhang switch (clk_id) {
476efb944b6SElaine Zhang case ACLK_LCDC0:
4773e3a3170SElaine Zhang case ACLK_VIO0:
4783e3a3170SElaine Zhang con = readl(&cru->cru_clksel_con[31]);
4793e3a3170SElaine Zhang div = con & 0x1f;
4803e3a3170SElaine Zhang parent = GPLL_HZ;
4813e3a3170SElaine Zhang break;
4823e3a3170SElaine Zhang case ACLK_VIO1:
4833e3a3170SElaine Zhang con = readl(&cru->cru_clksel_con[31]);
4843e3a3170SElaine Zhang div = (con >> 8) & 0x1f;
4853e3a3170SElaine Zhang parent = GPLL_HZ;
4863e3a3170SElaine Zhang break;
487efb944b6SElaine Zhang case DCLK_VOP:
4883e3a3170SElaine Zhang con = readl(&cru->cru_clksel_con[27]);
489efb944b6SElaine Zhang div = (con & DCLK_VOP_DIV_CON_MASK) >> DCLK_VOP_DIV_CON_SHIFT;
490efb944b6SElaine Zhang parent = rockchip_pll_get_rate(&rk3128_pll_clks[CPLL],
491efb944b6SElaine Zhang priv->cru, CPLL);
4923e3a3170SElaine Zhang break;
4933e3a3170SElaine Zhang default:
4943e3a3170SElaine Zhang return -ENOENT;
4953e3a3170SElaine Zhang }
4963e3a3170SElaine Zhang return DIV_TO_RATE(parent, div);
4973e3a3170SElaine Zhang }
498582fa222SElaine Zhang
rk3128_crypto_get_rate(struct rk3128_clk_priv * priv)499582fa222SElaine Zhang static ulong rk3128_crypto_get_rate(struct rk3128_clk_priv *priv)
500582fa222SElaine Zhang {
501582fa222SElaine Zhang struct rk3128_cru *cru = priv->cru;
502582fa222SElaine Zhang u32 div, val;
503582fa222SElaine Zhang
504582fa222SElaine Zhang val = readl(&cru->cru_clksel_con[24]);
505582fa222SElaine Zhang div = (val & CLK_CRYPTO_DIV_CON_MASK) >> CLK_CRYPTO_DIV_CON_SHIFT;
506582fa222SElaine Zhang
507582fa222SElaine Zhang return DIV_TO_RATE(rk3128_bus_get_clk(priv, ACLK_CPU), div);
508582fa222SElaine Zhang }
509582fa222SElaine Zhang
rk3128_crypto_set_rate(struct rk3128_clk_priv * priv,uint hz)510582fa222SElaine Zhang static ulong rk3128_crypto_set_rate(struct rk3128_clk_priv *priv,
511582fa222SElaine Zhang uint hz)
512582fa222SElaine Zhang {
513582fa222SElaine Zhang struct rk3128_cru *cru = priv->cru;
514582fa222SElaine Zhang int src_clk_div;
515582fa222SElaine Zhang uint p_rate;
516582fa222SElaine Zhang
517582fa222SElaine Zhang p_rate = rk3128_bus_get_clk(priv, ACLK_CPU);
518582fa222SElaine Zhang src_clk_div = DIV_ROUND_UP(p_rate, hz) - 1;
519582fa222SElaine Zhang assert(src_clk_div < 3);
520582fa222SElaine Zhang
521582fa222SElaine Zhang rk_clrsetreg(&cru->cru_clksel_con[24],
522582fa222SElaine Zhang CLK_CRYPTO_DIV_CON_MASK,
523582fa222SElaine Zhang src_clk_div << CLK_CRYPTO_DIV_CON_SHIFT);
524582fa222SElaine Zhang
525582fa222SElaine Zhang return rk3128_crypto_get_rate(priv);
526582fa222SElaine Zhang }
527efb944b6SElaine Zhang #endif
5283e3a3170SElaine Zhang
rk3128_clk_get_rate(struct clk * clk)529de4fa243SKever Yang static ulong rk3128_clk_get_rate(struct clk *clk)
530de4fa243SKever Yang {
531de4fa243SKever Yang struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
532efb944b6SElaine Zhang ulong rate = 0;
533de4fa243SKever Yang
534de4fa243SKever Yang switch (clk->id) {
535efb944b6SElaine Zhang case PLL_APLL:
536efb944b6SElaine Zhang case PLL_DPLL:
537efb944b6SElaine Zhang case PLL_CPLL:
538efb944b6SElaine Zhang case PLL_GPLL:
539efb944b6SElaine Zhang rate = rockchip_pll_get_rate(&rk3128_pll_clks[clk->id - 1],
540efb944b6SElaine Zhang priv->cru, clk->id - 1);
541efb944b6SElaine Zhang break;
542efb944b6SElaine Zhang case ARMCLK:
543efb944b6SElaine Zhang rate = rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
544efb944b6SElaine Zhang priv->cru, APLL);
545efb944b6SElaine Zhang break;
546efb944b6SElaine Zhang case HCLK_EMMC:
547efb944b6SElaine Zhang case SCLK_EMMC:
548efb944b6SElaine Zhang case HCLK_SDMMC:
549efb944b6SElaine Zhang case SCLK_SDMMC:
550efb944b6SElaine Zhang case HCLK_SDIO:
551efb944b6SElaine Zhang case SCLK_SDIO:
552efb944b6SElaine Zhang rate = rockchip_mmc_get_clk(priv, clk->id);
553efb944b6SElaine Zhang break;
554efb944b6SElaine Zhang case ACLK_PERI:
555efb944b6SElaine Zhang case HCLK_PERI:
556efb944b6SElaine Zhang case PCLK_PERI:
5579a872265SElaine Zhang case PCLK_I2C0:
5589a872265SElaine Zhang case PCLK_I2C1:
5599a872265SElaine Zhang case PCLK_I2C2:
5609a872265SElaine Zhang case PCLK_I2C3:
561bab2d2c3SDavid Wu case PCLK_PWM:
56233a03efdSElaine Zhang case PCLK_WDT:
563efb944b6SElaine Zhang rate = rk3128_peri_get_clk(priv, clk->id);
564efb944b6SElaine Zhang break;
565efb944b6SElaine Zhang case ACLK_CPU:
566efb944b6SElaine Zhang case HCLK_CPU:
567efb944b6SElaine Zhang case PCLK_CPU:
568efb944b6SElaine Zhang rate = rk3128_bus_get_clk(priv, clk->id);
569efb944b6SElaine Zhang break;
5707f619f26SElaine Zhang case SCLK_SPI0:
5717f619f26SElaine Zhang rate = rk3128_spi_get_clk(priv);
5727f619f26SElaine Zhang break;
573efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
574eb4fc8a1SDavid Wu case SCLK_SARADC:
575efb944b6SElaine Zhang rate = rk3128_saradc_get_clk(priv);
576efb944b6SElaine Zhang break;
577efb944b6SElaine Zhang case DCLK_VOP:
5783e3a3170SElaine Zhang case ACLK_VIO0:
5793e3a3170SElaine Zhang case ACLK_VIO1:
580efb944b6SElaine Zhang case ACLK_LCDC0:
581efb944b6SElaine Zhang rate = rk3128_vop_get_rate(priv, clk->id);
582efb944b6SElaine Zhang break;
583582fa222SElaine Zhang case SCLK_CRYPTO:
584582fa222SElaine Zhang rate = rk3128_crypto_get_rate(priv);
585582fa222SElaine Zhang break;
586efb944b6SElaine Zhang #endif
587de4fa243SKever Yang default:
588de4fa243SKever Yang return -ENOENT;
589de4fa243SKever Yang }
590efb944b6SElaine Zhang return rate;
591de4fa243SKever Yang }
592de4fa243SKever Yang
rk3128_clk_set_rate(struct clk * clk,ulong rate)593de4fa243SKever Yang static ulong rk3128_clk_set_rate(struct clk *clk, ulong rate)
594de4fa243SKever Yang {
595de4fa243SKever Yang struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
59692c6b642SElaine Zhang ulong ret = 0;
597de4fa243SKever Yang
598de4fa243SKever Yang switch (clk->id) {
599efb944b6SElaine Zhang case PLL_APLL:
600efb944b6SElaine Zhang case PLL_DPLL:
601efb944b6SElaine Zhang case PLL_CPLL:
602efb944b6SElaine Zhang ret = rockchip_pll_set_rate(&rk3128_pll_clks[clk->id - 1],
603efb944b6SElaine Zhang priv->cru, clk->id - 1, rate);
604efb944b6SElaine Zhang case PLL_GPLL:
605efb944b6SElaine Zhang ret = rockchip_pll_set_rate(&rk3128_pll_clks[GPLL],
606efb944b6SElaine Zhang priv->cru, GPLL, rate);
607efb944b6SElaine Zhang priv->gpll_hz = rate;
608efb944b6SElaine Zhang break;
609efb944b6SElaine Zhang case ARMCLK:
61092c6b642SElaine Zhang if (priv->armclk_hz)
611efb944b6SElaine Zhang ret = rk3128_armclk_set_clk(priv, rate);
61292c6b642SElaine Zhang priv->armclk_hz = rate;
6133e3a3170SElaine Zhang break;
614de4fa243SKever Yang case HCLK_EMMC:
615efb944b6SElaine Zhang case SCLK_EMMC:
616efb944b6SElaine Zhang case SCLK_EMMC_SAMPLE:
617efb944b6SElaine Zhang case HCLK_SDMMC:
618efb944b6SElaine Zhang case SCLK_SDMMC:
619efb944b6SElaine Zhang case SCLK_SDMMC_SAMPLE:
620efb944b6SElaine Zhang case HCLK_SDIO:
621efb944b6SElaine Zhang case SCLK_SDIO:
622efb944b6SElaine Zhang case SCLK_SDIO_SAMPLE:
623efb944b6SElaine Zhang ret = rockchip_mmc_set_clk(priv, clk->id, rate);
624de4fa243SKever Yang break;
625efb944b6SElaine Zhang case ACLK_PERI:
626efb944b6SElaine Zhang case PCLK_PERI:
627efb944b6SElaine Zhang case HCLK_PERI:
6289a872265SElaine Zhang case PCLK_I2C0:
6299a872265SElaine Zhang case PCLK_I2C1:
6309a872265SElaine Zhang case PCLK_I2C2:
6319a872265SElaine Zhang case PCLK_I2C3:
632bab2d2c3SDavid Wu case PCLK_PWM:
633efb944b6SElaine Zhang ret = rk3128_peri_set_clk(priv, clk->id, rate);
6349a872265SElaine Zhang break;
635efb944b6SElaine Zhang case ACLK_CPU:
636efb944b6SElaine Zhang case HCLK_CPU:
637efb944b6SElaine Zhang case PCLK_CPU:
638efb944b6SElaine Zhang ret = rk3128_bus_set_clk(priv, clk->id, rate);
639efb944b6SElaine Zhang break;
6407f619f26SElaine Zhang case SCLK_SPI0:
641*73201477SJon Lin ret = rk3128_spi_set_clk(priv, rate);
6427f619f26SElaine Zhang break;
643efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
644eb4fc8a1SDavid Wu case SCLK_SARADC:
645efb944b6SElaine Zhang ret = rk3128_saradc_set_clk(priv, rate);
646eb4fc8a1SDavid Wu break;
647efb944b6SElaine Zhang case DCLK_VOP:
648efb944b6SElaine Zhang case ACLK_VIO0:
649efb944b6SElaine Zhang case ACLK_VIO1:
650efb944b6SElaine Zhang case ACLK_LCDC0:
651efb944b6SElaine Zhang ret = rk3128_vop_set_clk(priv, clk->id, rate);
652efb944b6SElaine Zhang break;
653582fa222SElaine Zhang case SCLK_CRYPTO:
654582fa222SElaine Zhang ret = rk3128_crypto_set_rate(priv, rate);
655582fa222SElaine Zhang break;
656efb944b6SElaine Zhang #endif
657de4fa243SKever Yang default:
658de4fa243SKever Yang return -ENOENT;
659de4fa243SKever Yang }
660efb944b6SElaine Zhang return ret;
661de4fa243SKever Yang }
662de4fa243SKever Yang
663aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAY_SEL BIT(10)
664aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DEGREE_MASK 0x3
665aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
666aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
667aa8c2987SElaine Zhang
668aa8c2987SElaine Zhang #define PSECS_PER_SEC 1000000000000LL
669aa8c2987SElaine Zhang /*
670aa8c2987SElaine Zhang * Each fine delay is between 44ps-77ps. Assume each fine delay is 60ps to
671aa8c2987SElaine Zhang * simplify calculations. So 45degs could be anywhere between 33deg and 57.8deg.
672aa8c2987SElaine Zhang */
673aa8c2987SElaine Zhang #define ROCKCHIP_MMC_DELAY_ELEMENT_PSEC 60
674aa8c2987SElaine Zhang
rk3128_mmc_get_phase(struct clk * clk)675aa8c2987SElaine Zhang int rk3128_mmc_get_phase(struct clk *clk)
676aa8c2987SElaine Zhang {
677aa8c2987SElaine Zhang struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
678aa8c2987SElaine Zhang struct rk3128_cru *cru = priv->cru;
679aa8c2987SElaine Zhang u32 raw_value, delay_num;
680aa8c2987SElaine Zhang u16 degrees = 0;
681aa8c2987SElaine Zhang ulong rate;
682aa8c2987SElaine Zhang
683aa8c2987SElaine Zhang rate = rk3128_clk_get_rate(clk);
684aa8c2987SElaine Zhang
685aa8c2987SElaine Zhang if (rate < 0)
686aa8c2987SElaine Zhang return rate;
687aa8c2987SElaine Zhang
688aa8c2987SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
689aa8c2987SElaine Zhang raw_value = readl(&cru->cru_emmc_con[1]);
690aa8c2987SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
691aa8c2987SElaine Zhang raw_value = readl(&cru->cru_sdmmc_con[1]);
692aa8c2987SElaine Zhang else
693aa8c2987SElaine Zhang raw_value = readl(&cru->cru_sdio_con[1]);
694aa8c2987SElaine Zhang
695aa8c2987SElaine Zhang raw_value >>= 1;
696aa8c2987SElaine Zhang degrees = (raw_value & ROCKCHIP_MMC_DEGREE_MASK) * 90;
697aa8c2987SElaine Zhang
698aa8c2987SElaine Zhang if (raw_value & ROCKCHIP_MMC_DELAY_SEL) {
699aa8c2987SElaine Zhang /* degrees/delaynum * 10000 */
700aa8c2987SElaine Zhang unsigned long factor = (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10) *
701aa8c2987SElaine Zhang 36 * (rate / 1000000);
702aa8c2987SElaine Zhang
703aa8c2987SElaine Zhang delay_num = (raw_value & ROCKCHIP_MMC_DELAYNUM_MASK);
704aa8c2987SElaine Zhang delay_num >>= ROCKCHIP_MMC_DELAYNUM_OFFSET;
705aa8c2987SElaine Zhang degrees += DIV_ROUND_CLOSEST(delay_num * factor, 10000);
706aa8c2987SElaine Zhang }
707aa8c2987SElaine Zhang
708aa8c2987SElaine Zhang return degrees % 360;
709aa8c2987SElaine Zhang }
710aa8c2987SElaine Zhang
rk3128_mmc_set_phase(struct clk * clk,u32 degrees)711aa8c2987SElaine Zhang int rk3128_mmc_set_phase(struct clk *clk, u32 degrees)
712aa8c2987SElaine Zhang {
713aa8c2987SElaine Zhang struct rk3128_clk_priv *priv = dev_get_priv(clk->dev);
714aa8c2987SElaine Zhang struct rk3128_cru *cru = priv->cru;
715aa8c2987SElaine Zhang u8 nineties, remainder, delay_num;
716aa8c2987SElaine Zhang u32 raw_value, delay;
717aa8c2987SElaine Zhang ulong rate;
718aa8c2987SElaine Zhang
719aa8c2987SElaine Zhang rate = rk3128_clk_get_rate(clk);
720aa8c2987SElaine Zhang
721aa8c2987SElaine Zhang if (rate < 0)
722aa8c2987SElaine Zhang return rate;
723aa8c2987SElaine Zhang
724aa8c2987SElaine Zhang nineties = degrees / 90;
725aa8c2987SElaine Zhang remainder = (degrees % 90);
726aa8c2987SElaine Zhang
727aa8c2987SElaine Zhang /*
728aa8c2987SElaine Zhang * Convert to delay; do a little extra work to make sure we
729aa8c2987SElaine Zhang * don't overflow 32-bit / 64-bit numbers.
730aa8c2987SElaine Zhang */
731aa8c2987SElaine Zhang delay = 10000000; /* PSECS_PER_SEC / 10000 / 10 */
732aa8c2987SElaine Zhang delay *= remainder;
733aa8c2987SElaine Zhang delay = DIV_ROUND_CLOSEST(delay, (rate / 1000) * 36 *
734aa8c2987SElaine Zhang (ROCKCHIP_MMC_DELAY_ELEMENT_PSEC / 10));
735aa8c2987SElaine Zhang
736aa8c2987SElaine Zhang delay_num = (u8)min_t(u32, delay, 255);
737aa8c2987SElaine Zhang
738aa8c2987SElaine Zhang raw_value = delay_num ? ROCKCHIP_MMC_DELAY_SEL : 0;
739aa8c2987SElaine Zhang raw_value |= delay_num << ROCKCHIP_MMC_DELAYNUM_OFFSET;
740aa8c2987SElaine Zhang raw_value |= nineties;
741aa8c2987SElaine Zhang
742aa8c2987SElaine Zhang raw_value <<= 1;
743aa8c2987SElaine Zhang if (clk->id == SCLK_EMMC_SAMPLE)
744aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->cru_emmc_con[1]);
745aa8c2987SElaine Zhang else if (clk->id == SCLK_SDMMC_SAMPLE)
746aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->cru_sdmmc_con[1]);
747aa8c2987SElaine Zhang else
748aa8c2987SElaine Zhang writel(raw_value | 0xffff0000, &cru->cru_sdio_con[1]);
749aa8c2987SElaine Zhang
750aa8c2987SElaine Zhang debug("mmc set_phase(%d) delay_nums=%u reg=%#x actual_degrees=%d\n",
751aa8c2987SElaine Zhang degrees, delay_num, raw_value, rk3128_mmc_get_phase(clk));
752aa8c2987SElaine Zhang
753aa8c2987SElaine Zhang return 0;
754aa8c2987SElaine Zhang }
755aa8c2987SElaine Zhang
rk3128_clk_get_phase(struct clk * clk)756aa8c2987SElaine Zhang static int rk3128_clk_get_phase(struct clk *clk)
757aa8c2987SElaine Zhang {
758aa8c2987SElaine Zhang int ret;
759aa8c2987SElaine Zhang
760aa8c2987SElaine Zhang debug("%s %ld\n", __func__, clk->id);
761aa8c2987SElaine Zhang switch (clk->id) {
762aa8c2987SElaine Zhang case SCLK_EMMC_SAMPLE:
763aa8c2987SElaine Zhang case SCLK_SDMMC_SAMPLE:
764aa8c2987SElaine Zhang case SCLK_SDIO_SAMPLE:
765aa8c2987SElaine Zhang ret = rk3128_mmc_get_phase(clk);
766aa8c2987SElaine Zhang break;
767aa8c2987SElaine Zhang default:
768aa8c2987SElaine Zhang return -ENOENT;
769aa8c2987SElaine Zhang }
770aa8c2987SElaine Zhang
771aa8c2987SElaine Zhang return ret;
772aa8c2987SElaine Zhang }
773aa8c2987SElaine Zhang
rk3128_clk_set_phase(struct clk * clk,int degrees)774aa8c2987SElaine Zhang static int rk3128_clk_set_phase(struct clk *clk, int degrees)
775aa8c2987SElaine Zhang {
776aa8c2987SElaine Zhang int ret;
777aa8c2987SElaine Zhang
778aa8c2987SElaine Zhang debug("%s %ld\n", __func__, clk->id);
779aa8c2987SElaine Zhang switch (clk->id) {
780aa8c2987SElaine Zhang case SCLK_EMMC_SAMPLE:
781aa8c2987SElaine Zhang case SCLK_SDMMC_SAMPLE:
782aa8c2987SElaine Zhang case SCLK_SDIO_SAMPLE:
783aa8c2987SElaine Zhang ret = rk3128_mmc_set_phase(clk, degrees);
784aa8c2987SElaine Zhang break;
785aa8c2987SElaine Zhang default:
786aa8c2987SElaine Zhang return -ENOENT;
787aa8c2987SElaine Zhang }
788aa8c2987SElaine Zhang
789aa8c2987SElaine Zhang return ret;
790aa8c2987SElaine Zhang }
791aa8c2987SElaine Zhang
792de4fa243SKever Yang static struct clk_ops rk3128_clk_ops = {
793de4fa243SKever Yang .get_rate = rk3128_clk_get_rate,
794de4fa243SKever Yang .set_rate = rk3128_clk_set_rate,
795aa8c2987SElaine Zhang .get_phase = rk3128_clk_get_phase,
796aa8c2987SElaine Zhang .set_phase = rk3128_clk_set_phase,
797de4fa243SKever Yang };
798de4fa243SKever Yang
rk3128_clk_ofdata_to_platdata(struct udevice * dev)79941dd6e98SKever Yang static int rk3128_clk_ofdata_to_platdata(struct udevice *dev)
800de4fa243SKever Yang {
801de4fa243SKever Yang struct rk3128_clk_priv *priv = dev_get_priv(dev);
802de4fa243SKever Yang
8036ab5195bSKever Yang priv->cru = dev_read_addr_ptr(dev);
80441dd6e98SKever Yang
80541dd6e98SKever Yang return 0;
80641dd6e98SKever Yang }
80741dd6e98SKever Yang
rkclk_init(struct rk3128_clk_priv * priv)808efb944b6SElaine Zhang static void rkclk_init(struct rk3128_clk_priv *priv)
809efb944b6SElaine Zhang {
810efb944b6SElaine Zhang if (rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
811efb944b6SElaine Zhang priv->cru, APLL) != APLL_HZ)
812efb944b6SElaine Zhang rk3128_armclk_set_clk(priv, APLL_HZ);
813efb944b6SElaine Zhang
814efb944b6SElaine Zhang priv->gpll_hz = rockchip_pll_get_rate(&rk3128_pll_clks[GPLL],
815efb944b6SElaine Zhang priv->cru, GPLL);
816efb944b6SElaine Zhang rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ / 2);
817efb944b6SElaine Zhang rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ / 2);
818efb944b6SElaine Zhang rockchip_pll_set_rate(&rk3128_pll_clks[GPLL],
819efb944b6SElaine Zhang priv->cru, GPLL, GPLL_HZ);
820efb944b6SElaine Zhang priv->gpll_hz = GPLL_HZ;
821efb944b6SElaine Zhang rk_clrsetreg(&priv->cru->cru_clksel_con[2],
822efb944b6SElaine Zhang NANDC_PLL_SEL_MASK | NANDC_CLK_DIV_MASK,
823efb944b6SElaine Zhang NANDC_PLL_SEL_GPLL << NANDC_PLL_SEL_SHIFT |
824efb944b6SElaine Zhang 3 << NANDC_CLK_DIV_SHIFT);
825a2795c33SDingqiang Lin rk_clrsetreg(&priv->cru->cru_clksel_con[11],
826a2795c33SDingqiang Lin SFC_PLL_SEL_MASK | SFC_CLK_DIV_MASK,
827a2795c33SDingqiang Lin SFC_PLL_SEL_GPLL << SFC_PLL_SEL_SHIFT |
828a2795c33SDingqiang Lin 9 << SFC_CLK_DIV_SHIFT);
829a2795c33SDingqiang Lin
830efb944b6SElaine Zhang rk3128_bus_set_clk(priv, ACLK_CPU, ACLK_BUS_HZ);
831efb944b6SElaine Zhang rk3128_bus_set_clk(priv, HCLK_CPU, ACLK_BUS_HZ / 2);
832efb944b6SElaine Zhang rk3128_bus_set_clk(priv, PCLK_CPU, ACLK_BUS_HZ / 2);
833efb944b6SElaine Zhang rk3128_peri_set_clk(priv, ACLK_PERI, ACLK_PERI_HZ);
834efb944b6SElaine Zhang rk3128_peri_set_clk(priv, HCLK_PERI, ACLK_PERI_HZ / 2);
835efb944b6SElaine Zhang rk3128_peri_set_clk(priv, PCLK_PERI, ACLK_PERI_HZ / 2);
836ba5fededSElaine Zhang
837ba5fededSElaine Zhang rockchip_pll_set_rate(&rk3128_pll_clks[CPLL],
838ba5fededSElaine Zhang priv->cru, CPLL, CPLL_HZ);
839efb944b6SElaine Zhang }
840efb944b6SElaine Zhang
rk3128_clk_probe(struct udevice * dev)84141dd6e98SKever Yang static int rk3128_clk_probe(struct udevice *dev)
84241dd6e98SKever Yang {
84341dd6e98SKever Yang struct rk3128_clk_priv *priv = dev_get_priv(dev);
84441dd6e98SKever Yang
84592c6b642SElaine Zhang priv->sync_kernel = false;
84692c6b642SElaine Zhang if (!priv->armclk_enter_hz)
84792c6b642SElaine Zhang priv->armclk_enter_hz =
84892c6b642SElaine Zhang rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
84992c6b642SElaine Zhang priv->cru, APLL);
850efb944b6SElaine Zhang rkclk_init(priv);
85192c6b642SElaine Zhang if (!priv->armclk_init_hz)
85292c6b642SElaine Zhang priv->armclk_init_hz =
85392c6b642SElaine Zhang rockchip_pll_get_rate(&rk3128_pll_clks[APLL],
85492c6b642SElaine Zhang priv->cru, APLL);
855de4fa243SKever Yang
856de4fa243SKever Yang return 0;
857de4fa243SKever Yang }
858de4fa243SKever Yang
rk3128_clk_bind(struct udevice * dev)859de4fa243SKever Yang static int rk3128_clk_bind(struct udevice *dev)
860de4fa243SKever Yang {
861de4fa243SKever Yang int ret;
8623d555d75SElaine Zhang struct udevice *sys_child, *sf_child;
863fbdd1558SKever Yang struct sysreset_reg *priv;
8643d555d75SElaine Zhang struct softreset_reg *sf_priv;
865de4fa243SKever Yang
866de4fa243SKever Yang /* The reset driver does not have a device node, so bind it here */
867fbdd1558SKever Yang ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset",
868fbdd1558SKever Yang &sys_child);
869fbdd1558SKever Yang if (ret) {
870fbdd1558SKever Yang debug("Warning: No sysreset driver: ret=%d\n", ret);
871fbdd1558SKever Yang } else {
872fbdd1558SKever Yang priv = malloc(sizeof(struct sysreset_reg));
873fbdd1558SKever Yang priv->glb_srst_fst_value = offsetof(struct rk3128_cru,
874fbdd1558SKever Yang cru_glb_srst_fst_value);
875fbdd1558SKever Yang priv->glb_srst_snd_value = offsetof(struct rk3128_cru,
876fbdd1558SKever Yang cru_glb_srst_snd_value);
877fbdd1558SKever Yang sys_child->priv = priv;
878fbdd1558SKever Yang }
879de4fa243SKever Yang
8803d555d75SElaine Zhang ret = device_bind_driver_to_node(dev, "rockchip_reset", "reset",
8813d555d75SElaine Zhang dev_ofnode(dev), &sf_child);
8823d555d75SElaine Zhang if (ret) {
8833d555d75SElaine Zhang debug("Warning: No rockchip reset driver: ret=%d\n", ret);
8843d555d75SElaine Zhang } else {
8853d555d75SElaine Zhang sf_priv = malloc(sizeof(struct softreset_reg));
8863d555d75SElaine Zhang sf_priv->sf_reset_offset = offsetof(struct rk3128_cru,
8873d555d75SElaine Zhang cru_softrst_con[0]);
8883d555d75SElaine Zhang sf_priv->sf_reset_num = 9;
8893d555d75SElaine Zhang sf_child->priv = sf_priv;
8903d555d75SElaine Zhang }
8913d555d75SElaine Zhang
892de4fa243SKever Yang return 0;
893de4fa243SKever Yang }
894de4fa243SKever Yang
895de4fa243SKever Yang static const struct udevice_id rk3128_clk_ids[] = {
896de4fa243SKever Yang { .compatible = "rockchip,rk3128-cru" },
89727e702b6SKever Yang { .compatible = "rockchip,rk3126-cru" },
898de4fa243SKever Yang { }
899de4fa243SKever Yang };
900de4fa243SKever Yang
901de4fa243SKever Yang U_BOOT_DRIVER(rockchip_rk3128_cru) = {
902de4fa243SKever Yang .name = "clk_rk3128",
903de4fa243SKever Yang .id = UCLASS_CLK,
904de4fa243SKever Yang .of_match = rk3128_clk_ids,
905de4fa243SKever Yang .priv_auto_alloc_size = sizeof(struct rk3128_clk_priv),
90641dd6e98SKever Yang .ofdata_to_platdata = rk3128_clk_ofdata_to_platdata,
907de4fa243SKever Yang .ops = &rk3128_clk_ops,
908de4fa243SKever Yang .bind = rk3128_clk_bind,
909de4fa243SKever Yang .probe = rk3128_clk_probe,
910de4fa243SKever Yang };
911efb944b6SElaine Zhang
912efb944b6SElaine Zhang #ifndef CONFIG_SPL_BUILD
913efb944b6SElaine Zhang /**
914efb944b6SElaine Zhang * soc_clk_dump() - Print clock frequencies
915efb944b6SElaine Zhang * Returns zero on success
916efb944b6SElaine Zhang *
917efb944b6SElaine Zhang * Implementation for the clk dump command.
918efb944b6SElaine Zhang */
soc_clk_dump(void)919efb944b6SElaine Zhang int soc_clk_dump(void)
920efb944b6SElaine Zhang {
921efb944b6SElaine Zhang struct udevice *cru_dev;
92292c6b642SElaine Zhang struct rk3128_clk_priv *priv;
923efb944b6SElaine Zhang const struct rk3128_clk_info *clk_dump;
924efb944b6SElaine Zhang struct clk clk;
925efb944b6SElaine Zhang unsigned long clk_count = ARRAY_SIZE(clks_dump);
926efb944b6SElaine Zhang unsigned long rate;
927efb944b6SElaine Zhang int i, ret;
928efb944b6SElaine Zhang
929efb944b6SElaine Zhang ret = uclass_get_device_by_driver(UCLASS_CLK,
930efb944b6SElaine Zhang DM_GET_DRIVER(rockchip_rk3128_cru),
931efb944b6SElaine Zhang &cru_dev);
932efb944b6SElaine Zhang if (ret) {
933efb944b6SElaine Zhang printf("%s failed to get cru device\n", __func__);
934efb944b6SElaine Zhang return ret;
935efb944b6SElaine Zhang }
936efb944b6SElaine Zhang
93792c6b642SElaine Zhang priv = dev_get_priv(cru_dev);
93892c6b642SElaine Zhang printf("CLK: (%s. arm: enter %lu KHz, init %lu KHz, kernel %lu%s)\n",
93992c6b642SElaine Zhang priv->sync_kernel ? "sync kernel" : "uboot",
94092c6b642SElaine Zhang priv->armclk_enter_hz / 1000,
94192c6b642SElaine Zhang priv->armclk_init_hz / 1000,
94292c6b642SElaine Zhang priv->set_armclk_rate ? priv->armclk_hz / 1000 : 0,
94392c6b642SElaine Zhang priv->set_armclk_rate ? " KHz" : "N/A");
944efb944b6SElaine Zhang for (i = 0; i < clk_count; i++) {
945efb944b6SElaine Zhang clk_dump = &clks_dump[i];
946efb944b6SElaine Zhang if (clk_dump->name) {
947efb944b6SElaine Zhang clk.id = clk_dump->id;
948efb944b6SElaine Zhang if (clk_dump->is_cru)
949efb944b6SElaine Zhang ret = clk_request(cru_dev, &clk);
950efb944b6SElaine Zhang if (ret < 0)
951efb944b6SElaine Zhang return ret;
952efb944b6SElaine Zhang
953efb944b6SElaine Zhang rate = clk_get_rate(&clk);
954efb944b6SElaine Zhang clk_free(&clk);
955efb944b6SElaine Zhang if (i == 0) {
956efb944b6SElaine Zhang if (rate < 0)
95792c6b642SElaine Zhang printf(" %s %s\n", clk_dump->name,
958efb944b6SElaine Zhang "unknown");
959efb944b6SElaine Zhang else
96092c6b642SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
96192c6b642SElaine Zhang rate / 1000);
962efb944b6SElaine Zhang } else {
963efb944b6SElaine Zhang if (rate < 0)
96492c6b642SElaine Zhang printf(" %s %s\n", clk_dump->name,
965efb944b6SElaine Zhang "unknown");
966efb944b6SElaine Zhang else
96792c6b642SElaine Zhang printf(" %s %lu KHz\n", clk_dump->name,
96892c6b642SElaine Zhang rate / 1000);
969efb944b6SElaine Zhang }
970efb944b6SElaine Zhang }
971efb944b6SElaine Zhang }
972efb944b6SElaine Zhang
973efb944b6SElaine Zhang return 0;
974efb944b6SElaine Zhang }
975efb944b6SElaine Zhang #endif
976efb944b6SElaine Zhang
977