blob: c2a16916322d96f914c445e5718b310671798246 [file] [log] [blame]
huang linc14b54d2016-03-02 18:38:40 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2016 Rockchip Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
huang linc14b54d2016-03-02 18:38:40 +080014 */
15
Lin Huanga1f82a32016-03-09 18:08:20 +080016#include <assert.h>
17#include <console/console.h>
18#include <delay.h>
19#include <soc/addressmap.h>
huang linc14b54d2016-03-02 18:38:40 +080020#include <soc/clock.h>
Lin Huangf5702e72016-03-19 22:45:19 +080021#include <soc/grf.h>
Lin Huanga1f82a32016-03-09 18:08:20 +080022#include <soc/soc.h>
23#include <stdint.h>
24#include <stdlib.h>
25#include <string.h>
26
27struct pll_div {
28 u32 refdiv;
29 u32 fbdiv;
30 u32 postdiv1;
31 u32 postdiv2;
32 u32 frac;
33};
34
35#define PLL_DIVISORS(hz, _refdiv, _postdiv1, _postdiv2) {\
36 .refdiv = _refdiv,\
37 .fbdiv = (u32)((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ),\
38 .postdiv1 = _postdiv1, .postdiv2 = _postdiv2};\
39 _Static_assert(((u64)hz * _refdiv * _postdiv1 * _postdiv2 / OSC_HZ) *\
40 OSC_HZ / (_refdiv * _postdiv1 * _postdiv2) == hz,\
41 #hz "Hz cannot be hit with PLL "\
42 "divisors on line " STRINGIFY(__LINE__))
43
44static const struct pll_div gpll_init_cfg = PLL_DIVISORS(GPLL_HZ, 2, 2, 1);
45static const struct pll_div cpll_init_cfg = PLL_DIVISORS(CPLL_HZ, 1, 2, 2);
46static const struct pll_div ppll_init_cfg = PLL_DIVISORS(PPLL_HZ, 2, 2, 1);
47
48static const struct pll_div apll_l_1600_cfg = PLL_DIVISORS(1600*MHz, 3, 1, 1);
49static const struct pll_div apll_l_600_cfg = PLL_DIVISORS(600*MHz, 1, 2, 1);
50
51static const struct pll_div *apll_l_cfgs[] = {
52 [APLL_L_1600_MHZ] = &apll_l_1600_cfg,
53 [APLL_L_600_MHZ] = &apll_l_600_cfg,
54};
55
56enum {
57 /* PLL_CON0 */
58 PLL_FBDIV_MASK = 0xfff,
59 PLL_FBDIV_SHIFT = 0,
60
61 /* PLL_CON1 */
62 PLL_POSTDIV2_MASK = 0x7,
63 PLL_POSTDIV2_SHIFT = 12,
64 PLL_POSTDIV1_MASK = 0x7,
65 PLL_POSTDIV1_SHIFT = 8,
66 PLL_REFDIV_MASK = 0x3f,
67 PLL_REFDIV_SHIFT = 0,
68
69 /* PLL_CON2 */
70 PLL_LOCK_STATUS_MASK = 1,
71 PLL_LOCK_STATUS_SHIFT = 31,
72 PLL_FRACDIV_MASK = 0xffffff,
73 PLL_FRACDIV_SHIFT = 0,
74
75 /* PLL_CON3 */
76 PLL_MODE_MASK = 3,
77 PLL_MODE_SHIFT = 8,
78 PLL_MODE_SLOW = 0,
79 PLL_MODE_NORM,
80 PLL_MODE_DEEP,
81 PLL_DSMPD_MASK = 1,
82 PLL_DSMPD_SHIFT = 3,
83 PLL_INTEGER_MODE = 1,
84
85 /* PMUCRU_CLKSEL_CON0 */
86 PMU_PCLK_DIV_CON_MASK = 0x1f,
87 PMU_PCLK_DIV_CON_SHIFT = 0,
88
89 /* CLKSEL_CON0 */
90 ACLKM_CORE_L_DIV_CON_MASK = 0x1f,
91 ACLKM_CORE_L_DIV_CON_SHIFT = 8,
92 CLK_CORE_L_PLL_SEL_MASK = 3,
93 CLK_CORE_L_PLL_SEL_SHIFT = 6,
94 CLK_CORE_L_PLL_SEL_ALPLL = 0x0,
95 CLK_CORE_L_PLL_SEL_ABPLL = 0x1,
96 CLK_CORE_L_PLL_SEL_DPLL = 0x10,
97 CLK_CORE_L_PLL_SEL_GPLL = 0x11,
98 CLK_CORE_L_DIV_MASK = 0x1f,
99 CLK_CORE_L_DIV_SHIFT = 0,
100
101 /* CLKSEL_CON1 */
102 PCLK_DBG_L_DIV_MASK = 0x1f,
103 PCLK_DBG_L_DIV_SHIFT = 0x8,
104 ATCLK_CORE_L_DIV_MASK = 0x1f,
105 ATCLK_CORE_L_DIV_SHIFT = 0,
106
107 /* CLKSEL_CON14 */
108 PCLK_PERIHP_DIV_CON_MASK = 0x7,
109 PCLK_PERIHP_DIV_CON_SHIFT = 12,
110 HCLK_PERIHP_DIV_CON_MASK = 3,
111 HCLK_PERIHP_DIV_CON_SHIFT = 8,
112 ACLK_PERIHP_PLL_SEL_MASK = 1,
113 ACLK_PERIHP_PLL_SEL_SHIFT = 7,
114 ACLK_PERIHP_PLL_SEL_CPLL = 0,
115 ACLK_PERIHP_PLL_SEL_GPLL = 1,
116 ACLK_PERIHP_DIV_CON_MASK = 0x1f,
117 ACLK_PERIHP_DIV_CON_SHIFT = 0,
118
119 /* CLKSEL_CON23 */
120 PCLK_PERILP0_DIV_CON_MASK = 0x7,
121 PCLK_PERILP0_DIV_CON_SHIFT = 12,
122 HCLK_PERILP0_DIV_CON_MASK = 3,
123 HCLK_PERILP0_DIV_CON_SHIFT = 8,
124 ACLK_PERILP0_PLL_SEL_MASK = 1,
125 ACLK_PERILP0_PLL_SEL_SHIFT = 7,
126 ACLK_PERILP0_PLL_SEL_CPLL = 0,
127 ACLK_PERILP0_PLL_SEL_GPLL = 1,
128 ACLK_PERILP0_DIV_CON_MASK = 0x1f,
129 ACLK_PERILP0_DIV_CON_SHIFT = 0,
130
131 /* CLKSEL_CON25 */
132 PCLK_PERILP1_DIV_CON_MASK = 0x7,
133 PCLK_PERILP1_DIV_CON_SHIFT = 8,
134 HCLK_PERILP1_PLL_SEL_MASK = 1,
135 HCLK_PERILP1_PLL_SEL_SHIFT = 7,
136 HCLK_PERILP1_PLL_SEL_CPLL = 0,
137 HCLK_PERILP1_PLL_SEL_GPLL = 1,
138 HCLK_PERILP1_DIV_CON_MASK = 0x1f,
139 HCLK_PERILP1_DIV_CON_SHIFT = 0,
Shunqian Zhengce60d5a2016-04-21 23:53:08 +0800140
141 /* CRU_SOFTRST_CON4 */
142 RESETN_DDR0_REQ_MASK = 1,
143 RESETN_DDR0_REQ_SHIFT = 8,
144 RESETN_DDRPHY0_REQ_MASK = 1,
145 RESETN_DDRPHY0_REQ_SHIFT = 9,
146 RESETN_DDR1_REQ_MASK = 1,
147 RESETN_DDR1_REQ_SHIFT = 12,
148 RESETN_DDRPHY1_REQ_MASK = 1,
149 RESETN_DDRPHY1_REQ_SHIFT = 13,
Lin Huanga1f82a32016-03-09 18:08:20 +0800150};
151
152#define VCO_MAX_KHZ (3200 * (MHz / KHz))
153#define VCO_MIN_KHZ (800 * (MHz / KHz))
154#define OUTPUT_MAX_KHZ (3200 * (MHz / KHz))
155#define OUTPUT_MIN_KHZ (16 * (MHz / KHz))
156
157/* the div restrictions of pll in integer mode,
158 * these are defined in * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
159 */
160#define PLL_DIV_MIN 16
161#define PLL_DIV_MAX 3200
162
163/* How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
164 * Formulas also embedded within the Fractional PLL Verilog model:
165 * If DSMPD = 1 (DSM is disabled, "integer mode")
166 * FOUTVCO = FREF / REFDIV * FBDIV
167 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
168 * Where:
169 * FOUTVCO = Fractional PLL non-divided output frequency
170 * FOUTPOSTDIV = Fractional PLL divided output frequency
171 * (output of second post divider)
172 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
173 * REFDIV = Fractional PLL input reference clock divider
174 * FBDIV = Integer value programmed into feedback divide
175 *
176 */
177static void rkclk_set_pll(u32 *pll_con, const struct pll_div *div)
178{
179 /* All 8 PLLs have same VCO and output frequency range restrictions. */
180 u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
181 u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
182
183 printk(BIOS_DEBUG, "PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, "
184 "postdiv2=%d, vco=%u khz, output=%u khz\n",
185 pll_con, div->fbdiv, div->refdiv, div->postdiv1,
186 div->postdiv2, vco_khz, output_khz);
187 assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
188 output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
189 div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
190
191 /* When power on or changing PLL setting,
192 * we must force PLL into slow mode to ensure output stable clock.
193 */
194 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
195 PLL_MODE_SLOW << PLL_MODE_SHIFT));
196
197 /* use integer mode */
198 write32(&pll_con[3],
199 RK_CLRSETBITS(PLL_DSMPD_MASK << PLL_DSMPD_SHIFT,
200 PLL_INTEGER_MODE << PLL_DSMPD_SHIFT));
201
202 write32(&pll_con[0], RK_CLRSETBITS(PLL_FBDIV_MASK << PLL_FBDIV_SHIFT,
203 div->fbdiv << PLL_FBDIV_SHIFT));
204 write32(&pll_con[1],
205 RK_CLRSETBITS(PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
206 PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT |
207 PLL_REFDIV_MASK | PLL_REFDIV_SHIFT,
208 (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
209 (div->postdiv1 << PLL_POSTDIV1_SHIFT) |
210 (div->refdiv << PLL_REFDIV_SHIFT)));
211
212 /* waiting for pll lock */
213 while (!(read32(&pll_con[2]) & (1 << PLL_LOCK_STATUS_SHIFT)))
214 udelay(1);
215
216 /* pll enter normal mode */
217 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
218 PLL_MODE_NORM << PLL_MODE_SHIFT));
219}
220
221void rkclk_init(void)
222{
223 u32 aclk_div;
224 u32 hclk_div;
225 u32 pclk_div;
226
227 /* some cru registers changed by bootrom, we'd better reset them to
228 * reset/default values described in TRM to avoid confusion in kernel.
229 * Please consider these threee lines as a fix of bootrom bug.
230 */
231 write32(&cru_ptr->clksel_con[12], 0xffff4101);
232 write32(&cru_ptr->clksel_con[19], 0xffff033f);
233 write32(&cru_ptr->clksel_con[56], 0x00030003);
234
235 /* configure pmu pll(ppll) */
236 rkclk_set_pll(&pmucru_ptr->ppll_con[0], &ppll_init_cfg);
237
238 /* configure pmu pclk */
239 pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1;
240 assert((pclk_div + 1) * PMU_PCLK_HZ == PPLL_HZ && pclk_div < 0x1f);
241 write32(&pmucru_ptr->pmucru_clksel[0],
242 RK_CLRSETBITS(PMU_PCLK_DIV_CON_MASK << PMU_PCLK_DIV_CON_SHIFT,
243 pclk_div << PMU_PCLK_DIV_CON_SHIFT));
244
245 /* configure gpll cpll */
246 rkclk_set_pll(&cru_ptr->gpll_con[0], &gpll_init_cfg);
247 rkclk_set_pll(&cru_ptr->cpll_con[0], &cpll_init_cfg);
248
249 /* configure perihp aclk, hclk, pclk */
250 aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1;
251 assert((aclk_div + 1) * PERIHP_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
252
253 hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
254 assert((hclk_div + 1) * PERIHP_HCLK_HZ ==
255 PERIHP_ACLK_HZ && (hclk_div < 0x4));
256
257 pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
258 assert((pclk_div + 1) * PERIHP_PCLK_HZ ==
259 PERIHP_ACLK_HZ && (pclk_div < 0x7));
260
261 write32(&cru_ptr->clksel_con[14],
262 RK_CLRSETBITS(PCLK_PERIHP_DIV_CON_MASK <<
263 PCLK_PERIHP_DIV_CON_SHIFT |
264 HCLK_PERIHP_DIV_CON_MASK <<
265 HCLK_PERIHP_DIV_CON_SHIFT |
266 ACLK_PERIHP_PLL_SEL_MASK <<
267 ACLK_PERIHP_PLL_SEL_SHIFT |
268 ACLK_PERIHP_DIV_CON_MASK <<
269 ACLK_PERIHP_DIV_CON_SHIFT,
270 pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
271 hclk_div << HCLK_PERIHP_DIV_CON_SHIFT |
272 ACLK_PERIHP_PLL_SEL_GPLL <<
273 ACLK_PERIHP_PLL_SEL_SHIFT |
274 aclk_div << ACLK_PERIHP_DIV_CON_SHIFT));
275
276 /* configure perilp0 aclk, hclk, pclk */
277 aclk_div = GPLL_HZ / PERILP0_ACLK_HZ - 1;
278 assert((aclk_div + 1) * PERILP0_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
279
280 hclk_div = PERILP0_ACLK_HZ / PERILP0_HCLK_HZ - 1;
281 assert((hclk_div + 1) * PERILP0_HCLK_HZ ==
282 PERILP0_ACLK_HZ && (hclk_div < 0x4));
283
284 pclk_div = PERILP0_ACLK_HZ / PERILP0_PCLK_HZ - 1;
285 assert((pclk_div + 1) * PERILP0_PCLK_HZ ==
286 PERILP0_ACLK_HZ && (pclk_div < 0x7));
287
288 write32(&cru_ptr->clksel_con[23],
289 RK_CLRSETBITS(PCLK_PERILP0_DIV_CON_MASK <<
290 PCLK_PERILP0_DIV_CON_SHIFT |
291 HCLK_PERILP0_DIV_CON_MASK <<
292 HCLK_PERILP0_DIV_CON_SHIFT |
293 ACLK_PERILP0_PLL_SEL_MASK <<
294 ACLK_PERILP0_PLL_SEL_SHIFT |
295 ACLK_PERILP0_DIV_CON_MASK <<
296 ACLK_PERILP0_DIV_CON_SHIFT,
297 pclk_div << PCLK_PERILP0_DIV_CON_SHIFT |
298 hclk_div << HCLK_PERILP0_DIV_CON_SHIFT |
299 ACLK_PERILP0_PLL_SEL_GPLL <<
300 ACLK_PERILP0_PLL_SEL_SHIFT |
301 aclk_div << ACLK_PERILP0_DIV_CON_SHIFT));
302
303 /* perilp1 hclk select gpll as source */
304 hclk_div = GPLL_HZ / PERILP1_HCLK_HZ - 1;
305 assert((hclk_div + 1) * PERILP1_HCLK_HZ ==
306 GPLL_HZ && (hclk_div < 0x1f));
307
308 pclk_div = PERILP1_HCLK_HZ / PERILP1_HCLK_HZ - 1;
309 assert((pclk_div + 1) * PERILP1_HCLK_HZ ==
310 PERILP1_HCLK_HZ && (hclk_div < 0x7));
311
312 write32(&cru_ptr->clksel_con[25],
313 RK_CLRSETBITS(PCLK_PERILP1_DIV_CON_MASK <<
314 PCLK_PERILP1_DIV_CON_SHIFT |
315 HCLK_PERILP1_DIV_CON_MASK <<
316 HCLK_PERILP1_DIV_CON_SHIFT |
317 HCLK_PERILP1_PLL_SEL_MASK <<
318 HCLK_PERILP1_PLL_SEL_SHIFT,
319 pclk_div << PCLK_PERILP1_DIV_CON_SHIFT |
320 hclk_div << HCLK_PERILP1_DIV_CON_SHIFT |
321 HCLK_PERILP1_PLL_SEL_GPLL <<
322 HCLK_PERILP1_PLL_SEL_SHIFT));
323}
324
325void rkclk_configure_cpu(enum apll_l_frequencies apll_l_freq)
326{
327 u32 aclkm_div;
328 u32 pclk_dbg_div;
329 u32 atclk_div;
330
331 rkclk_set_pll(&cru_ptr->apll_l_con[0], apll_l_cfgs[apll_l_freq]);
332
333 aclkm_div = APLL_HZ / ACLKM_CORE_HZ - 1;
334 assert((aclkm_div + 1) * ACLKM_CORE_HZ == APLL_HZ &&
335 aclkm_div < 0x1f);
336
337 pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ - 1;
338 assert((pclk_dbg_div + 1) * PCLK_DBG_HZ == APLL_HZ &&
339 pclk_dbg_div < 0x1f);
340
341 atclk_div = APLL_HZ / ATCLK_CORE_HZ - 1;
342 assert((atclk_div + 1) * ATCLK_CORE_HZ == APLL_HZ &&
343 atclk_div < 0x1f);
344
345 write32(&cru_ptr->clksel_con[0],
346 RK_CLRSETBITS(ACLKM_CORE_L_DIV_CON_MASK <<
347 ACLKM_CORE_L_DIV_CON_SHIFT |
348 CLK_CORE_L_PLL_SEL_MASK <<
349 CLK_CORE_L_PLL_SEL_SHIFT |
350 CLK_CORE_L_DIV_MASK << CLK_CORE_L_DIV_SHIFT,
351 aclkm_div << ACLKM_CORE_L_DIV_CON_SHIFT |
352 CLK_CORE_L_PLL_SEL_ALPLL <<
353 CLK_CORE_L_PLL_SEL_SHIFT |
354 0 << CLK_CORE_L_DIV_SHIFT));
355
356 write32(&cru_ptr->clksel_con[1],
357 RK_CLRSETBITS(PCLK_DBG_L_DIV_MASK << PCLK_DBG_L_DIV_SHIFT |
358 ATCLK_CORE_L_DIV_MASK << ATCLK_CORE_L_DIV_SHIFT,
359 pclk_dbg_div << PCLK_DBG_L_DIV_SHIFT |
360 atclk_div << ATCLK_CORE_L_DIV_SHIFT));
361}
Lin Huangf5702e72016-03-19 22:45:19 +0800362
Shunqian Zhengce60d5a2016-04-21 23:53:08 +0800363void rkclk_configure_ddr(unsigned int hz)
364{
365 struct pll_div dpll_cfg;
366
367 /* IC ECO bug, need to set this register */
368 write32(&rk3399_pmusgrf->ddr_rgn_con[16], 0xc000c000);
369
370 /* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
371 switch (hz) {
372 case 200*MHz:
373 dpll_cfg = (struct pll_div)
374 {.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
375 break;
376 case 300*MHz:
377 dpll_cfg = (struct pll_div)
378 {.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
379 break;
380 case 666*MHz:
381 dpll_cfg = (struct pll_div)
382 {.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
383 break;
384 case 800*MHz:
385 dpll_cfg = (struct pll_div)
386 {.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
387 break;
388 default:
389 die("Unsupported SDRAM frequency, add to clock.c!");
390 }
391 rkclk_set_pll(&cru_ptr->dpll_con[0], &dpll_cfg);
392}
393
huang linc14b54d2016-03-02 18:38:40 +0800394void rkclk_configure_spi(unsigned int bus, unsigned int hz)
395{
396}