blob: 7053a37d62dfb23a15341b113c58b75f545a09c5 [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,
140};
141
142#define VCO_MAX_KHZ (3200 * (MHz / KHz))
143#define VCO_MIN_KHZ (800 * (MHz / KHz))
144#define OUTPUT_MAX_KHZ (3200 * (MHz / KHz))
145#define OUTPUT_MIN_KHZ (16 * (MHz / KHz))
146
147/* the div restrictions of pll in integer mode,
148 * these are defined in * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
149 */
150#define PLL_DIV_MIN 16
151#define PLL_DIV_MAX 3200
152
153/* How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
154 * Formulas also embedded within the Fractional PLL Verilog model:
155 * If DSMPD = 1 (DSM is disabled, "integer mode")
156 * FOUTVCO = FREF / REFDIV * FBDIV
157 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
158 * Where:
159 * FOUTVCO = Fractional PLL non-divided output frequency
160 * FOUTPOSTDIV = Fractional PLL divided output frequency
161 * (output of second post divider)
162 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
163 * REFDIV = Fractional PLL input reference clock divider
164 * FBDIV = Integer value programmed into feedback divide
165 *
166 */
167static void rkclk_set_pll(u32 *pll_con, const struct pll_div *div)
168{
169 /* All 8 PLLs have same VCO and output frequency range restrictions. */
170 u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
171 u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
172
173 printk(BIOS_DEBUG, "PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, "
174 "postdiv2=%d, vco=%u khz, output=%u khz\n",
175 pll_con, div->fbdiv, div->refdiv, div->postdiv1,
176 div->postdiv2, vco_khz, output_khz);
177 assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
178 output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
179 div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
180
181 /* When power on or changing PLL setting,
182 * we must force PLL into slow mode to ensure output stable clock.
183 */
184 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
185 PLL_MODE_SLOW << PLL_MODE_SHIFT));
186
187 /* use integer mode */
188 write32(&pll_con[3],
189 RK_CLRSETBITS(PLL_DSMPD_MASK << PLL_DSMPD_SHIFT,
190 PLL_INTEGER_MODE << PLL_DSMPD_SHIFT));
191
192 write32(&pll_con[0], RK_CLRSETBITS(PLL_FBDIV_MASK << PLL_FBDIV_SHIFT,
193 div->fbdiv << PLL_FBDIV_SHIFT));
194 write32(&pll_con[1],
195 RK_CLRSETBITS(PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
196 PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT |
197 PLL_REFDIV_MASK | PLL_REFDIV_SHIFT,
198 (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
199 (div->postdiv1 << PLL_POSTDIV1_SHIFT) |
200 (div->refdiv << PLL_REFDIV_SHIFT)));
201
202 /* waiting for pll lock */
203 while (!(read32(&pll_con[2]) & (1 << PLL_LOCK_STATUS_SHIFT)))
204 udelay(1);
205
206 /* pll enter normal mode */
207 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
208 PLL_MODE_NORM << PLL_MODE_SHIFT));
209}
210
211void rkclk_init(void)
212{
213 u32 aclk_div;
214 u32 hclk_div;
215 u32 pclk_div;
216
217 /* some cru registers changed by bootrom, we'd better reset them to
218 * reset/default values described in TRM to avoid confusion in kernel.
219 * Please consider these threee lines as a fix of bootrom bug.
220 */
221 write32(&cru_ptr->clksel_con[12], 0xffff4101);
222 write32(&cru_ptr->clksel_con[19], 0xffff033f);
223 write32(&cru_ptr->clksel_con[56], 0x00030003);
224
225 /* configure pmu pll(ppll) */
226 rkclk_set_pll(&pmucru_ptr->ppll_con[0], &ppll_init_cfg);
227
228 /* configure pmu pclk */
229 pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1;
230 assert((pclk_div + 1) * PMU_PCLK_HZ == PPLL_HZ && pclk_div < 0x1f);
231 write32(&pmucru_ptr->pmucru_clksel[0],
232 RK_CLRSETBITS(PMU_PCLK_DIV_CON_MASK << PMU_PCLK_DIV_CON_SHIFT,
233 pclk_div << PMU_PCLK_DIV_CON_SHIFT));
234
235 /* configure gpll cpll */
236 rkclk_set_pll(&cru_ptr->gpll_con[0], &gpll_init_cfg);
237 rkclk_set_pll(&cru_ptr->cpll_con[0], &cpll_init_cfg);
238
239 /* configure perihp aclk, hclk, pclk */
240 aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1;
241 assert((aclk_div + 1) * PERIHP_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
242
243 hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
244 assert((hclk_div + 1) * PERIHP_HCLK_HZ ==
245 PERIHP_ACLK_HZ && (hclk_div < 0x4));
246
247 pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
248 assert((pclk_div + 1) * PERIHP_PCLK_HZ ==
249 PERIHP_ACLK_HZ && (pclk_div < 0x7));
250
251 write32(&cru_ptr->clksel_con[14],
252 RK_CLRSETBITS(PCLK_PERIHP_DIV_CON_MASK <<
253 PCLK_PERIHP_DIV_CON_SHIFT |
254 HCLK_PERIHP_DIV_CON_MASK <<
255 HCLK_PERIHP_DIV_CON_SHIFT |
256 ACLK_PERIHP_PLL_SEL_MASK <<
257 ACLK_PERIHP_PLL_SEL_SHIFT |
258 ACLK_PERIHP_DIV_CON_MASK <<
259 ACLK_PERIHP_DIV_CON_SHIFT,
260 pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
261 hclk_div << HCLK_PERIHP_DIV_CON_SHIFT |
262 ACLK_PERIHP_PLL_SEL_GPLL <<
263 ACLK_PERIHP_PLL_SEL_SHIFT |
264 aclk_div << ACLK_PERIHP_DIV_CON_SHIFT));
265
266 /* configure perilp0 aclk, hclk, pclk */
267 aclk_div = GPLL_HZ / PERILP0_ACLK_HZ - 1;
268 assert((aclk_div + 1) * PERILP0_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
269
270 hclk_div = PERILP0_ACLK_HZ / PERILP0_HCLK_HZ - 1;
271 assert((hclk_div + 1) * PERILP0_HCLK_HZ ==
272 PERILP0_ACLK_HZ && (hclk_div < 0x4));
273
274 pclk_div = PERILP0_ACLK_HZ / PERILP0_PCLK_HZ - 1;
275 assert((pclk_div + 1) * PERILP0_PCLK_HZ ==
276 PERILP0_ACLK_HZ && (pclk_div < 0x7));
277
278 write32(&cru_ptr->clksel_con[23],
279 RK_CLRSETBITS(PCLK_PERILP0_DIV_CON_MASK <<
280 PCLK_PERILP0_DIV_CON_SHIFT |
281 HCLK_PERILP0_DIV_CON_MASK <<
282 HCLK_PERILP0_DIV_CON_SHIFT |
283 ACLK_PERILP0_PLL_SEL_MASK <<
284 ACLK_PERILP0_PLL_SEL_SHIFT |
285 ACLK_PERILP0_DIV_CON_MASK <<
286 ACLK_PERILP0_DIV_CON_SHIFT,
287 pclk_div << PCLK_PERILP0_DIV_CON_SHIFT |
288 hclk_div << HCLK_PERILP0_DIV_CON_SHIFT |
289 ACLK_PERILP0_PLL_SEL_GPLL <<
290 ACLK_PERILP0_PLL_SEL_SHIFT |
291 aclk_div << ACLK_PERILP0_DIV_CON_SHIFT));
292
293 /* perilp1 hclk select gpll as source */
294 hclk_div = GPLL_HZ / PERILP1_HCLK_HZ - 1;
295 assert((hclk_div + 1) * PERILP1_HCLK_HZ ==
296 GPLL_HZ && (hclk_div < 0x1f));
297
298 pclk_div = PERILP1_HCLK_HZ / PERILP1_HCLK_HZ - 1;
299 assert((pclk_div + 1) * PERILP1_HCLK_HZ ==
300 PERILP1_HCLK_HZ && (hclk_div < 0x7));
301
302 write32(&cru_ptr->clksel_con[25],
303 RK_CLRSETBITS(PCLK_PERILP1_DIV_CON_MASK <<
304 PCLK_PERILP1_DIV_CON_SHIFT |
305 HCLK_PERILP1_DIV_CON_MASK <<
306 HCLK_PERILP1_DIV_CON_SHIFT |
307 HCLK_PERILP1_PLL_SEL_MASK <<
308 HCLK_PERILP1_PLL_SEL_SHIFT,
309 pclk_div << PCLK_PERILP1_DIV_CON_SHIFT |
310 hclk_div << HCLK_PERILP1_DIV_CON_SHIFT |
311 HCLK_PERILP1_PLL_SEL_GPLL <<
312 HCLK_PERILP1_PLL_SEL_SHIFT));
313}
314
315void rkclk_configure_cpu(enum apll_l_frequencies apll_l_freq)
316{
317 u32 aclkm_div;
318 u32 pclk_dbg_div;
319 u32 atclk_div;
320
321 rkclk_set_pll(&cru_ptr->apll_l_con[0], apll_l_cfgs[apll_l_freq]);
322
323 aclkm_div = APLL_HZ / ACLKM_CORE_HZ - 1;
324 assert((aclkm_div + 1) * ACLKM_CORE_HZ == APLL_HZ &&
325 aclkm_div < 0x1f);
326
327 pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ - 1;
328 assert((pclk_dbg_div + 1) * PCLK_DBG_HZ == APLL_HZ &&
329 pclk_dbg_div < 0x1f);
330
331 atclk_div = APLL_HZ / ATCLK_CORE_HZ - 1;
332 assert((atclk_div + 1) * ATCLK_CORE_HZ == APLL_HZ &&
333 atclk_div < 0x1f);
334
335 write32(&cru_ptr->clksel_con[0],
336 RK_CLRSETBITS(ACLKM_CORE_L_DIV_CON_MASK <<
337 ACLKM_CORE_L_DIV_CON_SHIFT |
338 CLK_CORE_L_PLL_SEL_MASK <<
339 CLK_CORE_L_PLL_SEL_SHIFT |
340 CLK_CORE_L_DIV_MASK << CLK_CORE_L_DIV_SHIFT,
341 aclkm_div << ACLKM_CORE_L_DIV_CON_SHIFT |
342 CLK_CORE_L_PLL_SEL_ALPLL <<
343 CLK_CORE_L_PLL_SEL_SHIFT |
344 0 << CLK_CORE_L_DIV_SHIFT));
345
346 write32(&cru_ptr->clksel_con[1],
347 RK_CLRSETBITS(PCLK_DBG_L_DIV_MASK << PCLK_DBG_L_DIV_SHIFT |
348 ATCLK_CORE_L_DIV_MASK << ATCLK_CORE_L_DIV_SHIFT,
349 pclk_dbg_div << PCLK_DBG_L_DIV_SHIFT |
350 atclk_div << ATCLK_CORE_L_DIV_SHIFT));
351}
Lin Huangf5702e72016-03-19 22:45:19 +0800352
huang linc14b54d2016-03-02 18:38:40 +0800353void rkclk_configure_spi(unsigned int bus, unsigned int hz)
354{
355}