Merge git://git.denx.de/u-boot-rockchip
[oweals/u-boot.git] / drivers / clk / rockchip / clk_rk3036.c
1 /*
2  * (C) Copyright 2015 Google, Inc
3  *
4  * SPDX-License-Identifier:     GPL-2.0
5  */
6
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <syscon.h>
12 #include <asm/io.h>
13 #include <asm/arch/clock.h>
14 #include <asm/arch/cru_rk3036.h>
15 #include <asm/arch/hardware.h>
16 #include <dm/lists.h>
17 #include <dt-bindings/clock/rk3036-cru.h>
18 #include <linux/log2.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 enum {
23         VCO_MAX_HZ      = 2400U * 1000000,
24         VCO_MIN_HZ      = 600 * 1000000,
25         OUTPUT_MAX_HZ   = 2400U * 1000000,
26         OUTPUT_MIN_HZ   = 24 * 1000000,
27 };
28
29 #define RATE_TO_DIV(input_rate, output_rate) \
30         ((input_rate) / (output_rate) - 1);
31
32 #define DIV_TO_RATE(input_rate, div)    ((input_rate) / ((div) + 1))
33
34 #define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
35         .refdiv = _refdiv,\
36         .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
37         .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
38         _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
39                          OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
40                          #hz "Hz cannot be hit with PLL "\
41                          "divisors on line " __stringify(__LINE__));
42
43 /* use interge mode*/
44 static const struct pll_div apll_init_cfg = PLL_DIVISORS(APLL_HZ, 1, 3, 1);
45 static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
46
47 static int rkclk_set_pll(struct rk3036_cru *cru, enum rk_clk_id clk_id,
48                          const struct pll_div *div)
49 {
50         int pll_id = rk_pll_id(clk_id);
51         struct rk3036_pll *pll = &cru->pll[pll_id];
52
53         /* All PLLs have same VCO and output frequency range restrictions. */
54         uint vco_hz = OSC_HZ / 1000 * div->fbdiv / div->refdiv * 1000;
55         uint output_hz = vco_hz / div->postdiv1 / div->postdiv2;
56
57         debug("PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, postdiv2=%d,\
58                  vco=%u Hz, output=%u Hz\n",
59                         pll, div->fbdiv, div->refdiv, div->postdiv1,
60                         div->postdiv2, vco_hz, output_hz);
61         assert(vco_hz >= VCO_MIN_HZ && vco_hz <= VCO_MAX_HZ &&
62                output_hz >= OUTPUT_MIN_HZ && output_hz <= OUTPUT_MAX_HZ);
63
64         /* use interger mode */
65         rk_clrreg(&pll->con1, 1 << PLL_DSMPD_SHIFT);
66
67         rk_clrsetreg(&pll->con0,
68                      PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT | PLL_FBDIV_MASK,
69                      (div->postdiv1 << PLL_POSTDIV1_SHIFT) | div->fbdiv);
70         rk_clrsetreg(&pll->con1, PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
71                         PLL_REFDIV_MASK << PLL_REFDIV_SHIFT,
72                         (div->postdiv2 << PLL_POSTDIV2_SHIFT |
73                          div->refdiv << PLL_REFDIV_SHIFT));
74
75         /* waiting for pll lock */
76         while (readl(&pll->con1) & (1 << PLL_LOCK_STATUS_SHIFT))
77                 udelay(1);
78
79         return 0;
80 }
81
82 static void rkclk_init(struct rk3036_cru *cru)
83 {
84         u32 aclk_div;
85         u32 hclk_div;
86         u32 pclk_div;
87
88         /* pll enter slow-mode */
89         rk_clrsetreg(&cru->cru_mode_con,
90                      GPLL_MODE_MASK << GPLL_MODE_SHIFT |
91                      APLL_MODE_MASK << APLL_MODE_SHIFT,
92                      GPLL_MODE_SLOW << GPLL_MODE_SHIFT |
93                      APLL_MODE_SLOW << APLL_MODE_SHIFT);
94
95         /* init pll */
96         rkclk_set_pll(cru, CLK_ARM, &apll_init_cfg);
97         rkclk_set_pll(cru, CLK_GENERAL, &gpll_init_cfg);
98
99         /*
100          * select apll as core clock pll source and
101          * set up dependent divisors for PCLK/HCLK and ACLK clocks.
102          * core hz : apll = 1:1
103          */
104         aclk_div = APLL_HZ / CORE_ACLK_HZ - 1;
105         assert((aclk_div + 1) * CORE_ACLK_HZ == APLL_HZ && aclk_div < 0x7);
106
107         pclk_div = APLL_HZ / CORE_PERI_HZ - 1;
108         assert((pclk_div + 1) * CORE_PERI_HZ == APLL_HZ && pclk_div < 0xf);
109
110         rk_clrsetreg(&cru->cru_clksel_con[0],
111                      CORE_CLK_PLL_SEL_MASK << CORE_CLK_PLL_SEL_SHIFT |
112                      CORE_DIV_CON_MASK << CORE_DIV_CON_SHIFT,
113                      CORE_CLK_PLL_SEL_APLL << CORE_CLK_PLL_SEL_SHIFT |
114                      0 << CORE_DIV_CON_SHIFT);
115
116         rk_clrsetreg(&cru->cru_clksel_con[1],
117                      CORE_ACLK_DIV_MASK << CORE_ACLK_DIV_SHIFT |
118                      CORE_PERI_DIV_MASK << CORE_PERI_DIV_SHIFT,
119                      aclk_div << CORE_ACLK_DIV_SHIFT |
120                      pclk_div << CORE_PERI_DIV_SHIFT);
121
122         /*
123          * select apll as cpu clock pll source and
124          * set up dependent divisors for PCLK/HCLK and ACLK clocks.
125          */
126         aclk_div = APLL_HZ / CPU_ACLK_HZ - 1;
127         assert((aclk_div + 1) * CPU_ACLK_HZ == APLL_HZ && aclk_div < 0x1f);
128
129         pclk_div = APLL_HZ / CPU_PCLK_HZ - 1;
130         assert((pclk_div + 1) * CPU_PCLK_HZ == APLL_HZ && pclk_div < 0x7);
131
132         hclk_div = APLL_HZ / CPU_HCLK_HZ - 1;
133         assert((hclk_div + 1) * CPU_HCLK_HZ == APLL_HZ && hclk_div < 0x3);
134
135         rk_clrsetreg(&cru->cru_clksel_con[0],
136                      CPU_CLK_PLL_SEL_MASK << CPU_CLK_PLL_SEL_SHIFT |
137                      ACLK_CPU_DIV_MASK << ACLK_CPU_DIV_SHIFT,
138                      CPU_CLK_PLL_SEL_APLL << CPU_CLK_PLL_SEL_SHIFT |
139                      aclk_div << ACLK_CPU_DIV_SHIFT);
140
141         rk_clrsetreg(&cru->cru_clksel_con[1],
142                      CPU_PCLK_DIV_MASK << CPU_PCLK_DIV_SHIFT |
143                      CPU_HCLK_DIV_MASK << CPU_HCLK_DIV_SHIFT,
144                      pclk_div << CPU_PCLK_DIV_SHIFT |
145                      hclk_div << CPU_HCLK_DIV_SHIFT);
146
147         /*
148          * select gpll as peri clock pll source and
149          * set up dependent divisors for PCLK/HCLK and ACLK clocks.
150          */
151         aclk_div = GPLL_HZ / PERI_ACLK_HZ - 1;
152         assert((aclk_div + 1) * PERI_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
153
154         hclk_div = ilog2(PERI_ACLK_HZ / PERI_HCLK_HZ);
155         assert((1 << hclk_div) * PERI_HCLK_HZ ==
156                 PERI_ACLK_HZ && (pclk_div < 0x4));
157
158         pclk_div = ilog2(PERI_ACLK_HZ / PERI_PCLK_HZ);
159         assert((1 << pclk_div) * PERI_PCLK_HZ ==
160                 PERI_ACLK_HZ && pclk_div < 0x8);
161
162         rk_clrsetreg(&cru->cru_clksel_con[10],
163                      PERI_PLL_SEL_MASK << PERI_PLL_SEL_SHIFT |
164                      PERI_PCLK_DIV_MASK << PERI_PCLK_DIV_SHIFT |
165                      PERI_HCLK_DIV_MASK << PERI_HCLK_DIV_SHIFT |
166                      PERI_ACLK_DIV_MASK << PERI_ACLK_DIV_SHIFT,
167                      PERI_PLL_GPLL << PERI_PLL_SEL_SHIFT |
168                      pclk_div << PERI_PCLK_DIV_SHIFT |
169                      hclk_div << PERI_HCLK_DIV_SHIFT |
170                      aclk_div << PERI_ACLK_DIV_SHIFT);
171
172         /* PLL enter normal-mode */
173         rk_clrsetreg(&cru->cru_mode_con,
174                      GPLL_MODE_MASK << GPLL_MODE_SHIFT |
175                      APLL_MODE_MASK << APLL_MODE_SHIFT,
176                      GPLL_MODE_NORM << GPLL_MODE_SHIFT |
177                      APLL_MODE_NORM << APLL_MODE_SHIFT);
178 }
179
180 /* Get pll rate by id */
181 static uint32_t rkclk_pll_get_rate(struct rk3036_cru *cru,
182                                    enum rk_clk_id clk_id)
183 {
184         uint32_t refdiv, fbdiv, postdiv1, postdiv2;
185         uint32_t con;
186         int pll_id = rk_pll_id(clk_id);
187         struct rk3036_pll *pll = &cru->pll[pll_id];
188         static u8 clk_shift[CLK_COUNT] = {
189                 0xff, APLL_MODE_SHIFT, DPLL_MODE_SHIFT, 0xff,
190                 GPLL_MODE_SHIFT, 0xff
191         };
192         static u8 clk_mask[CLK_COUNT] = {
193                 0xff, APLL_MODE_MASK, DPLL_MODE_MASK, 0xff,
194                 GPLL_MODE_MASK, 0xff
195         };
196         uint shift;
197         uint mask;
198
199         con = readl(&cru->cru_mode_con);
200         shift = clk_shift[clk_id];
201         mask = clk_mask[clk_id];
202
203         switch ((con >> shift) & mask) {
204         case GPLL_MODE_SLOW:
205                 return OSC_HZ;
206         case GPLL_MODE_NORM:
207
208                 /* normal mode */
209                 con = readl(&pll->con0);
210                 postdiv1 = (con >> PLL_POSTDIV1_SHIFT) & PLL_POSTDIV1_MASK;
211                 fbdiv = (con >> PLL_FBDIV_SHIFT) & PLL_FBDIV_MASK;
212                 con = readl(&pll->con1);
213                 postdiv2 = (con >> PLL_POSTDIV2_SHIFT) & PLL_POSTDIV2_MASK;
214                 refdiv = (con >> PLL_REFDIV_SHIFT) & PLL_REFDIV_MASK;
215                 return (24 * fbdiv / (refdiv * postdiv1 * postdiv2)) * 1000000;
216         case GPLL_MODE_DEEP:
217         default:
218                 return 32768;
219         }
220 }
221
222 static ulong rockchip_mmc_get_clk(struct rk3036_cru *cru, uint clk_general_rate,
223                                   int periph)
224 {
225         uint src_rate;
226         uint div, mux;
227         u32 con;
228
229         switch (periph) {
230         case HCLK_EMMC:
231                 con = readl(&cru->cru_clksel_con[12]);
232                 mux = (con >> EMMC_PLL_SHIFT) & EMMC_PLL_MASK;
233                 div = (con >> EMMC_DIV_SHIFT) & EMMC_DIV_MASK;
234                 break;
235         case HCLK_SDIO:
236                 con = readl(&cru->cru_clksel_con[12]);
237                 mux = (con >> MMC0_PLL_SHIFT) & MMC0_PLL_MASK;
238                 div = (con >> MMC0_DIV_SHIFT) & MMC0_DIV_MASK;
239                 break;
240         default:
241                 return -EINVAL;
242         }
243
244         src_rate = mux == EMMC_SEL_24M ? OSC_HZ : clk_general_rate;
245         return DIV_TO_RATE(src_rate, div);
246 }
247
248 static ulong rockchip_mmc_set_clk(struct rk3036_cru *cru, uint clk_general_rate,
249                                   int periph, uint freq)
250 {
251         int src_clk_div;
252         int mux;
253
254         debug("%s: clk_general_rate=%u\n", __func__, clk_general_rate);
255
256         /* mmc clock auto divide 2 in internal */
257         src_clk_div = (clk_general_rate / 2 + freq - 1) / freq;
258
259         if (src_clk_div > 0x7f) {
260                 src_clk_div = (OSC_HZ / 2 + freq - 1) / freq;
261                 mux = EMMC_SEL_24M;
262         } else {
263                 mux = EMMC_SEL_GPLL;
264         }
265
266         switch (periph) {
267         case HCLK_EMMC:
268                 rk_clrsetreg(&cru->cru_clksel_con[12],
269                              EMMC_PLL_MASK << EMMC_PLL_SHIFT |
270                              EMMC_DIV_MASK << EMMC_DIV_SHIFT,
271                              mux << EMMC_PLL_SHIFT |
272                              (src_clk_div - 1) << EMMC_DIV_SHIFT);
273                 break;
274         case HCLK_SDIO:
275                 rk_clrsetreg(&cru->cru_clksel_con[11],
276                              MMC0_PLL_MASK << MMC0_PLL_SHIFT |
277                              MMC0_DIV_MASK << MMC0_DIV_SHIFT,
278                              mux << MMC0_PLL_SHIFT |
279                              (src_clk_div - 1) << MMC0_DIV_SHIFT);
280                 break;
281         default:
282                 return -EINVAL;
283         }
284
285         return rockchip_mmc_get_clk(cru, clk_general_rate, periph);
286 }
287
288 static ulong rk3036_clk_get_rate(struct clk *clk)
289 {
290         struct rk3036_clk_priv *priv = dev_get_priv(clk->dev);
291
292         switch (clk->id) {
293         case 0 ... 63:
294                 return rkclk_pll_get_rate(priv->cru, clk->id);
295         default:
296                 return -ENOENT;
297         }
298 }
299
300 static ulong rk3036_clk_set_rate(struct clk *clk, ulong rate)
301 {
302         struct rk3036_clk_priv *priv = dev_get_priv(clk->dev);
303         ulong new_rate, gclk_rate;
304
305         gclk_rate = rkclk_pll_get_rate(priv->cru, CLK_GENERAL);
306         switch (clk->id) {
307         case 0 ... 63:
308                 return 0;
309         case HCLK_EMMC:
310                 new_rate = rockchip_mmc_set_clk(priv->cru, gclk_rate,
311                                                 clk->id, rate);
312                 break;
313         default:
314                 return -ENOENT;
315         }
316
317         return new_rate;
318 }
319
320 static struct clk_ops rk3036_clk_ops = {
321         .get_rate       = rk3036_clk_get_rate,
322         .set_rate       = rk3036_clk_set_rate,
323 };
324
325 static int rk3036_clk_probe(struct udevice *dev)
326 {
327         struct rk3036_clk_priv *priv = dev_get_priv(dev);
328
329         priv->cru = (struct rk3036_cru *)dev_get_addr(dev);
330         rkclk_init(priv->cru);
331
332         return 0;
333 }
334
335 static int rk3036_clk_bind(struct udevice *dev)
336 {
337         int ret;
338
339         /* The reset driver does not have a device node, so bind it here */
340         ret = device_bind_driver(gd->dm_root, "rk3036_sysreset", "reset", &dev);
341         if (ret)
342                 debug("Warning: No RK3036 reset driver: ret=%d\n", ret);
343
344         return 0;
345 }
346
347 static const struct udevice_id rk3036_clk_ids[] = {
348         { .compatible = "rockchip,rk3036-cru" },
349         { }
350 };
351
352 U_BOOT_DRIVER(rockchip_rk3036_cru) = {
353         .name           = "clk_rk3036",
354         .id             = UCLASS_CLK,
355         .of_match       = rk3036_clk_ids,
356         .priv_auto_alloc_size = sizeof(struct rk3036_clk_priv),
357         .ops            = &rk3036_clk_ops,
358         .bind           = rk3036_clk_bind,
359         .probe          = rk3036_clk_probe,
360 };