]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0 |
41793000 KY |
2 | /* |
3 | * (C) Copyright 2017 Rockchip Electronics Co., Ltd | |
41793000 KY |
4 | */ |
5 | ||
6 | #include <common.h> | |
b375d841 | 7 | #include <bitfield.h> |
41793000 KY |
8 | #include <clk-uclass.h> |
9 | #include <dm.h> | |
10 | #include <errno.h> | |
11 | #include <syscon.h> | |
12 | #include <asm/arch/clock.h> | |
13 | #include <asm/arch/cru_rk3328.h> | |
14 | #include <asm/arch/hardware.h> | |
7cd4ebab | 15 | #include <asm/arch/grf_rk3328.h> |
41793000 KY |
16 | #include <asm/io.h> |
17 | #include <dm/lists.h> | |
18 | #include <dt-bindings/clock/rk3328-cru.h> | |
19 | ||
41793000 KY |
20 | struct pll_div { |
21 | u32 refdiv; | |
22 | u32 fbdiv; | |
23 | u32 postdiv1; | |
24 | u32 postdiv2; | |
25 | u32 frac; | |
26 | }; | |
27 | ||
28 | #define RATE_TO_DIV(input_rate, output_rate) \ | |
29 | ((input_rate) / (output_rate) - 1); | |
30 | #define DIV_TO_RATE(input_rate, div) ((input_rate) / ((div) + 1)) | |
31 | ||
32 | #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\ | |
33 | .refdiv = _refdiv,\ | |
34 | .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\ | |
35 | .postdiv1 = _postdiv1, .postdiv2 = _postdiv2}; | |
36 | ||
37 | static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 1, 4, 1); | |
38 | static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 2, 2, 1); | |
39 | ||
40 | static const struct pll_div apll_816_cfg = PLL_DIVISORS(816 * MHz, 1, 2, 1); | |
41 | static const struct pll_div apll_600_cfg = PLL_DIVISORS(600 * MHz, 1, 3, 1); | |
42 | ||
43 | static const struct pll_div *apll_cfgs[] = { | |
44 | [APLL_816_MHZ] = &apll_816_cfg, | |
45 | [APLL_600_MHZ] = &apll_600_cfg, | |
46 | }; | |
47 | ||
48 | enum { | |
49 | /* PLL_CON0 */ | |
50 | PLL_POSTDIV1_SHIFT = 12, | |
51 | PLL_POSTDIV1_MASK = 0x7 << PLL_POSTDIV1_SHIFT, | |
52 | PLL_FBDIV_SHIFT = 0, | |
53 | PLL_FBDIV_MASK = 0xfff, | |
54 | ||
55 | /* PLL_CON1 */ | |
56 | PLL_DSMPD_SHIFT = 12, | |
57 | PLL_DSMPD_MASK = 1 << PLL_DSMPD_SHIFT, | |
58 | PLL_INTEGER_MODE = 1, | |
59 | PLL_LOCK_STATUS_SHIFT = 10, | |
60 | PLL_LOCK_STATUS_MASK = 1 << PLL_LOCK_STATUS_SHIFT, | |
61 | PLL_POSTDIV2_SHIFT = 6, | |
62 | PLL_POSTDIV2_MASK = 0x7 << PLL_POSTDIV2_SHIFT, | |
63 | PLL_REFDIV_SHIFT = 0, | |
64 | PLL_REFDIV_MASK = 0x3f, | |
65 | ||
66 | /* PLL_CON2 */ | |
67 | PLL_FRACDIV_SHIFT = 0, | |
68 | PLL_FRACDIV_MASK = 0xffffff, | |
69 | ||
70 | /* MODE_CON */ | |
71 | APLL_MODE_SHIFT = 0, | |
72 | NPLL_MODE_SHIFT = 1, | |
73 | DPLL_MODE_SHIFT = 4, | |
74 | CPLL_MODE_SHIFT = 8, | |
75 | GPLL_MODE_SHIFT = 12, | |
76 | PLL_MODE_SLOW = 0, | |
77 | PLL_MODE_NORM, | |
78 | ||
79 | /* CLKSEL_CON0 */ | |
80 | CLK_CORE_PLL_SEL_APLL = 0, | |
81 | CLK_CORE_PLL_SEL_GPLL, | |
82 | CLK_CORE_PLL_SEL_DPLL, | |
83 | CLK_CORE_PLL_SEL_NPLL, | |
84 | CLK_CORE_PLL_SEL_SHIFT = 6, | |
85 | CLK_CORE_PLL_SEL_MASK = 3 << CLK_CORE_PLL_SEL_SHIFT, | |
86 | CLK_CORE_DIV_SHIFT = 0, | |
87 | CLK_CORE_DIV_MASK = 0x1f, | |
88 | ||
89 | /* CLKSEL_CON1 */ | |
90 | ACLKM_CORE_DIV_SHIFT = 4, | |
91 | ACLKM_CORE_DIV_MASK = 0x7 << ACLKM_CORE_DIV_SHIFT, | |
92 | PCLK_DBG_DIV_SHIFT = 0, | |
93 | PCLK_DBG_DIV_MASK = 0xF << PCLK_DBG_DIV_SHIFT, | |
94 | ||
7cd4ebab DW |
95 | /* CLKSEL_CON27 */ |
96 | GMAC2IO_PLL_SEL_SHIFT = 7, | |
97 | GMAC2IO_PLL_SEL_MASK = 1 << GMAC2IO_PLL_SEL_SHIFT, | |
98 | GMAC2IO_PLL_SEL_CPLL = 0, | |
99 | GMAC2IO_PLL_SEL_GPLL = 1, | |
100 | GMAC2IO_CLK_DIV_MASK = 0x1f, | |
101 | GMAC2IO_CLK_DIV_SHIFT = 0, | |
102 | ||
41793000 KY |
103 | /* CLKSEL_CON28 */ |
104 | ACLK_PERIHP_PLL_SEL_CPLL = 0, | |
105 | ACLK_PERIHP_PLL_SEL_GPLL, | |
106 | ACLK_PERIHP_PLL_SEL_HDMIPHY, | |
107 | ACLK_PERIHP_PLL_SEL_SHIFT = 6, | |
108 | ACLK_PERIHP_PLL_SEL_MASK = 3 << ACLK_PERIHP_PLL_SEL_SHIFT, | |
109 | ACLK_PERIHP_DIV_CON_SHIFT = 0, | |
110 | ACLK_PERIHP_DIV_CON_MASK = 0x1f, | |
111 | ||
112 | /* CLKSEL_CON29 */ | |
113 | PCLK_PERIHP_DIV_CON_SHIFT = 4, | |
114 | PCLK_PERIHP_DIV_CON_MASK = 0x7 << PCLK_PERIHP_DIV_CON_SHIFT, | |
115 | HCLK_PERIHP_DIV_CON_SHIFT = 0, | |
116 | HCLK_PERIHP_DIV_CON_MASK = 3 << HCLK_PERIHP_DIV_CON_SHIFT, | |
117 | ||
118 | /* CLKSEL_CON22 */ | |
119 | CLK_TSADC_DIV_CON_SHIFT = 0, | |
120 | CLK_TSADC_DIV_CON_MASK = 0x3ff, | |
121 | ||
122 | /* CLKSEL_CON23 */ | |
123 | CLK_SARADC_DIV_CON_SHIFT = 0, | |
b375d841 DW |
124 | CLK_SARADC_DIV_CON_MASK = GENMASK(9, 0), |
125 | CLK_SARADC_DIV_CON_WIDTH = 10, | |
41793000 KY |
126 | |
127 | /* CLKSEL_CON24 */ | |
128 | CLK_PWM_PLL_SEL_CPLL = 0, | |
129 | CLK_PWM_PLL_SEL_GPLL, | |
130 | CLK_PWM_PLL_SEL_SHIFT = 15, | |
131 | CLK_PWM_PLL_SEL_MASK = 1 << CLK_PWM_PLL_SEL_SHIFT, | |
132 | CLK_PWM_DIV_CON_SHIFT = 8, | |
133 | CLK_PWM_DIV_CON_MASK = 0x7f << CLK_PWM_DIV_CON_SHIFT, | |
134 | ||
135 | CLK_SPI_PLL_SEL_CPLL = 0, | |
136 | CLK_SPI_PLL_SEL_GPLL, | |
137 | CLK_SPI_PLL_SEL_SHIFT = 7, | |
138 | CLK_SPI_PLL_SEL_MASK = 1 << CLK_SPI_PLL_SEL_SHIFT, | |
139 | CLK_SPI_DIV_CON_SHIFT = 0, | |
140 | CLK_SPI_DIV_CON_MASK = 0x7f << CLK_SPI_DIV_CON_SHIFT, | |
141 | ||
142 | /* CLKSEL_CON30 */ | |
143 | CLK_SDMMC_PLL_SEL_CPLL = 0, | |
144 | CLK_SDMMC_PLL_SEL_GPLL, | |
145 | CLK_SDMMC_PLL_SEL_24M, | |
146 | CLK_SDMMC_PLL_SEL_USBPHY, | |
147 | CLK_SDMMC_PLL_SHIFT = 8, | |
148 | CLK_SDMMC_PLL_MASK = 0x3 << CLK_SDMMC_PLL_SHIFT, | |
149 | CLK_SDMMC_DIV_CON_SHIFT = 0, | |
150 | CLK_SDMMC_DIV_CON_MASK = 0xff << CLK_SDMMC_DIV_CON_SHIFT, | |
151 | ||
152 | /* CLKSEL_CON32 */ | |
153 | CLK_EMMC_PLL_SEL_CPLL = 0, | |
154 | CLK_EMMC_PLL_SEL_GPLL, | |
155 | CLK_EMMC_PLL_SEL_24M, | |
156 | CLK_EMMC_PLL_SEL_USBPHY, | |
157 | CLK_EMMC_PLL_SHIFT = 8, | |
158 | CLK_EMMC_PLL_MASK = 0x3 << CLK_EMMC_PLL_SHIFT, | |
159 | CLK_EMMC_DIV_CON_SHIFT = 0, | |
160 | CLK_EMMC_DIV_CON_MASK = 0xff << CLK_EMMC_DIV_CON_SHIFT, | |
161 | ||
162 | /* CLKSEL_CON34 */ | |
163 | CLK_I2C_PLL_SEL_CPLL = 0, | |
164 | CLK_I2C_PLL_SEL_GPLL, | |
165 | CLK_I2C_DIV_CON_MASK = 0x7f, | |
166 | CLK_I2C_PLL_SEL_MASK = 1, | |
167 | CLK_I2C1_PLL_SEL_SHIFT = 15, | |
168 | CLK_I2C1_DIV_CON_SHIFT = 8, | |
169 | CLK_I2C0_PLL_SEL_SHIFT = 7, | |
170 | CLK_I2C0_DIV_CON_SHIFT = 0, | |
171 | ||
172 | /* CLKSEL_CON35 */ | |
173 | CLK_I2C3_PLL_SEL_SHIFT = 15, | |
174 | CLK_I2C3_DIV_CON_SHIFT = 8, | |
175 | CLK_I2C2_PLL_SEL_SHIFT = 7, | |
176 | CLK_I2C2_DIV_CON_SHIFT = 0, | |
177 | }; | |
178 | ||
179 | #define VCO_MAX_KHZ (3200 * (MHz / KHz)) | |
180 | #define VCO_MIN_KHZ (800 * (MHz / KHz)) | |
181 | #define OUTPUT_MAX_KHZ (3200 * (MHz / KHz)) | |
182 | #define OUTPUT_MIN_KHZ (16 * (MHz / KHz)) | |
183 | ||
184 | /* | |
185 | * the div restructions of pll in integer mode, these are defined in | |
186 | * * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0 | |
187 | */ | |
188 | #define PLL_DIV_MIN 16 | |
189 | #define PLL_DIV_MAX 3200 | |
190 | ||
191 | /* | |
192 | * How to calculate the PLL(from TRM V0.3 Part 1 Page 63): | |
193 | * Formulas also embedded within the Fractional PLL Verilog model: | |
194 | * If DSMPD = 1 (DSM is disabled, "integer mode") | |
195 | * FOUTVCO = FREF / REFDIV * FBDIV | |
196 | * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2 | |
197 | * Where: | |
198 | * FOUTVCO = Fractional PLL non-divided output frequency | |
199 | * FOUTPOSTDIV = Fractional PLL divided output frequency | |
200 | * (output of second post divider) | |
201 | * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input) | |
202 | * REFDIV = Fractional PLL input reference clock divider | |
203 | * FBDIV = Integer value programmed into feedback divide | |
204 | * | |
205 | */ | |
206 | static void rkclk_set_pll(struct rk3328_cru *cru, enum rk_clk_id clk_id, | |
207 | const struct pll_div *div) | |
208 | { | |
209 | u32 *pll_con; | |
210 | u32 mode_shift, mode_mask; | |
211 | ||
212 | pll_con = NULL; | |
213 | mode_shift = 0; | |
214 | switch (clk_id) { | |
215 | case CLK_ARM: | |
216 | pll_con = cru->apll_con; | |
217 | mode_shift = APLL_MODE_SHIFT; | |
218 | break; | |
219 | case CLK_DDR: | |
220 | pll_con = cru->dpll_con; | |
221 | mode_shift = DPLL_MODE_SHIFT; | |
222 | break; | |
223 | case CLK_CODEC: | |
224 | pll_con = cru->cpll_con; | |
225 | mode_shift = CPLL_MODE_SHIFT; | |
226 | break; | |
227 | case CLK_GENERAL: | |
228 | pll_con = cru->gpll_con; | |
229 | mode_shift = GPLL_MODE_SHIFT; | |
230 | break; | |
231 | case CLK_NEW: | |
232 | pll_con = cru->npll_con; | |
233 | mode_shift = NPLL_MODE_SHIFT; | |
234 | break; | |
235 | default: | |
236 | break; | |
237 | } | |
238 | mode_mask = 1 << mode_shift; | |
239 | ||
240 | /* All 8 PLLs have same VCO and output frequency range restrictions. */ | |
241 | u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv; | |
242 | u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2; | |
243 | ||
244 | debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, \ | |
245 | postdiv2=%d, vco=%u khz, output=%u khz\n", | |
246 | pll_con, div->fbdiv, div->refdiv, div->postdiv1, | |
247 | div->postdiv2, vco_khz, output_khz); | |
248 | assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ && | |
249 | output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ && | |
250 | div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX); | |
251 | ||
252 | /* | |
253 | * When power on or changing PLL setting, | |
254 | * we must force PLL into slow mode to ensure output stable clock. | |
255 | */ | |
256 | rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_SLOW << mode_shift); | |
257 | ||
258 | /* use integer mode */ | |
259 | rk_clrsetreg(&pll_con[1], PLL_DSMPD_MASK, | |
260 | PLL_INTEGER_MODE << PLL_DSMPD_SHIFT); | |
261 | ||
262 | rk_clrsetreg(&pll_con[0], | |
263 | PLL_FBDIV_MASK | PLL_POSTDIV1_MASK, | |
264 | (div->fbdiv << PLL_FBDIV_SHIFT) | | |
265 | (div->postdiv1 << PLL_POSTDIV1_SHIFT)); | |
266 | rk_clrsetreg(&pll_con[1], | |
267 | PLL_POSTDIV2_MASK | PLL_REFDIV_MASK, | |
268 | (div->postdiv2 << PLL_POSTDIV2_SHIFT) | | |
269 | (div->refdiv << PLL_REFDIV_SHIFT)); | |
270 | ||
271 | /* waiting for pll lock */ | |
272 | while (!(readl(&pll_con[1]) & (1 << PLL_LOCK_STATUS_SHIFT))) | |
273 | udelay(1); | |
274 | ||
275 | /* pll enter normal mode */ | |
276 | rk_clrsetreg(&cru->mode_con, mode_mask, PLL_MODE_NORM << mode_shift); | |
277 | } | |
278 | ||
279 | static void rkclk_init(struct rk3328_cru *cru) | |
280 | { | |
281 | u32 aclk_div; | |
282 | u32 hclk_div; | |
283 | u32 pclk_div; | |
284 | ||
285 | /* configure gpll cpll */ | |
286 | rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg); | |
287 | rkclk_set_pll(cru, CLK_CODEC, &cpll_init_cfg); | |
288 | ||
289 | /* configure perihp aclk, hclk, pclk */ | |
290 | aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1; | |
291 | hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1; | |
292 | pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1; | |
293 | ||
294 | rk_clrsetreg(&cru->clksel_con[28], | |
295 | ACLK_PERIHP_PLL_SEL_MASK | ACLK_PERIHP_DIV_CON_MASK, | |
296 | ACLK_PERIHP_PLL_SEL_GPLL << ACLK_PERIHP_PLL_SEL_SHIFT | | |
297 | aclk_div << ACLK_PERIHP_DIV_CON_SHIFT); | |
298 | rk_clrsetreg(&cru->clksel_con[29], | |
299 | PCLK_PERIHP_DIV_CON_MASK | HCLK_PERIHP_DIV_CON_MASK, | |
300 | pclk_div << PCLK_PERIHP_DIV_CON_SHIFT | | |
301 | hclk_div << HCLK_PERIHP_DIV_CON_SHIFT); | |
302 | } | |
303 | ||
304 | void rk3328_configure_cpu(struct rk3328_cru *cru, | |
305 | enum apll_frequencies apll_freq) | |
306 | { | |
307 | u32 clk_core_div; | |
308 | u32 aclkm_div; | |
309 | u32 pclk_dbg_div; | |
310 | ||
311 | rkclk_set_pll(cru, CLK_ARM, apll_cfgs[apll_freq]); | |
312 | ||
313 | clk_core_div = APLL_HZ / CLK_CORE_HZ - 1; | |
314 | aclkm_div = APLL_HZ / ACLKM_CORE_HZ / (clk_core_div + 1) - 1; | |
315 | pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ / (clk_core_div + 1) - 1; | |
316 | ||
317 | rk_clrsetreg(&cru->clksel_con[0], | |
318 | CLK_CORE_PLL_SEL_MASK | CLK_CORE_DIV_MASK, | |
319 | CLK_CORE_PLL_SEL_APLL << CLK_CORE_PLL_SEL_SHIFT | | |
320 | clk_core_div << CLK_CORE_DIV_SHIFT); | |
321 | ||
322 | rk_clrsetreg(&cru->clksel_con[1], | |
323 | PCLK_DBG_DIV_MASK | ACLKM_CORE_DIV_MASK, | |
324 | pclk_dbg_div << PCLK_DBG_DIV_SHIFT | | |
325 | aclkm_div << ACLKM_CORE_DIV_SHIFT); | |
326 | } | |
327 | ||
328 | ||
329 | static ulong rk3328_i2c_get_clk(struct rk3328_cru *cru, ulong clk_id) | |
330 | { | |
331 | u32 div, con; | |
332 | ||
333 | switch (clk_id) { | |
334 | case SCLK_I2C0: | |
335 | con = readl(&cru->clksel_con[34]); | |
336 | div = con >> CLK_I2C0_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; | |
337 | break; | |
338 | case SCLK_I2C1: | |
339 | con = readl(&cru->clksel_con[34]); | |
340 | div = con >> CLK_I2C1_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; | |
341 | break; | |
342 | case SCLK_I2C2: | |
343 | con = readl(&cru->clksel_con[35]); | |
344 | div = con >> CLK_I2C2_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; | |
345 | break; | |
346 | case SCLK_I2C3: | |
347 | con = readl(&cru->clksel_con[35]); | |
348 | div = con >> CLK_I2C3_DIV_CON_SHIFT & CLK_I2C_DIV_CON_MASK; | |
349 | break; | |
350 | default: | |
351 | printf("do not support this i2c bus\n"); | |
352 | return -EINVAL; | |
353 | } | |
354 | ||
355 | return DIV_TO_RATE(GPLL_HZ, div); | |
356 | } | |
357 | ||
358 | static ulong rk3328_i2c_set_clk(struct rk3328_cru *cru, ulong clk_id, uint hz) | |
359 | { | |
360 | int src_clk_div; | |
361 | ||
362 | src_clk_div = GPLL_HZ / hz; | |
363 | assert(src_clk_div - 1 < 127); | |
364 | ||
365 | switch (clk_id) { | |
366 | case SCLK_I2C0: | |
367 | rk_clrsetreg(&cru->clksel_con[34], | |
368 | CLK_I2C_DIV_CON_MASK << CLK_I2C0_DIV_CON_SHIFT | | |
369 | CLK_I2C_PLL_SEL_MASK << CLK_I2C0_PLL_SEL_SHIFT, | |
370 | (src_clk_div - 1) << CLK_I2C0_DIV_CON_SHIFT | | |
371 | CLK_I2C_PLL_SEL_GPLL << CLK_I2C0_PLL_SEL_SHIFT); | |
372 | break; | |
373 | case SCLK_I2C1: | |
374 | rk_clrsetreg(&cru->clksel_con[34], | |
375 | CLK_I2C_DIV_CON_MASK << CLK_I2C1_DIV_CON_SHIFT | | |
376 | CLK_I2C_PLL_SEL_MASK << CLK_I2C1_PLL_SEL_SHIFT, | |
377 | (src_clk_div - 1) << CLK_I2C1_DIV_CON_SHIFT | | |
378 | CLK_I2C_PLL_SEL_GPLL << CLK_I2C1_PLL_SEL_SHIFT); | |
379 | break; | |
380 | case SCLK_I2C2: | |
381 | rk_clrsetreg(&cru->clksel_con[35], | |
382 | CLK_I2C_DIV_CON_MASK << CLK_I2C2_DIV_CON_SHIFT | | |
383 | CLK_I2C_PLL_SEL_MASK << CLK_I2C2_PLL_SEL_SHIFT, | |
384 | (src_clk_div - 1) << CLK_I2C2_DIV_CON_SHIFT | | |
385 | CLK_I2C_PLL_SEL_GPLL << CLK_I2C2_PLL_SEL_SHIFT); | |
386 | break; | |
387 | case SCLK_I2C3: | |
388 | rk_clrsetreg(&cru->clksel_con[35], | |
389 | CLK_I2C_DIV_CON_MASK << CLK_I2C3_DIV_CON_SHIFT | | |
390 | CLK_I2C_PLL_SEL_MASK << CLK_I2C3_PLL_SEL_SHIFT, | |
391 | (src_clk_div - 1) << CLK_I2C3_DIV_CON_SHIFT | | |
392 | CLK_I2C_PLL_SEL_GPLL << CLK_I2C3_PLL_SEL_SHIFT); | |
393 | break; | |
394 | default: | |
395 | printf("do not support this i2c bus\n"); | |
396 | return -EINVAL; | |
397 | } | |
398 | ||
399 | return DIV_TO_RATE(GPLL_HZ, src_clk_div); | |
400 | } | |
401 | ||
7cd4ebab DW |
402 | static ulong rk3328_gmac2io_set_clk(struct rk3328_cru *cru, ulong rate) |
403 | { | |
404 | struct rk3328_grf_regs *grf; | |
405 | ulong ret; | |
406 | ||
407 | grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
408 | ||
409 | /* | |
410 | * The RGMII CLK can be derived either from an external "clkin" | |
411 | * or can be generated from internally by a divider from SCLK_MAC. | |
412 | */ | |
413 | if (readl(&grf->mac_con[1]) & BIT(10) && | |
414 | readl(&grf->soc_con[4]) & BIT(14)) { | |
415 | /* An external clock will always generate the right rate... */ | |
416 | ret = rate; | |
417 | } else { | |
418 | u32 con = readl(&cru->clksel_con[27]); | |
419 | ulong pll_rate; | |
420 | u8 div; | |
421 | ||
422 | if ((con >> GMAC2IO_PLL_SEL_SHIFT) & GMAC2IO_PLL_SEL_GPLL) | |
423 | pll_rate = GPLL_HZ; | |
424 | else | |
425 | pll_rate = CPLL_HZ; | |
426 | ||
427 | div = DIV_ROUND_UP(pll_rate, rate) - 1; | |
428 | if (div <= 0x1f) | |
429 | rk_clrsetreg(&cru->clksel_con[27], GMAC2IO_CLK_DIV_MASK, | |
430 | div << GMAC2IO_CLK_DIV_SHIFT); | |
431 | else | |
432 | debug("Unsupported div for gmac:%d\n", div); | |
433 | ||
434 | return DIV_TO_RATE(pll_rate, div); | |
435 | } | |
436 | ||
437 | return ret; | |
438 | } | |
439 | ||
41793000 KY |
440 | static ulong rk3328_mmc_get_clk(struct rk3328_cru *cru, uint clk_id) |
441 | { | |
442 | u32 div, con, con_id; | |
443 | ||
444 | switch (clk_id) { | |
445 | case HCLK_SDMMC: | |
85c91cb6 | 446 | case SCLK_SDMMC: |
41793000 KY |
447 | con_id = 30; |
448 | break; | |
449 | case HCLK_EMMC: | |
85c91cb6 | 450 | case SCLK_EMMC: |
41793000 KY |
451 | con_id = 32; |
452 | break; | |
453 | default: | |
454 | return -EINVAL; | |
455 | } | |
456 | con = readl(&cru->clksel_con[con_id]); | |
457 | div = (con & CLK_EMMC_DIV_CON_MASK) >> CLK_EMMC_DIV_CON_SHIFT; | |
458 | ||
459 | if ((con & CLK_EMMC_PLL_MASK) >> CLK_EMMC_PLL_SHIFT | |
460 | == CLK_EMMC_PLL_SEL_24M) | |
3a94d75d | 461 | return DIV_TO_RATE(OSC_HZ, div) / 2; |
41793000 | 462 | else |
3a94d75d | 463 | return DIV_TO_RATE(GPLL_HZ, div) / 2; |
41793000 KY |
464 | } |
465 | ||
466 | static ulong rk3328_mmc_set_clk(struct rk3328_cru *cru, | |
467 | ulong clk_id, ulong set_rate) | |
468 | { | |
469 | int src_clk_div; | |
470 | u32 con_id; | |
471 | ||
472 | switch (clk_id) { | |
473 | case HCLK_SDMMC: | |
85c91cb6 | 474 | case SCLK_SDMMC: |
41793000 KY |
475 | con_id = 30; |
476 | break; | |
477 | case HCLK_EMMC: | |
85c91cb6 | 478 | case SCLK_EMMC: |
41793000 KY |
479 | con_id = 32; |
480 | break; | |
481 | default: | |
482 | return -EINVAL; | |
483 | } | |
484 | /* Select clk_sdmmc/emmc source from GPLL by default */ | |
3a94d75d KY |
485 | /* mmc clock defaulg div 2 internal, need provide double in cru */ |
486 | src_clk_div = DIV_ROUND_UP(GPLL_HZ / 2, set_rate); | |
41793000 KY |
487 | |
488 | if (src_clk_div > 127) { | |
489 | /* use 24MHz source for 400KHz clock */ | |
3a94d75d | 490 | src_clk_div = DIV_ROUND_UP(OSC_HZ / 2, set_rate); |
41793000 KY |
491 | rk_clrsetreg(&cru->clksel_con[con_id], |
492 | CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK, | |
493 | CLK_EMMC_PLL_SEL_24M << CLK_EMMC_PLL_SHIFT | | |
494 | (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT); | |
495 | } else { | |
496 | rk_clrsetreg(&cru->clksel_con[con_id], | |
497 | CLK_EMMC_PLL_MASK | CLK_EMMC_DIV_CON_MASK, | |
498 | CLK_EMMC_PLL_SEL_GPLL << CLK_EMMC_PLL_SHIFT | | |
499 | (src_clk_div - 1) << CLK_EMMC_DIV_CON_SHIFT); | |
500 | } | |
501 | ||
502 | return rk3328_mmc_get_clk(cru, clk_id); | |
503 | } | |
504 | ||
505 | static ulong rk3328_pwm_get_clk(struct rk3328_cru *cru) | |
506 | { | |
507 | u32 div, con; | |
508 | ||
509 | con = readl(&cru->clksel_con[24]); | |
510 | div = (con & CLK_PWM_DIV_CON_MASK) >> CLK_PWM_DIV_CON_SHIFT; | |
511 | ||
512 | return DIV_TO_RATE(GPLL_HZ, div); | |
513 | } | |
514 | ||
515 | static ulong rk3328_pwm_set_clk(struct rk3328_cru *cru, uint hz) | |
516 | { | |
517 | u32 div = GPLL_HZ / hz; | |
518 | ||
519 | rk_clrsetreg(&cru->clksel_con[24], | |
520 | CLK_PWM_PLL_SEL_MASK | CLK_PWM_DIV_CON_MASK, | |
521 | CLK_PWM_PLL_SEL_GPLL << CLK_PWM_PLL_SEL_SHIFT | | |
522 | (div - 1) << CLK_PWM_DIV_CON_SHIFT); | |
523 | ||
524 | return DIV_TO_RATE(GPLL_HZ, div); | |
525 | } | |
526 | ||
b375d841 DW |
527 | static ulong rk3328_saradc_get_clk(struct rk3328_cru *cru) |
528 | { | |
529 | u32 div, val; | |
530 | ||
531 | val = readl(&cru->clksel_con[23]); | |
532 | div = bitfield_extract(val, CLK_SARADC_DIV_CON_SHIFT, | |
533 | CLK_SARADC_DIV_CON_WIDTH); | |
534 | ||
535 | return DIV_TO_RATE(OSC_HZ, div); | |
536 | } | |
537 | ||
538 | static ulong rk3328_saradc_set_clk(struct rk3328_cru *cru, uint hz) | |
539 | { | |
540 | int src_clk_div; | |
541 | ||
542 | src_clk_div = DIV_ROUND_UP(OSC_HZ, hz) - 1; | |
543 | assert(src_clk_div < 128); | |
544 | ||
545 | rk_clrsetreg(&cru->clksel_con[23], | |
546 | CLK_SARADC_DIV_CON_MASK, | |
547 | src_clk_div << CLK_SARADC_DIV_CON_SHIFT); | |
548 | ||
549 | return rk3328_saradc_get_clk(cru); | |
550 | } | |
551 | ||
41793000 KY |
552 | static ulong rk3328_clk_get_rate(struct clk *clk) |
553 | { | |
554 | struct rk3328_clk_priv *priv = dev_get_priv(clk->dev); | |
555 | ulong rate = 0; | |
556 | ||
557 | switch (clk->id) { | |
558 | case 0 ... 29: | |
559 | return 0; | |
560 | case HCLK_SDMMC: | |
561 | case HCLK_EMMC: | |
85c91cb6 XZ |
562 | case SCLK_SDMMC: |
563 | case SCLK_EMMC: | |
41793000 KY |
564 | rate = rk3328_mmc_get_clk(priv->cru, clk->id); |
565 | break; | |
566 | case SCLK_I2C0: | |
567 | case SCLK_I2C1: | |
568 | case SCLK_I2C2: | |
569 | case SCLK_I2C3: | |
570 | rate = rk3328_i2c_get_clk(priv->cru, clk->id); | |
571 | break; | |
572 | case SCLK_PWM: | |
573 | rate = rk3328_pwm_get_clk(priv->cru); | |
574 | break; | |
b375d841 DW |
575 | case SCLK_SARADC: |
576 | rate = rk3328_saradc_get_clk(priv->cru); | |
577 | break; | |
41793000 KY |
578 | default: |
579 | return -ENOENT; | |
580 | } | |
581 | ||
582 | return rate; | |
583 | } | |
584 | ||
585 | static ulong rk3328_clk_set_rate(struct clk *clk, ulong rate) | |
586 | { | |
587 | struct rk3328_clk_priv *priv = dev_get_priv(clk->dev); | |
588 | ulong ret = 0; | |
589 | ||
590 | switch (clk->id) { | |
591 | case 0 ... 29: | |
592 | return 0; | |
593 | case HCLK_SDMMC: | |
594 | case HCLK_EMMC: | |
85c91cb6 XZ |
595 | case SCLK_SDMMC: |
596 | case SCLK_EMMC: | |
41793000 KY |
597 | ret = rk3328_mmc_set_clk(priv->cru, clk->id, rate); |
598 | break; | |
599 | case SCLK_I2C0: | |
600 | case SCLK_I2C1: | |
601 | case SCLK_I2C2: | |
602 | case SCLK_I2C3: | |
603 | ret = rk3328_i2c_set_clk(priv->cru, clk->id, rate); | |
604 | break; | |
7cd4ebab DW |
605 | case SCLK_MAC2IO: |
606 | ret = rk3328_gmac2io_set_clk(priv->cru, rate); | |
607 | break; | |
41793000 KY |
608 | case SCLK_PWM: |
609 | ret = rk3328_pwm_set_clk(priv->cru, rate); | |
610 | break; | |
b375d841 DW |
611 | case SCLK_SARADC: |
612 | ret = rk3328_saradc_set_clk(priv->cru, rate); | |
613 | break; | |
7cd4ebab DW |
614 | case DCLK_LCDC: |
615 | case SCLK_PDM: | |
616 | case SCLK_RTC32K: | |
617 | case SCLK_UART0: | |
618 | case SCLK_UART1: | |
619 | case SCLK_UART2: | |
620 | case SCLK_SDIO: | |
621 | case SCLK_TSP: | |
622 | case SCLK_WIFI: | |
623 | case ACLK_BUS_PRE: | |
624 | case HCLK_BUS_PRE: | |
625 | case PCLK_BUS_PRE: | |
626 | case ACLK_PERI_PRE: | |
627 | case HCLK_PERI: | |
628 | case PCLK_PERI: | |
629 | case ACLK_VIO_PRE: | |
630 | case HCLK_VIO_PRE: | |
631 | case ACLK_RGA_PRE: | |
632 | case SCLK_RGA: | |
633 | case ACLK_VOP_PRE: | |
634 | case ACLK_RKVDEC_PRE: | |
635 | case ACLK_RKVENC: | |
636 | case ACLK_VPU_PRE: | |
637 | case SCLK_VDEC_CABAC: | |
638 | case SCLK_VDEC_CORE: | |
639 | case SCLK_VENC_CORE: | |
640 | case SCLK_VENC_DSP: | |
641 | case SCLK_EFUSE: | |
642 | case PCLK_DDR: | |
643 | case ACLK_GMAC: | |
644 | case PCLK_GMAC: | |
645 | case SCLK_USB3OTG_SUSPEND: | |
646 | return 0; | |
41793000 KY |
647 | default: |
648 | return -ENOENT; | |
649 | } | |
650 | ||
651 | return ret; | |
652 | } | |
653 | ||
7cd4ebab DW |
654 | static int rk3328_gmac2io_set_parent(struct clk *clk, struct clk *parent) |
655 | { | |
656 | struct rk3328_grf_regs *grf; | |
657 | const char *clock_output_name; | |
658 | int ret; | |
659 | ||
660 | grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
661 | ||
662 | /* | |
663 | * If the requested parent is in the same clock-controller and the id | |
664 | * is SCLK_MAC2IO_SRC ("clk_mac2io_src"), switch to the internal clock. | |
665 | */ | |
666 | if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO_SRC)) { | |
667 | debug("%s: switching RGMII to SCLK_MAC2IO_SRC\n", __func__); | |
668 | rk_clrreg(&grf->mac_con[1], BIT(10)); | |
669 | return 0; | |
670 | } | |
671 | ||
672 | /* | |
673 | * Otherwise, we need to check the clock-output-names of the | |
674 | * requested parent to see if the requested id is "gmac_clkin". | |
675 | */ | |
676 | ret = dev_read_string_index(parent->dev, "clock-output-names", | |
677 | parent->id, &clock_output_name); | |
678 | if (ret < 0) | |
679 | return -ENODATA; | |
680 | ||
681 | /* If this is "gmac_clkin", switch to the external clock input */ | |
682 | if (!strcmp(clock_output_name, "gmac_clkin")) { | |
683 | debug("%s: switching RGMII to CLKIN\n", __func__); | |
684 | rk_setreg(&grf->mac_con[1], BIT(10)); | |
685 | return 0; | |
686 | } | |
687 | ||
688 | return -EINVAL; | |
689 | } | |
690 | ||
691 | static int rk3328_gmac2io_ext_set_parent(struct clk *clk, struct clk *parent) | |
692 | { | |
693 | struct rk3328_grf_regs *grf; | |
694 | const char *clock_output_name; | |
695 | int ret; | |
696 | ||
697 | grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
698 | ||
699 | /* | |
700 | * If the requested parent is in the same clock-controller and the id | |
701 | * is SCLK_MAC2IO ("clk_mac2io"), switch to the internal clock. | |
702 | */ | |
703 | if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC2IO)) { | |
704 | debug("%s: switching RGMII to SCLK_MAC2IO\n", __func__); | |
705 | rk_clrreg(&grf->soc_con[4], BIT(14)); | |
706 | return 0; | |
707 | } | |
708 | ||
709 | /* | |
710 | * Otherwise, we need to check the clock-output-names of the | |
711 | * requested parent to see if the requested id is "gmac_clkin". | |
712 | */ | |
713 | ret = dev_read_string_index(parent->dev, "clock-output-names", | |
714 | parent->id, &clock_output_name); | |
715 | if (ret < 0) | |
716 | return -ENODATA; | |
717 | ||
718 | /* If this is "gmac_clkin", switch to the external clock input */ | |
719 | if (!strcmp(clock_output_name, "gmac_clkin")) { | |
720 | debug("%s: switching RGMII to CLKIN\n", __func__); | |
721 | rk_setreg(&grf->soc_con[4], BIT(14)); | |
722 | return 0; | |
723 | } | |
724 | ||
725 | return -EINVAL; | |
726 | } | |
727 | ||
728 | static int rk3328_clk_set_parent(struct clk *clk, struct clk *parent) | |
729 | { | |
730 | switch (clk->id) { | |
731 | case SCLK_MAC2IO: | |
732 | return rk3328_gmac2io_set_parent(clk, parent); | |
733 | case SCLK_MAC2IO_EXT: | |
734 | return rk3328_gmac2io_ext_set_parent(clk, parent); | |
735 | case DCLK_LCDC: | |
736 | case SCLK_PDM: | |
737 | case SCLK_RTC32K: | |
738 | case SCLK_UART0: | |
739 | case SCLK_UART1: | |
740 | case SCLK_UART2: | |
741 | return 0; | |
742 | } | |
743 | ||
744 | debug("%s: unsupported clk %ld\n", __func__, clk->id); | |
745 | return -ENOENT; | |
746 | } | |
747 | ||
41793000 KY |
748 | static struct clk_ops rk3328_clk_ops = { |
749 | .get_rate = rk3328_clk_get_rate, | |
750 | .set_rate = rk3328_clk_set_rate, | |
7cd4ebab | 751 | .set_parent = rk3328_clk_set_parent, |
41793000 KY |
752 | }; |
753 | ||
754 | static int rk3328_clk_probe(struct udevice *dev) | |
755 | { | |
756 | struct rk3328_clk_priv *priv = dev_get_priv(dev); | |
757 | ||
758 | rkclk_init(priv->cru); | |
759 | ||
760 | return 0; | |
761 | } | |
762 | ||
763 | static int rk3328_clk_ofdata_to_platdata(struct udevice *dev) | |
764 | { | |
765 | struct rk3328_clk_priv *priv = dev_get_priv(dev); | |
766 | ||
08516431 | 767 | priv->cru = dev_read_addr_ptr(dev); |
41793000 KY |
768 | |
769 | return 0; | |
770 | } | |
771 | ||
772 | static int rk3328_clk_bind(struct udevice *dev) | |
773 | { | |
774 | int ret; | |
f24e36da KY |
775 | struct udevice *sys_child; |
776 | struct sysreset_reg *priv; | |
41793000 KY |
777 | |
778 | /* The reset driver does not have a device node, so bind it here */ | |
f24e36da KY |
779 | ret = device_bind_driver(dev, "rockchip_sysreset", "sysreset", |
780 | &sys_child); | |
781 | if (ret) { | |
782 | debug("Warning: No sysreset driver: ret=%d\n", ret); | |
783 | } else { | |
784 | priv = malloc(sizeof(struct sysreset_reg)); | |
785 | priv->glb_srst_fst_value = offsetof(struct rk3328_cru, | |
786 | glb_srst_fst_value); | |
787 | priv->glb_srst_snd_value = offsetof(struct rk3328_cru, | |
788 | glb_srst_snd_value); | |
789 | sys_child->priv = priv; | |
790 | } | |
41793000 | 791 | |
538f67c3 EZ |
792 | #if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP) |
793 | ret = offsetof(struct rk3328_cru, softrst_con[0]); | |
794 | ret = rockchip_reset_bind(dev, ret, 12); | |
795 | if (ret) | |
796 | debug("Warning: software reset driver bind faile\n"); | |
797 | #endif | |
798 | ||
41793000 KY |
799 | return ret; |
800 | } | |
801 | ||
802 | static const struct udevice_id rk3328_clk_ids[] = { | |
803 | { .compatible = "rockchip,rk3328-cru" }, | |
804 | { } | |
805 | }; | |
806 | ||
807 | U_BOOT_DRIVER(rockchip_rk3328_cru) = { | |
808 | .name = "rockchip_rk3328_cru", | |
809 | .id = UCLASS_CLK, | |
810 | .of_match = rk3328_clk_ids, | |
811 | .priv_auto_alloc_size = sizeof(struct rk3328_clk_priv), | |
812 | .ofdata_to_platdata = rk3328_clk_ofdata_to_platdata, | |
813 | .ops = &rk3328_clk_ops, | |
814 | .bind = rk3328_clk_bind, | |
815 | .probe = rk3328_clk_probe, | |
816 | }; |