blob: 8a2b3517f6f2a4e9a66509139c14c060c784caad [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
Shunqian Zheng347c83c2016-04-13 22:34:39 +080089 /* PMUCRU_CLKSEL_CON1 */
90 SPI3_PLL_SEL_MASK = 1,
91 SPI3_PLL_SEL_SHIFT = 7,
92 SPI3_PLL_SEL_24M = 0,
93 SPI3_PLL_SEL_PPLL = 1,
94 SPI3_DIV_CON_MASK = 0x7f,
95 SPI3_DIV_CON_SHIFT = 0x0,
96
Lin Huanga1f82a32016-03-09 18:08:20 +080097 /* CLKSEL_CON0 */
98 ACLKM_CORE_L_DIV_CON_MASK = 0x1f,
99 ACLKM_CORE_L_DIV_CON_SHIFT = 8,
100 CLK_CORE_L_PLL_SEL_MASK = 3,
101 CLK_CORE_L_PLL_SEL_SHIFT = 6,
102 CLK_CORE_L_PLL_SEL_ALPLL = 0x0,
103 CLK_CORE_L_PLL_SEL_ABPLL = 0x1,
104 CLK_CORE_L_PLL_SEL_DPLL = 0x10,
105 CLK_CORE_L_PLL_SEL_GPLL = 0x11,
106 CLK_CORE_L_DIV_MASK = 0x1f,
107 CLK_CORE_L_DIV_SHIFT = 0,
108
109 /* CLKSEL_CON1 */
110 PCLK_DBG_L_DIV_MASK = 0x1f,
111 PCLK_DBG_L_DIV_SHIFT = 0x8,
112 ATCLK_CORE_L_DIV_MASK = 0x1f,
113 ATCLK_CORE_L_DIV_SHIFT = 0,
114
115 /* CLKSEL_CON14 */
116 PCLK_PERIHP_DIV_CON_MASK = 0x7,
117 PCLK_PERIHP_DIV_CON_SHIFT = 12,
118 HCLK_PERIHP_DIV_CON_MASK = 3,
119 HCLK_PERIHP_DIV_CON_SHIFT = 8,
120 ACLK_PERIHP_PLL_SEL_MASK = 1,
121 ACLK_PERIHP_PLL_SEL_SHIFT = 7,
122 ACLK_PERIHP_PLL_SEL_CPLL = 0,
123 ACLK_PERIHP_PLL_SEL_GPLL = 1,
124 ACLK_PERIHP_DIV_CON_MASK = 0x1f,
125 ACLK_PERIHP_DIV_CON_SHIFT = 0,
126
127 /* CLKSEL_CON23 */
128 PCLK_PERILP0_DIV_CON_MASK = 0x7,
129 PCLK_PERILP0_DIV_CON_SHIFT = 12,
130 HCLK_PERILP0_DIV_CON_MASK = 3,
131 HCLK_PERILP0_DIV_CON_SHIFT = 8,
132 ACLK_PERILP0_PLL_SEL_MASK = 1,
133 ACLK_PERILP0_PLL_SEL_SHIFT = 7,
134 ACLK_PERILP0_PLL_SEL_CPLL = 0,
135 ACLK_PERILP0_PLL_SEL_GPLL = 1,
136 ACLK_PERILP0_DIV_CON_MASK = 0x1f,
137 ACLK_PERILP0_DIV_CON_SHIFT = 0,
138
139 /* CLKSEL_CON25 */
140 PCLK_PERILP1_DIV_CON_MASK = 0x7,
141 PCLK_PERILP1_DIV_CON_SHIFT = 8,
142 HCLK_PERILP1_PLL_SEL_MASK = 1,
143 HCLK_PERILP1_PLL_SEL_SHIFT = 7,
144 HCLK_PERILP1_PLL_SEL_CPLL = 0,
145 HCLK_PERILP1_PLL_SEL_GPLL = 1,
146 HCLK_PERILP1_DIV_CON_MASK = 0x1f,
147 HCLK_PERILP1_DIV_CON_SHIFT = 0,
Shunqian Zhengce60d5a2016-04-21 23:53:08 +0800148
Shunqian Zheng347c83c2016-04-13 22:34:39 +0800149 /* CLKSEL_CON58 */
150 CLK_SPI_PLL_SEL_MASK = 1,
151 CLK_SPI_PLL_SEL_CPLL = 0,
152 CLK_SPI_PLL_SEL_GPLL = 1,
153 CLK_SPI_PLL_DIV_CON_MASK = 0x7f,
154 CLK_SPI5_PLL_DIV_CON_SHIFT = 8,
155 CLK_SPI5_PLL_SEL_SHIFT = 15,
156
157 /* CLKSEL_CON59 */
158 CLK_SPI1_PLL_SEL_SHIFT = 15,
159 CLK_SPI1_PLL_DIV_CON_SHIFT = 8,
160 CLK_SPI0_PLL_SEL_SHIFT = 7,
161 CLK_SPI0_PLL_DIV_CON_SHIFT = 0,
162
163 /* CLKSEL_CON60 */
164 CLK_SPI4_PLL_SEL_SHIFT = 15,
165 CLK_SPI4_PLL_DIV_CON_SHIFT = 8,
166 CLK_SPI2_PLL_SEL_SHIFT = 7,
167 CLK_SPI2_PLL_DIV_CON_SHIFT = 0,
168
Shunqian Zhengce60d5a2016-04-21 23:53:08 +0800169 /* CRU_SOFTRST_CON4 */
170 RESETN_DDR0_REQ_MASK = 1,
171 RESETN_DDR0_REQ_SHIFT = 8,
172 RESETN_DDRPHY0_REQ_MASK = 1,
173 RESETN_DDRPHY0_REQ_SHIFT = 9,
174 RESETN_DDR1_REQ_MASK = 1,
175 RESETN_DDR1_REQ_SHIFT = 12,
176 RESETN_DDRPHY1_REQ_MASK = 1,
177 RESETN_DDRPHY1_REQ_SHIFT = 13,
Lin Huanga1f82a32016-03-09 18:08:20 +0800178};
179
180#define VCO_MAX_KHZ (3200 * (MHz / KHz))
181#define VCO_MIN_KHZ (800 * (MHz / KHz))
182#define OUTPUT_MAX_KHZ (3200 * (MHz / KHz))
183#define OUTPUT_MIN_KHZ (16 * (MHz / KHz))
184
185/* the div restrictions of pll in integer mode,
186 * these are defined in * CRU_*PLL_CON0 or PMUCRU_*PLL_CON0
187 */
188#define PLL_DIV_MIN 16
189#define PLL_DIV_MAX 3200
190
191/* How to calculate the PLL(from TRM V0.3 Part 1 Page 63):
192 * Formulas also embedded within the Fractional PLL Verilog model:
193 * If DSMPD = 1 (DSM is disabled, "integer mode")
194 * FOUTVCO = FREF / REFDIV * FBDIV
195 * FOUTPOSTDIV = FOUTVCO / POSTDIV1 / POSTDIV2
196 * Where:
197 * FOUTVCO = Fractional PLL non-divided output frequency
198 * FOUTPOSTDIV = Fractional PLL divided output frequency
199 * (output of second post divider)
200 * FREF = Fractional PLL input reference frequency, (the OSC_HZ 24MHz input)
201 * REFDIV = Fractional PLL input reference clock divider
202 * FBDIV = Integer value programmed into feedback divide
203 *
204 */
205static void rkclk_set_pll(u32 *pll_con, const struct pll_div *div)
206{
207 /* All 8 PLLs have same VCO and output frequency range restrictions. */
208 u32 vco_khz = OSC_HZ / 1000 * div->fbdiv / div->refdiv;
209 u32 output_khz = vco_khz / div->postdiv1 / div->postdiv2;
210
211 printk(BIOS_DEBUG, "PLL at %p: fbdiv=%d, refdiv=%d, postdiv1=%d, "
212 "postdiv2=%d, vco=%u khz, output=%u khz\n",
213 pll_con, div->fbdiv, div->refdiv, div->postdiv1,
214 div->postdiv2, vco_khz, output_khz);
215 assert(vco_khz >= VCO_MIN_KHZ && vco_khz <= VCO_MAX_KHZ &&
216 output_khz >= OUTPUT_MIN_KHZ && output_khz <= OUTPUT_MAX_KHZ &&
217 div->fbdiv >= PLL_DIV_MIN && div->fbdiv <= PLL_DIV_MAX);
218
219 /* When power on or changing PLL setting,
220 * we must force PLL into slow mode to ensure output stable clock.
221 */
222 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
223 PLL_MODE_SLOW << PLL_MODE_SHIFT));
224
225 /* use integer mode */
226 write32(&pll_con[3],
227 RK_CLRSETBITS(PLL_DSMPD_MASK << PLL_DSMPD_SHIFT,
228 PLL_INTEGER_MODE << PLL_DSMPD_SHIFT));
229
230 write32(&pll_con[0], RK_CLRSETBITS(PLL_FBDIV_MASK << PLL_FBDIV_SHIFT,
231 div->fbdiv << PLL_FBDIV_SHIFT));
232 write32(&pll_con[1],
233 RK_CLRSETBITS(PLL_POSTDIV2_MASK << PLL_POSTDIV2_SHIFT |
234 PLL_POSTDIV1_MASK << PLL_POSTDIV1_SHIFT |
235 PLL_REFDIV_MASK | PLL_REFDIV_SHIFT,
236 (div->postdiv2 << PLL_POSTDIV2_SHIFT) |
237 (div->postdiv1 << PLL_POSTDIV1_SHIFT) |
238 (div->refdiv << PLL_REFDIV_SHIFT)));
239
240 /* waiting for pll lock */
241 while (!(read32(&pll_con[2]) & (1 << PLL_LOCK_STATUS_SHIFT)))
242 udelay(1);
243
244 /* pll enter normal mode */
245 write32(&pll_con[3], RK_CLRSETBITS(PLL_MODE_MASK << PLL_MODE_SHIFT,
246 PLL_MODE_NORM << PLL_MODE_SHIFT));
247}
248
249void rkclk_init(void)
250{
251 u32 aclk_div;
252 u32 hclk_div;
253 u32 pclk_div;
254
255 /* some cru registers changed by bootrom, we'd better reset them to
256 * reset/default values described in TRM to avoid confusion in kernel.
257 * Please consider these threee lines as a fix of bootrom bug.
258 */
259 write32(&cru_ptr->clksel_con[12], 0xffff4101);
260 write32(&cru_ptr->clksel_con[19], 0xffff033f);
261 write32(&cru_ptr->clksel_con[56], 0x00030003);
262
263 /* configure pmu pll(ppll) */
264 rkclk_set_pll(&pmucru_ptr->ppll_con[0], &ppll_init_cfg);
265
266 /* configure pmu pclk */
267 pclk_div = PPLL_HZ / PMU_PCLK_HZ - 1;
268 assert((pclk_div + 1) * PMU_PCLK_HZ == PPLL_HZ && pclk_div < 0x1f);
269 write32(&pmucru_ptr->pmucru_clksel[0],
270 RK_CLRSETBITS(PMU_PCLK_DIV_CON_MASK << PMU_PCLK_DIV_CON_SHIFT,
271 pclk_div << PMU_PCLK_DIV_CON_SHIFT));
272
273 /* configure gpll cpll */
274 rkclk_set_pll(&cru_ptr->gpll_con[0], &gpll_init_cfg);
275 rkclk_set_pll(&cru_ptr->cpll_con[0], &cpll_init_cfg);
276
277 /* configure perihp aclk, hclk, pclk */
278 aclk_div = GPLL_HZ / PERIHP_ACLK_HZ - 1;
279 assert((aclk_div + 1) * PERIHP_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
280
281 hclk_div = PERIHP_ACLK_HZ / PERIHP_HCLK_HZ - 1;
282 assert((hclk_div + 1) * PERIHP_HCLK_HZ ==
283 PERIHP_ACLK_HZ && (hclk_div < 0x4));
284
285 pclk_div = PERIHP_ACLK_HZ / PERIHP_PCLK_HZ - 1;
286 assert((pclk_div + 1) * PERIHP_PCLK_HZ ==
287 PERIHP_ACLK_HZ && (pclk_div < 0x7));
288
289 write32(&cru_ptr->clksel_con[14],
290 RK_CLRSETBITS(PCLK_PERIHP_DIV_CON_MASK <<
291 PCLK_PERIHP_DIV_CON_SHIFT |
292 HCLK_PERIHP_DIV_CON_MASK <<
293 HCLK_PERIHP_DIV_CON_SHIFT |
294 ACLK_PERIHP_PLL_SEL_MASK <<
295 ACLK_PERIHP_PLL_SEL_SHIFT |
296 ACLK_PERIHP_DIV_CON_MASK <<
297 ACLK_PERIHP_DIV_CON_SHIFT,
298 pclk_div << PCLK_PERIHP_DIV_CON_SHIFT |
299 hclk_div << HCLK_PERIHP_DIV_CON_SHIFT |
300 ACLK_PERIHP_PLL_SEL_GPLL <<
301 ACLK_PERIHP_PLL_SEL_SHIFT |
302 aclk_div << ACLK_PERIHP_DIV_CON_SHIFT));
303
304 /* configure perilp0 aclk, hclk, pclk */
305 aclk_div = GPLL_HZ / PERILP0_ACLK_HZ - 1;
306 assert((aclk_div + 1) * PERILP0_ACLK_HZ == GPLL_HZ && aclk_div < 0x1f);
307
308 hclk_div = PERILP0_ACLK_HZ / PERILP0_HCLK_HZ - 1;
309 assert((hclk_div + 1) * PERILP0_HCLK_HZ ==
310 PERILP0_ACLK_HZ && (hclk_div < 0x4));
311
312 pclk_div = PERILP0_ACLK_HZ / PERILP0_PCLK_HZ - 1;
313 assert((pclk_div + 1) * PERILP0_PCLK_HZ ==
314 PERILP0_ACLK_HZ && (pclk_div < 0x7));
315
316 write32(&cru_ptr->clksel_con[23],
317 RK_CLRSETBITS(PCLK_PERILP0_DIV_CON_MASK <<
318 PCLK_PERILP0_DIV_CON_SHIFT |
319 HCLK_PERILP0_DIV_CON_MASK <<
320 HCLK_PERILP0_DIV_CON_SHIFT |
321 ACLK_PERILP0_PLL_SEL_MASK <<
322 ACLK_PERILP0_PLL_SEL_SHIFT |
323 ACLK_PERILP0_DIV_CON_MASK <<
324 ACLK_PERILP0_DIV_CON_SHIFT,
325 pclk_div << PCLK_PERILP0_DIV_CON_SHIFT |
326 hclk_div << HCLK_PERILP0_DIV_CON_SHIFT |
327 ACLK_PERILP0_PLL_SEL_GPLL <<
328 ACLK_PERILP0_PLL_SEL_SHIFT |
329 aclk_div << ACLK_PERILP0_DIV_CON_SHIFT));
330
331 /* perilp1 hclk select gpll as source */
332 hclk_div = GPLL_HZ / PERILP1_HCLK_HZ - 1;
333 assert((hclk_div + 1) * PERILP1_HCLK_HZ ==
334 GPLL_HZ && (hclk_div < 0x1f));
335
336 pclk_div = PERILP1_HCLK_HZ / PERILP1_HCLK_HZ - 1;
337 assert((pclk_div + 1) * PERILP1_HCLK_HZ ==
338 PERILP1_HCLK_HZ && (hclk_div < 0x7));
339
340 write32(&cru_ptr->clksel_con[25],
341 RK_CLRSETBITS(PCLK_PERILP1_DIV_CON_MASK <<
342 PCLK_PERILP1_DIV_CON_SHIFT |
343 HCLK_PERILP1_DIV_CON_MASK <<
344 HCLK_PERILP1_DIV_CON_SHIFT |
345 HCLK_PERILP1_PLL_SEL_MASK <<
346 HCLK_PERILP1_PLL_SEL_SHIFT,
347 pclk_div << PCLK_PERILP1_DIV_CON_SHIFT |
348 hclk_div << HCLK_PERILP1_DIV_CON_SHIFT |
349 HCLK_PERILP1_PLL_SEL_GPLL <<
350 HCLK_PERILP1_PLL_SEL_SHIFT));
351}
352
353void rkclk_configure_cpu(enum apll_l_frequencies apll_l_freq)
354{
355 u32 aclkm_div;
356 u32 pclk_dbg_div;
357 u32 atclk_div;
358
359 rkclk_set_pll(&cru_ptr->apll_l_con[0], apll_l_cfgs[apll_l_freq]);
360
361 aclkm_div = APLL_HZ / ACLKM_CORE_HZ - 1;
362 assert((aclkm_div + 1) * ACLKM_CORE_HZ == APLL_HZ &&
363 aclkm_div < 0x1f);
364
365 pclk_dbg_div = APLL_HZ / PCLK_DBG_HZ - 1;
366 assert((pclk_dbg_div + 1) * PCLK_DBG_HZ == APLL_HZ &&
367 pclk_dbg_div < 0x1f);
368
369 atclk_div = APLL_HZ / ATCLK_CORE_HZ - 1;
370 assert((atclk_div + 1) * ATCLK_CORE_HZ == APLL_HZ &&
371 atclk_div < 0x1f);
372
373 write32(&cru_ptr->clksel_con[0],
374 RK_CLRSETBITS(ACLKM_CORE_L_DIV_CON_MASK <<
375 ACLKM_CORE_L_DIV_CON_SHIFT |
376 CLK_CORE_L_PLL_SEL_MASK <<
377 CLK_CORE_L_PLL_SEL_SHIFT |
378 CLK_CORE_L_DIV_MASK << CLK_CORE_L_DIV_SHIFT,
379 aclkm_div << ACLKM_CORE_L_DIV_CON_SHIFT |
380 CLK_CORE_L_PLL_SEL_ALPLL <<
381 CLK_CORE_L_PLL_SEL_SHIFT |
382 0 << CLK_CORE_L_DIV_SHIFT));
383
384 write32(&cru_ptr->clksel_con[1],
385 RK_CLRSETBITS(PCLK_DBG_L_DIV_MASK << PCLK_DBG_L_DIV_SHIFT |
386 ATCLK_CORE_L_DIV_MASK << ATCLK_CORE_L_DIV_SHIFT,
387 pclk_dbg_div << PCLK_DBG_L_DIV_SHIFT |
388 atclk_div << ATCLK_CORE_L_DIV_SHIFT));
389}
Lin Huangf5702e72016-03-19 22:45:19 +0800390
Shunqian Zhengce60d5a2016-04-21 23:53:08 +0800391void rkclk_configure_ddr(unsigned int hz)
392{
393 struct pll_div dpll_cfg;
394
395 /* IC ECO bug, need to set this register */
396 write32(&rk3399_pmusgrf->ddr_rgn_con[16], 0xc000c000);
397
398 /* clk_ddrc == DPLL = 24MHz / refdiv * fbdiv / postdiv1 / postdiv2 */
399 switch (hz) {
400 case 200*MHz:
401 dpll_cfg = (struct pll_div)
402 {.refdiv = 1, .fbdiv = 50, .postdiv1 = 6, .postdiv2 = 1};
403 break;
404 case 300*MHz:
405 dpll_cfg = (struct pll_div)
406 {.refdiv = 2, .fbdiv = 100, .postdiv1 = 4, .postdiv2 = 1};
407 break;
408 case 666*MHz:
409 dpll_cfg = (struct pll_div)
410 {.refdiv = 2, .fbdiv = 111, .postdiv1 = 2, .postdiv2 = 1};
411 break;
412 case 800*MHz:
413 dpll_cfg = (struct pll_div)
414 {.refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1};
415 break;
416 default:
417 die("Unsupported SDRAM frequency, add to clock.c!");
418 }
419 rkclk_set_pll(&cru_ptr->dpll_con[0], &dpll_cfg);
420}
421
Shunqian Zheng347c83c2016-04-13 22:34:39 +0800422#define SPI_CLK_REG_VALUE(bus, clk_div) \
423 RK_CLRSETBITS(CLK_SPI_PLL_SEL_MASK << \
424 CLK_SPI ##bus## _PLL_SEL_SHIFT | \
425 CLK_SPI_PLL_DIV_CON_MASK << \
426 CLK_SPI ##bus## _PLL_DIV_CON_SHIFT, \
427 CLK_SPI_PLL_SEL_GPLL << \
428 CLK_SPI ##bus## _PLL_SEL_SHIFT | \
429 (clk_div - 1) << \
430 CLK_SPI ##bus## _PLL_DIV_CON_SHIFT)
431
huang linc14b54d2016-03-02 18:38:40 +0800432void rkclk_configure_spi(unsigned int bus, unsigned int hz)
433{
Shunqian Zheng347c83c2016-04-13 22:34:39 +0800434 int src_clk_div;
435 int pll;
436
437 /* spi3 src clock from ppll, while spi0,1,2,4,5 src clock from gpll */
438 pll = (bus == 3) ? PPLL_HZ : GPLL_HZ;
439 src_clk_div = pll / hz;
440 assert((src_clk_div - 1 < 127) && (src_clk_div * hz == pll));
441
442 switch (bus) {
443 case 0:
444 write32(&cru_ptr->clksel_con[59],
445 SPI_CLK_REG_VALUE(0, src_clk_div));
446 break;
447 case 1:
448 write32(&cru_ptr->clksel_con[59],
449 SPI_CLK_REG_VALUE(1, src_clk_div));
450 break;
451 case 2:
452 write32(&cru_ptr->clksel_con[60],
453 SPI_CLK_REG_VALUE(2, src_clk_div));
454 break;
455 case 3:
456 write32(&pmucru_ptr->pmucru_clksel[1],
457 RK_CLRSETBITS(SPI3_PLL_SEL_MASK << SPI3_PLL_SEL_SHIFT |
458 SPI3_DIV_CON_MASK << SPI3_DIV_CON_SHIFT,
459 SPI3_PLL_SEL_PPLL << SPI3_PLL_SEL_SHIFT |
460 (src_clk_div - 1) << SPI3_DIV_CON_SHIFT));
461 break;
462 case 4:
463 write32(&cru_ptr->clksel_con[60],
464 SPI_CLK_REG_VALUE(4, src_clk_div));
465 break;
466 case 5:
467 write32(&cru_ptr->clksel_con[58],
468 SPI_CLK_REG_VALUE(5, src_clk_div));
469 break;
470 default:
471 printk(BIOS_ERR, "do not support this spi bus\n");
472 }
huang linc14b54d2016-03-02 18:38:40 +0800473}