]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
de778115 LFT |
2 | /* |
3 | * Copyright (C) 2013-2017 Altera Corporation <www.altera.com> | |
de778115 LFT |
4 | */ |
5 | ||
6 | #include <common.h> | |
1045315d | 7 | #include <time.h> |
de778115 | 8 | #include <asm/io.h> |
21143ce1 | 9 | #include <dm.h> |
de778115 LFT |
10 | #include <asm/arch/clock_manager.h> |
11 | #include <wait_bit.h> | |
12 | ||
de778115 LFT |
13 | /* |
14 | * function to write the bypass register which requires a poll of the | |
15 | * busy bit | |
16 | */ | |
17 | static void cm_write_bypass(u32 val) | |
18 | { | |
94172c79 | 19 | writel(val, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_BYPASS); |
de778115 LFT |
20 | cm_wait_for_fsm(); |
21 | } | |
22 | ||
23 | /* function to write the ctrl register which requires a poll of the busy bit */ | |
24 | static void cm_write_ctrl(u32 val) | |
25 | { | |
94172c79 | 26 | writel(val, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_CTRL); |
de778115 LFT |
27 | cm_wait_for_fsm(); |
28 | } | |
29 | ||
30 | /* function to write a clock register that has phase information */ | |
ab12aa24 | 31 | static int cm_write_with_phase(u32 value, const void *reg_address, u32 mask) |
de778115 LFT |
32 | { |
33 | int ret; | |
34 | ||
35 | /* poll until phase is zero */ | |
48263504 | 36 | ret = wait_for_bit_le32(reg_address, mask, false, 20000, false); |
de778115 LFT |
37 | if (ret) |
38 | return ret; | |
39 | ||
40 | writel(value, reg_address); | |
41 | ||
48263504 | 42 | return wait_for_bit_le32(reg_address, mask, false, 20000, false); |
de778115 LFT |
43 | } |
44 | ||
45 | /* | |
46 | * Setup clocks while making no assumptions about previous state of the clocks. | |
47 | * | |
48 | * Start by being paranoid and gate all sw managed clocks | |
49 | * Put all plls in bypass | |
50 | * Put all plls VCO registers back to reset value (bandgap power down). | |
51 | * Put peripheral and main pll src to reset value to avoid glitch. | |
52 | * Delay 5 us. | |
53 | * Deassert bandgap power down and set numerator and denominator | |
54 | * Start 7 us timer. | |
55 | * set internal dividers | |
56 | * Wait for 7 us timer. | |
57 | * Enable plls | |
58 | * Set external dividers while plls are locking | |
59 | * Wait for pll lock | |
60 | * Assert/deassert outreset all. | |
61 | * Take all pll's out of bypass | |
62 | * Clear safe mode | |
63 | * set source main and peripheral clocks | |
64 | * Ungate clocks | |
65 | */ | |
66 | ||
67 | int cm_basic_init(const struct cm_config * const cfg) | |
68 | { | |
69 | unsigned long end; | |
70 | int ret; | |
71 | ||
72 | /* Start by being paranoid and gate all sw managed clocks */ | |
73 | ||
74 | /* | |
75 | * We need to disable nandclk | |
76 | * and then do another apb access before disabling | |
77 | * gatting off the rest of the periperal clocks. | |
78 | */ | |
79 | writel(~CLKMGR_PERPLLGRP_EN_NANDCLK_MASK & | |
94172c79 LFT |
80 | readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EN), |
81 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EN); | |
de778115 LFT |
82 | |
83 | /* DO NOT GATE OFF DEBUG CLOCKS & BRIDGE CLOCKS */ | |
84 | writel(CLKMGR_MAINPLLGRP_EN_DBGTIMERCLK_MASK | | |
85 | CLKMGR_MAINPLLGRP_EN_DBGTRACECLK_MASK | | |
86 | CLKMGR_MAINPLLGRP_EN_DBGCLK_MASK | | |
87 | CLKMGR_MAINPLLGRP_EN_DBGATCLK_MASK | | |
88 | CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK | | |
89 | CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK, | |
94172c79 | 90 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_EN); |
de778115 | 91 | |
94172c79 | 92 | writel(0, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_EN); |
de778115 LFT |
93 | |
94 | /* now we can gate off the rest of the peripheral clocks */ | |
94172c79 | 95 | writel(0, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EN); |
de778115 LFT |
96 | |
97 | /* Put all plls in bypass */ | |
98 | cm_write_bypass(CLKMGR_BYPASS_PERPLL | CLKMGR_BYPASS_SDRPLL | | |
99 | CLKMGR_BYPASS_MAINPLL); | |
100 | ||
101 | /* Put all plls VCO registers back to reset value. */ | |
102 | writel(CLKMGR_MAINPLLGRP_VCO_RESET_VALUE & | |
103 | ~CLKMGR_MAINPLLGRP_VCO_REGEXTSEL_MASK, | |
94172c79 | 104 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
de778115 LFT |
105 | writel(CLKMGR_PERPLLGRP_VCO_RESET_VALUE & |
106 | ~CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK, | |
94172c79 | 107 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
108 | writel(CLKMGR_SDRPLLGRP_VCO_RESET_VALUE & |
109 | ~CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK, | |
94172c79 | 110 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); |
de778115 LFT |
111 | |
112 | /* | |
113 | * The clocks to the flash devices and the L4_MAIN clocks can | |
114 | * glitch when coming out of safe mode if their source values | |
115 | * are different from their reset value. So the trick it to | |
116 | * put them back to their reset state, and change input | |
117 | * after exiting safe mode but before ungating the clocks. | |
118 | */ | |
119 | writel(CLKMGR_PERPLLGRP_SRC_RESET_VALUE, | |
94172c79 | 120 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_SRC); |
de778115 | 121 | writel(CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE, |
94172c79 | 122 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_L4SRC); |
de778115 LFT |
123 | |
124 | /* read back for the required 5 us delay. */ | |
94172c79 LFT |
125 | readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
126 | readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); | |
127 | readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); | |
de778115 LFT |
128 | |
129 | ||
130 | /* | |
131 | * We made sure bgpwr down was assert for 5 us. Now deassert BG PWR DN | |
132 | * with numerator and denominator. | |
133 | */ | |
94172c79 LFT |
134 | writel(cfg->main_vco_base, |
135 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); | |
136 | writel(cfg->peri_vco_base, | |
137 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); | |
138 | writel(cfg->sdram_vco_base, | |
139 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); | |
de778115 LFT |
140 | |
141 | /* | |
142 | * Time starts here. Must wait 7 us from | |
143 | * BGPWRDN_SET(0) to VCO_ENABLE_SET(1). | |
144 | */ | |
145 | end = timer_get_us() + 7; | |
146 | ||
147 | /* main mpu */ | |
94172c79 LFT |
148 | writel(cfg->mpuclk, |
149 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MPUCLK); | |
de778115 LFT |
150 | |
151 | /* altera group mpuclk */ | |
94172c79 LFT |
152 | writel(cfg->altera_grp_mpuclk, |
153 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_ALTR_MPUCLK); | |
de778115 LFT |
154 | |
155 | /* main main clock */ | |
94172c79 LFT |
156 | writel(cfg->mainclk, |
157 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MAINCLK); | |
de778115 LFT |
158 | |
159 | /* main for dbg */ | |
94172c79 LFT |
160 | writel(cfg->dbgatclk, |
161 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_DBGATCLK); | |
de778115 LFT |
162 | |
163 | /* main for cfgs2fuser0clk */ | |
164 | writel(cfg->cfg2fuser0clk, | |
94172c79 | 165 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_CFGS2FUSER0CLK); |
de778115 LFT |
166 | |
167 | /* Peri emac0 50 MHz default to RMII */ | |
94172c79 LFT |
168 | writel(cfg->emac0clk, |
169 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EMAC0CLK); | |
de778115 LFT |
170 | |
171 | /* Peri emac1 50 MHz default to RMII */ | |
94172c79 LFT |
172 | writel(cfg->emac1clk, |
173 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EMAC1CLK); | |
de778115 LFT |
174 | |
175 | /* Peri QSPI */ | |
94172c79 LFT |
176 | writel(cfg->mainqspiclk, |
177 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MAINQSPICLK); | |
de778115 | 178 | |
94172c79 LFT |
179 | writel(cfg->perqspiclk, |
180 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_PERQSPICLK); | |
de778115 LFT |
181 | |
182 | /* Peri pernandsdmmcclk */ | |
183 | writel(cfg->mainnandsdmmcclk, | |
94172c79 LFT |
184 | socfpga_get_clkmgr_addr() + |
185 | CLKMGR_GEN5_MAINPLL_MAINNANDSDMMCCLK); | |
de778115 LFT |
186 | |
187 | writel(cfg->pernandsdmmcclk, | |
94172c79 | 188 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_PERNANDSDMMCCLK); |
de778115 LFT |
189 | |
190 | /* Peri perbaseclk */ | |
94172c79 LFT |
191 | writel(cfg->perbaseclk, |
192 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_PERBASECLK); | |
de778115 LFT |
193 | |
194 | /* Peri s2fuser1clk */ | |
94172c79 LFT |
195 | writel(cfg->s2fuser1clk, |
196 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_S2FUSER1CLK); | |
de778115 LFT |
197 | |
198 | /* 7 us must have elapsed before we can enable the VCO */ | |
199 | while (timer_get_us() < end) | |
200 | ; | |
201 | ||
202 | /* Enable vco */ | |
203 | /* main pll vco */ | |
204 | writel(cfg->main_vco_base | CLKMGR_MAINPLLGRP_VCO_EN, | |
94172c79 | 205 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
de778115 LFT |
206 | |
207 | /* periferal pll */ | |
208 | writel(cfg->peri_vco_base | CLKMGR_MAINPLLGRP_VCO_EN, | |
94172c79 | 209 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
210 | |
211 | /* sdram pll vco */ | |
212 | writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN, | |
94172c79 | 213 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); |
de778115 LFT |
214 | |
215 | /* L3 MP and L3 SP */ | |
94172c79 LFT |
216 | writel(cfg->maindiv, |
217 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MAINDIV); | |
de778115 | 218 | |
94172c79 LFT |
219 | writel(cfg->dbgdiv, |
220 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_DBGDIV); | |
de778115 | 221 | |
94172c79 LFT |
222 | writel(cfg->tracediv, |
223 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_TRACEDIV); | |
de778115 LFT |
224 | |
225 | /* L4 MP, L4 SP, can0, and can1 */ | |
94172c79 LFT |
226 | writel(cfg->perdiv, |
227 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_DIV); | |
de778115 | 228 | |
94172c79 LFT |
229 | writel(cfg->gpiodiv, |
230 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_GPIODIV); | |
de778115 LFT |
231 | |
232 | cm_wait_for_lock(LOCKED_MASK); | |
233 | ||
234 | /* write the sdram clock counters before toggling outreset all */ | |
235 | writel(cfg->ddrdqsclk & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK, | |
94172c79 | 236 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_DDRDQSCLK); |
de778115 LFT |
237 | |
238 | writel(cfg->ddr2xdqsclk & CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_MASK, | |
94172c79 | 239 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_DDR2XDQSCLK); |
de778115 LFT |
240 | |
241 | writel(cfg->ddrdqclk & CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_MASK, | |
94172c79 | 242 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_DDRDQCLK); |
de778115 LFT |
243 | |
244 | writel(cfg->s2fuser2clk & CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_MASK, | |
94172c79 | 245 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_S2FUSER2CLK); |
de778115 LFT |
246 | |
247 | /* | |
248 | * after locking, but before taking out of bypass | |
249 | * assert/deassert outresetall | |
250 | */ | |
94172c79 LFT |
251 | u32 mainvco = readl(socfpga_get_clkmgr_addr() + |
252 | CLKMGR_GEN5_MAINPLL_VCO); | |
de778115 LFT |
253 | |
254 | /* assert main outresetall */ | |
255 | writel(mainvco | CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK, | |
94172c79 | 256 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
de778115 | 257 | |
94172c79 LFT |
258 | u32 periphvco = readl(socfpga_get_clkmgr_addr() + |
259 | CLKMGR_GEN5_PERPLL_VCO); | |
de778115 LFT |
260 | |
261 | /* assert pheriph outresetall */ | |
262 | writel(periphvco | CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK, | |
94172c79 | 263 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
264 | |
265 | /* assert sdram outresetall */ | |
94172c79 LFT |
266 | writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN | |
267 | CLKMGR_SDRPLLGRP_VCO_OUTRESETALL, | |
268 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); | |
de778115 LFT |
269 | |
270 | /* deassert main outresetall */ | |
271 | writel(mainvco & ~CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK, | |
94172c79 | 272 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
de778115 LFT |
273 | |
274 | /* deassert pheriph outresetall */ | |
275 | writel(periphvco & ~CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK, | |
94172c79 | 276 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
277 | |
278 | /* deassert sdram outresetall */ | |
279 | writel(cfg->sdram_vco_base | CLKMGR_MAINPLLGRP_VCO_EN, | |
94172c79 | 280 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); |
de778115 LFT |
281 | |
282 | /* | |
283 | * now that we've toggled outreset all, all the clocks | |
284 | * are aligned nicely; so we can change any phase. | |
285 | */ | |
286 | ret = cm_write_with_phase(cfg->ddrdqsclk, | |
94172c79 LFT |
287 | (const void *)(socfpga_get_clkmgr_addr() + |
288 | CLKMGR_GEN5_SDRPLL_DDRDQSCLK), | |
de778115 LFT |
289 | CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK); |
290 | if (ret) | |
291 | return ret; | |
292 | ||
293 | /* SDRAM DDR2XDQSCLK */ | |
294 | ret = cm_write_with_phase(cfg->ddr2xdqsclk, | |
94172c79 LFT |
295 | (const void *)(socfpga_get_clkmgr_addr() + |
296 | CLKMGR_GEN5_SDRPLL_DDR2XDQSCLK), | |
de778115 LFT |
297 | CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_MASK); |
298 | if (ret) | |
299 | return ret; | |
300 | ||
301 | ret = cm_write_with_phase(cfg->ddrdqclk, | |
94172c79 LFT |
302 | (const void *)(socfpga_get_clkmgr_addr() + |
303 | CLKMGR_GEN5_SDRPLL_DDRDQCLK), | |
de778115 LFT |
304 | CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_MASK); |
305 | if (ret) | |
306 | return ret; | |
307 | ||
308 | ret = cm_write_with_phase(cfg->s2fuser2clk, | |
94172c79 LFT |
309 | (const void *)(socfpga_get_clkmgr_addr() + |
310 | CLKMGR_GEN5_SDRPLL_S2FUSER2CLK), | |
de778115 LFT |
311 | CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK); |
312 | if (ret) | |
313 | return ret; | |
314 | ||
315 | /* Take all three PLLs out of bypass when safe mode is cleared. */ | |
316 | cm_write_bypass(0); | |
317 | ||
318 | /* clear safe mode */ | |
94172c79 LFT |
319 | cm_write_ctrl(readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_CTRL) | |
320 | CLKMGR_CTRL_SAFEMODE); | |
de778115 LFT |
321 | |
322 | /* | |
323 | * now that safe mode is clear with clocks gated | |
324 | * it safe to change the source mux for the flashes the the L4_MAIN | |
325 | */ | |
94172c79 LFT |
326 | writel(cfg->persrc, |
327 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_SRC); | |
328 | writel(cfg->l4src, | |
329 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_L4SRC); | |
de778115 LFT |
330 | |
331 | /* Now ungate non-hw-managed clocks */ | |
94172c79 LFT |
332 | writel(~0, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_EN); |
333 | writel(~0, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_EN); | |
334 | writel(~0, socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_EN); | |
de778115 LFT |
335 | |
336 | /* Clear the loss of lock bits (write 1 to clear) */ | |
94172c79 LFT |
337 | writel(CLKMGR_INTER_SDRPLLLOST_MASK | |
338 | CLKMGR_INTER_PERPLLLOST_MASK | | |
339 | CLKMGR_INTER_MAINPLLLOST_MASK, | |
340 | socfpga_get_clkmgr_addr() + CLKMGR_GEN5_INTER); | |
de778115 LFT |
341 | |
342 | return 0; | |
343 | } | |
344 | ||
345 | static unsigned int cm_get_main_vco_clk_hz(void) | |
346 | { | |
347 | u32 reg, clock; | |
348 | ||
349 | /* get the main VCO clock */ | |
94172c79 | 350 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_VCO); |
de778115 LFT |
351 | clock = cm_get_osc_clk_hz(1); |
352 | clock /= ((reg & CLKMGR_MAINPLLGRP_VCO_DENOM_MASK) >> | |
353 | CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) + 1; | |
354 | clock *= ((reg & CLKMGR_MAINPLLGRP_VCO_NUMER_MASK) >> | |
355 | CLKMGR_MAINPLLGRP_VCO_NUMER_OFFSET) + 1; | |
356 | ||
357 | return clock; | |
358 | } | |
359 | ||
360 | static unsigned int cm_get_per_vco_clk_hz(void) | |
361 | { | |
362 | u32 reg, clock = 0; | |
363 | ||
364 | /* identify PER PLL clock source */ | |
94172c79 | 365 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
366 | reg = (reg & CLKMGR_PERPLLGRP_VCO_SSRC_MASK) >> |
367 | CLKMGR_PERPLLGRP_VCO_SSRC_OFFSET; | |
368 | if (reg == CLKMGR_VCO_SSRC_EOSC1) | |
369 | clock = cm_get_osc_clk_hz(1); | |
370 | else if (reg == CLKMGR_VCO_SSRC_EOSC2) | |
371 | clock = cm_get_osc_clk_hz(2); | |
372 | else if (reg == CLKMGR_VCO_SSRC_F2S) | |
373 | clock = cm_get_f2s_per_ref_clk_hz(); | |
374 | ||
375 | /* get the PER VCO clock */ | |
94172c79 | 376 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_VCO); |
de778115 LFT |
377 | clock /= ((reg & CLKMGR_PERPLLGRP_VCO_DENOM_MASK) >> |
378 | CLKMGR_PERPLLGRP_VCO_DENOM_OFFSET) + 1; | |
379 | clock *= ((reg & CLKMGR_PERPLLGRP_VCO_NUMER_MASK) >> | |
380 | CLKMGR_PERPLLGRP_VCO_NUMER_OFFSET) + 1; | |
381 | ||
382 | return clock; | |
383 | } | |
384 | ||
385 | unsigned long cm_get_mpu_clk_hz(void) | |
386 | { | |
387 | u32 reg, clock; | |
388 | ||
389 | clock = cm_get_main_vco_clk_hz(); | |
390 | ||
391 | /* get the MPU clock */ | |
94172c79 | 392 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_ALTR_MPUCLK); |
de778115 | 393 | clock /= (reg + 1); |
94172c79 | 394 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MPUCLK); |
de778115 LFT |
395 | clock /= (reg + 1); |
396 | return clock; | |
397 | } | |
398 | ||
399 | unsigned long cm_get_sdram_clk_hz(void) | |
400 | { | |
401 | u32 reg, clock = 0; | |
402 | ||
403 | /* identify SDRAM PLL clock source */ | |
94172c79 | 404 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); |
de778115 LFT |
405 | reg = (reg & CLKMGR_SDRPLLGRP_VCO_SSRC_MASK) >> |
406 | CLKMGR_SDRPLLGRP_VCO_SSRC_OFFSET; | |
407 | if (reg == CLKMGR_VCO_SSRC_EOSC1) | |
408 | clock = cm_get_osc_clk_hz(1); | |
409 | else if (reg == CLKMGR_VCO_SSRC_EOSC2) | |
410 | clock = cm_get_osc_clk_hz(2); | |
411 | else if (reg == CLKMGR_VCO_SSRC_F2S) | |
412 | clock = cm_get_f2s_sdr_ref_clk_hz(); | |
413 | ||
414 | /* get the SDRAM VCO clock */ | |
94172c79 | 415 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_VCO); |
de778115 LFT |
416 | clock /= ((reg & CLKMGR_SDRPLLGRP_VCO_DENOM_MASK) >> |
417 | CLKMGR_SDRPLLGRP_VCO_DENOM_OFFSET) + 1; | |
418 | clock *= ((reg & CLKMGR_SDRPLLGRP_VCO_NUMER_MASK) >> | |
419 | CLKMGR_SDRPLLGRP_VCO_NUMER_OFFSET) + 1; | |
420 | ||
421 | /* get the SDRAM (DDR_DQS) clock */ | |
94172c79 | 422 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_SDRPLL_DDRDQSCLK); |
de778115 LFT |
423 | reg = (reg & CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK) >> |
424 | CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_OFFSET; | |
425 | clock /= (reg + 1); | |
426 | ||
427 | return clock; | |
428 | } | |
429 | ||
430 | unsigned int cm_get_l4_sp_clk_hz(void) | |
431 | { | |
432 | u32 reg, clock = 0; | |
433 | ||
434 | /* identify the source of L4 SP clock */ | |
94172c79 | 435 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_L4SRC); |
de778115 LFT |
436 | reg = (reg & CLKMGR_MAINPLLGRP_L4SRC_L4SP) >> |
437 | CLKMGR_MAINPLLGRP_L4SRC_L4SP_OFFSET; | |
438 | ||
439 | if (reg == CLKMGR_L4_SP_CLK_SRC_MAINPLL) { | |
440 | clock = cm_get_main_vco_clk_hz(); | |
441 | ||
442 | /* get the clock prior L4 SP divider (main clk) */ | |
94172c79 LFT |
443 | reg = readl(socfpga_get_clkmgr_addr() + |
444 | CLKMGR_GEN5_ALTR_MAINCLK); | |
de778115 | 445 | clock /= (reg + 1); |
94172c79 LFT |
446 | reg = readl(socfpga_get_clkmgr_addr() + |
447 | CLKMGR_GEN5_MAINPLL_MAINCLK); | |
de778115 LFT |
448 | clock /= (reg + 1); |
449 | } else if (reg == CLKMGR_L4_SP_CLK_SRC_PERPLL) { | |
450 | clock = cm_get_per_vco_clk_hz(); | |
451 | ||
452 | /* get the clock prior L4 SP divider (periph_base_clk) */ | |
94172c79 LFT |
453 | reg = readl(socfpga_get_clkmgr_addr() + |
454 | CLKMGR_GEN5_PERPLL_PERBASECLK); | |
de778115 LFT |
455 | clock /= (reg + 1); |
456 | } | |
457 | ||
458 | /* get the L4 SP clock which supplied to UART */ | |
94172c79 | 459 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_MAINPLL_MAINDIV); |
de778115 LFT |
460 | reg = (reg & CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_MASK) >> |
461 | CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_OFFSET; | |
462 | clock = clock / (1 << reg); | |
463 | ||
464 | return clock; | |
465 | } | |
466 | ||
467 | unsigned int cm_get_mmc_controller_clk_hz(void) | |
468 | { | |
469 | u32 reg, clock = 0; | |
470 | ||
471 | /* identify the source of MMC clock */ | |
94172c79 | 472 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_SRC); |
de778115 LFT |
473 | reg = (reg & CLKMGR_PERPLLGRP_SRC_SDMMC_MASK) >> |
474 | CLKMGR_PERPLLGRP_SRC_SDMMC_OFFSET; | |
475 | ||
476 | if (reg == CLKMGR_SDMMC_CLK_SRC_F2S) { | |
477 | clock = cm_get_f2s_per_ref_clk_hz(); | |
478 | } else if (reg == CLKMGR_SDMMC_CLK_SRC_MAIN) { | |
479 | clock = cm_get_main_vco_clk_hz(); | |
480 | ||
481 | /* get the SDMMC clock */ | |
94172c79 LFT |
482 | reg = readl(socfpga_get_clkmgr_addr() + |
483 | CLKMGR_GEN5_MAINPLL_MAINNANDSDMMCCLK); | |
de778115 LFT |
484 | clock /= (reg + 1); |
485 | } else if (reg == CLKMGR_SDMMC_CLK_SRC_PER) { | |
486 | clock = cm_get_per_vco_clk_hz(); | |
487 | ||
488 | /* get the SDMMC clock */ | |
94172c79 LFT |
489 | reg = readl(socfpga_get_clkmgr_addr() + |
490 | CLKMGR_GEN5_PERPLL_PERNANDSDMMCCLK); | |
de778115 LFT |
491 | clock /= (reg + 1); |
492 | } | |
493 | ||
494 | /* further divide by 4 as we have fixed divider at wrapper */ | |
495 | clock /= 4; | |
496 | return clock; | |
497 | } | |
498 | ||
499 | unsigned int cm_get_qspi_controller_clk_hz(void) | |
500 | { | |
501 | u32 reg, clock = 0; | |
502 | ||
503 | /* identify the source of QSPI clock */ | |
94172c79 | 504 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_SRC); |
de778115 LFT |
505 | reg = (reg & CLKMGR_PERPLLGRP_SRC_QSPI_MASK) >> |
506 | CLKMGR_PERPLLGRP_SRC_QSPI_OFFSET; | |
507 | ||
508 | if (reg == CLKMGR_QSPI_CLK_SRC_F2S) { | |
509 | clock = cm_get_f2s_per_ref_clk_hz(); | |
510 | } else if (reg == CLKMGR_QSPI_CLK_SRC_MAIN) { | |
511 | clock = cm_get_main_vco_clk_hz(); | |
512 | ||
513 | /* get the qspi clock */ | |
94172c79 LFT |
514 | reg = readl(socfpga_get_clkmgr_addr() + |
515 | CLKMGR_GEN5_MAINPLL_MAINQSPICLK); | |
de778115 LFT |
516 | clock /= (reg + 1); |
517 | } else if (reg == CLKMGR_QSPI_CLK_SRC_PER) { | |
518 | clock = cm_get_per_vco_clk_hz(); | |
519 | ||
520 | /* get the qspi clock */ | |
94172c79 LFT |
521 | reg = readl(socfpga_get_clkmgr_addr() + |
522 | CLKMGR_GEN5_PERPLL_PERQSPICLK); | |
de778115 LFT |
523 | clock /= (reg + 1); |
524 | } | |
525 | ||
526 | return clock; | |
527 | } | |
528 | ||
529 | unsigned int cm_get_spi_controller_clk_hz(void) | |
530 | { | |
531 | u32 reg, clock = 0; | |
532 | ||
533 | clock = cm_get_per_vco_clk_hz(); | |
534 | ||
535 | /* get the clock prior L4 SP divider (periph_base_clk) */ | |
94172c79 | 536 | reg = readl(socfpga_get_clkmgr_addr() + CLKMGR_GEN5_PERPLL_PERBASECLK); |
de778115 LFT |
537 | clock /= (reg + 1); |
538 | ||
539 | return clock; | |
540 | } | |
541 | ||
21143ce1 EP |
542 | /* Override weak dw_spi_get_clk implementation in designware_spi.c driver */ |
543 | int dw_spi_get_clk(struct udevice *bus, ulong *rate) | |
544 | { | |
545 | *rate = cm_get_spi_controller_clk_hz(); | |
546 | ||
547 | return 0; | |
548 | } | |
549 | ||
de778115 LFT |
550 | void cm_print_clock_quick_summary(void) |
551 | { | |
552 | printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000); | |
553 | printf("DDR %10ld kHz\n", cm_get_sdram_clk_hz() / 1000); | |
554 | printf("EOSC1 %8d kHz\n", cm_get_osc_clk_hz(1) / 1000); | |
555 | printf("EOSC2 %8d kHz\n", cm_get_osc_clk_hz(2) / 1000); | |
556 | printf("F2S_SDR_REF %8d kHz\n", cm_get_f2s_sdr_ref_clk_hz() / 1000); | |
557 | printf("F2S_PER_REF %8d kHz\n", cm_get_f2s_per_ref_clk_hz() / 1000); | |
558 | printf("MMC %8d kHz\n", cm_get_mmc_controller_clk_hz() / 1000); | |
559 | printf("QSPI %8d kHz\n", cm_get_qspi_controller_clk_hz() / 1000); | |
560 | printf("UART %8d kHz\n", cm_get_l4_sp_clk_hz() / 1000); | |
561 | printf("SPI %8d kHz\n", cm_get_spi_controller_clk_hz() / 1000); | |
562 | } |