]>
Commit | Line | Data |
---|---|---|
3776801d A |
1 | /* |
2 | * | |
3 | * Clock initialization for OMAP4 | |
4 | * | |
5 | * (C) Copyright 2010 | |
6 | * Texas Instruments, <www.ti.com> | |
7 | * | |
8 | * Aneesh V <aneesh@ti.com> | |
9 | * | |
10 | * Based on previous work by: | |
11 | * Santosh Shilimkar <santosh.shilimkar@ti.com> | |
12 | * Rajendra Nayak <rnayak@ti.com> | |
13 | * | |
1a459660 | 14 | * SPDX-License-Identifier: GPL-2.0+ |
3776801d A |
15 | */ |
16 | #include <common.h> | |
63fc0c77 | 17 | #include <i2c.h> |
3776801d | 18 | #include <asm/omap_common.h> |
3b690ebb | 19 | #include <asm/gpio.h> |
af1d002f | 20 | #include <asm/arch/clock.h> |
3776801d A |
21 | #include <asm/arch/sys_proto.h> |
22 | #include <asm/utils.h> | |
d506719f | 23 | #include <asm/omap_gpio.h> |
9ca8bfea | 24 | #include <asm/emif.h> |
3776801d A |
25 | |
26 | #ifndef CONFIG_SPL_BUILD | |
27 | /* | |
28 | * printing to console doesn't work unless | |
29 | * this code is executed from SPL | |
30 | */ | |
31 | #define printf(fmt, args...) | |
32 | #define puts(s) | |
33 | #endif | |
34 | ||
ee9447bf S |
35 | const u32 sys_clk_array[8] = { |
36 | 12000000, /* 12 MHz */ | |
97405d84 | 37 | 20000000, /* 20 MHz */ |
ee9447bf S |
38 | 16800000, /* 16.8 MHz */ |
39 | 19200000, /* 19.2 MHz */ | |
40 | 26000000, /* 26 MHz */ | |
41 | 27000000, /* 27 MHz */ | |
42 | 38400000, /* 38.4 MHz */ | |
43 | }; | |
44 | ||
3776801d A |
45 | static inline u32 __get_sys_clk_index(void) |
46 | { | |
ea8eff1f | 47 | s8 ind; |
3776801d A |
48 | /* |
49 | * For ES1 the ROM code calibration of sys clock is not reliable | |
50 | * due to hw issue. So, use hard-coded value. If this value is not | |
51 | * correct for any board over-ride this function in board file | |
52 | * From ES2.0 onwards you will get this information from | |
53 | * CM_SYS_CLKSEL | |
54 | */ | |
55 | if (omap_revision() == OMAP4430_ES1_0) | |
56 | ind = OMAP_SYS_CLK_IND_38_4_MHZ; | |
57 | else { | |
58 | /* SYS_CLKSEL - 1 to match the dpll param array indices */ | |
01b753ff | 59 | ind = (readl((*prcm)->cm_sys_clksel) & |
3776801d A |
60 | CM_SYS_CLKSEL_SYS_CLKSEL_MASK) - 1; |
61 | } | |
62 | return ind; | |
63 | } | |
64 | ||
65 | u32 get_sys_clk_index(void) | |
66 | __attribute__ ((weak, alias("__get_sys_clk_index"))); | |
67 | ||
68 | u32 get_sys_clk_freq(void) | |
69 | { | |
70 | u8 index = get_sys_clk_index(); | |
71 | return sys_clk_array[index]; | |
72 | } | |
73 | ||
ee9447bf S |
74 | void setup_post_dividers(u32 const base, const struct dpll_params *params) |
75 | { | |
76 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; | |
77 | ||
78 | /* Setup post-dividers */ | |
79 | if (params->m2 >= 0) | |
80 | writel(params->m2, &dpll_regs->cm_div_m2_dpll); | |
81 | if (params->m3 >= 0) | |
82 | writel(params->m3, &dpll_regs->cm_div_m3_dpll); | |
83 | if (params->m4_h11 >= 0) | |
84 | writel(params->m4_h11, &dpll_regs->cm_div_m4_h11_dpll); | |
85 | if (params->m5_h12 >= 0) | |
86 | writel(params->m5_h12, &dpll_regs->cm_div_m5_h12_dpll); | |
87 | if (params->m6_h13 >= 0) | |
88 | writel(params->m6_h13, &dpll_regs->cm_div_m6_h13_dpll); | |
89 | if (params->m7_h14 >= 0) | |
90 | writel(params->m7_h14, &dpll_regs->cm_div_m7_h14_dpll); | |
47abc3df S |
91 | if (params->h21 >= 0) |
92 | writel(params->h21, &dpll_regs->cm_div_h21_dpll); | |
ee9447bf S |
93 | if (params->h22 >= 0) |
94 | writel(params->h22, &dpll_regs->cm_div_h22_dpll); | |
95 | if (params->h23 >= 0) | |
96 | writel(params->h23, &dpll_regs->cm_div_h23_dpll); | |
47abc3df S |
97 | if (params->h24 >= 0) |
98 | writel(params->h24, &dpll_regs->cm_div_h24_dpll); | |
ee9447bf S |
99 | } |
100 | ||
01b753ff | 101 | static inline void do_bypass_dpll(u32 const base) |
3776801d A |
102 | { |
103 | struct dpll_regs *dpll_regs = (struct dpll_regs *)base; | |
104 | ||
105 | clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, | |
106 | CM_CLKMODE_DPLL_DPLL_EN_MASK, | |
107 | DPLL_EN_FAST_RELOCK_BYPASS << | |
108 | CM_CLKMODE_DPLL_EN_SHIFT); | |
109 | } | |
110 | ||
01b753ff | 111 | static inline void wait_for_bypass(u32 const base) |
3776801d A |
112 | { |
113 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; | |
114 | ||
115 | if (!wait_on_value(ST_DPLL_CLK_MASK, 0, &dpll_regs->cm_idlest_dpll, | |
116 | LDELAY)) { | |
01b753ff | 117 | printf("Bypassing DPLL failed %x\n", base); |
3776801d A |
118 | } |
119 | } | |
120 | ||
01b753ff | 121 | static inline void do_lock_dpll(u32 const base) |
3776801d A |
122 | { |
123 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; | |
124 | ||
125 | clrsetbits_le32(&dpll_regs->cm_clkmode_dpll, | |
126 | CM_CLKMODE_DPLL_DPLL_EN_MASK, | |
127 | DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT); | |
128 | } | |
129 | ||
01b753ff | 130 | static inline void wait_for_lock(u32 const base) |
3776801d A |
131 | { |
132 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; | |
133 | ||
134 | if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK, | |
135 | &dpll_regs->cm_idlest_dpll, LDELAY)) { | |
01b753ff | 136 | printf("DPLL locking failed for %x\n", base); |
3776801d A |
137 | hang(); |
138 | } | |
139 | } | |
140 | ||
01b753ff | 141 | inline u32 check_for_lock(u32 const base) |
78f455c0 S |
142 | { |
143 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; | |
144 | u32 lock = readl(&dpll_regs->cm_idlest_dpll) & ST_DPLL_CLK_MASK; | |
145 | ||
146 | return lock; | |
147 | } | |
148 | ||
ee9447bf S |
149 | const struct dpll_params *get_mpu_dpll_params(struct dplls const *dpll_data) |
150 | { | |
151 | u32 sysclk_ind = get_sys_clk_index(); | |
152 | return &dpll_data->mpu[sysclk_ind]; | |
153 | } | |
154 | ||
155 | const struct dpll_params *get_core_dpll_params(struct dplls const *dpll_data) | |
156 | { | |
157 | u32 sysclk_ind = get_sys_clk_index(); | |
158 | return &dpll_data->core[sysclk_ind]; | |
159 | } | |
160 | ||
161 | const struct dpll_params *get_per_dpll_params(struct dplls const *dpll_data) | |
162 | { | |
163 | u32 sysclk_ind = get_sys_clk_index(); | |
164 | return &dpll_data->per[sysclk_ind]; | |
165 | } | |
166 | ||
167 | const struct dpll_params *get_iva_dpll_params(struct dplls const *dpll_data) | |
168 | { | |
169 | u32 sysclk_ind = get_sys_clk_index(); | |
170 | return &dpll_data->iva[sysclk_ind]; | |
171 | } | |
172 | ||
173 | const struct dpll_params *get_usb_dpll_params(struct dplls const *dpll_data) | |
174 | { | |
175 | u32 sysclk_ind = get_sys_clk_index(); | |
176 | return &dpll_data->usb[sysclk_ind]; | |
177 | } | |
178 | ||
179 | const struct dpll_params *get_abe_dpll_params(struct dplls const *dpll_data) | |
180 | { | |
181 | #ifdef CONFIG_SYS_OMAP_ABE_SYSCK | |
182 | u32 sysclk_ind = get_sys_clk_index(); | |
183 | return &dpll_data->abe[sysclk_ind]; | |
184 | #else | |
185 | return dpll_data->abe; | |
186 | #endif | |
187 | } | |
188 | ||
ea8eff1f LV |
189 | static const struct dpll_params *get_ddr_dpll_params |
190 | (struct dplls const *dpll_data) | |
191 | { | |
192 | u32 sysclk_ind = get_sys_clk_index(); | |
193 | ||
194 | if (!dpll_data->ddr) | |
195 | return NULL; | |
196 | return &dpll_data->ddr[sysclk_ind]; | |
197 | } | |
198 | ||
65e9d56f LV |
199 | #ifdef CONFIG_DRIVER_TI_CPSW |
200 | static const struct dpll_params *get_gmac_dpll_params | |
201 | (struct dplls const *dpll_data) | |
202 | { | |
203 | u32 sysclk_ind = get_sys_clk_index(); | |
204 | ||
205 | if (!dpll_data->gmac) | |
206 | return NULL; | |
207 | return &dpll_data->gmac[sysclk_ind]; | |
208 | } | |
209 | #endif | |
210 | ||
01b753ff | 211 | static void do_setup_dpll(u32 const base, const struct dpll_params *params, |
78f455c0 | 212 | u8 lock, char *dpll) |
3776801d | 213 | { |
78f455c0 | 214 | u32 temp, M, N; |
3776801d A |
215 | struct dpll_regs *const dpll_regs = (struct dpll_regs *)base; |
216 | ||
ea8eff1f LV |
217 | if (!params) |
218 | return; | |
219 | ||
78f455c0 S |
220 | temp = readl(&dpll_regs->cm_clksel_dpll); |
221 | ||
222 | if (check_for_lock(base)) { | |
223 | /* | |
224 | * The Dpll has already been locked by rom code using CH. | |
225 | * Check if M,N are matching with Ideal nominal opp values. | |
226 | * If matches, skip the rest otherwise relock. | |
227 | */ | |
228 | M = (temp & CM_CLKSEL_DPLL_M_MASK) >> CM_CLKSEL_DPLL_M_SHIFT; | |
229 | N = (temp & CM_CLKSEL_DPLL_N_MASK) >> CM_CLKSEL_DPLL_N_SHIFT; | |
230 | if ((M != (params->m)) || (N != (params->n))) { | |
231 | debug("\n %s Dpll locked, but not for ideal M = %d," | |
232 | "N = %d values, current values are M = %d," | |
233 | "N= %d" , dpll, params->m, params->n, | |
234 | M, N); | |
235 | } else { | |
236 | /* Dpll locked with ideal values for nominal opps. */ | |
237 | debug("\n %s Dpll already locked with ideal" | |
238 | "nominal opp values", dpll); | |
239 | goto setup_post_dividers; | |
240 | } | |
241 | } | |
242 | ||
3776801d A |
243 | bypass_dpll(base); |
244 | ||
245 | /* Set M & N */ | |
3776801d A |
246 | temp &= ~CM_CLKSEL_DPLL_M_MASK; |
247 | temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK; | |
248 | ||
249 | temp &= ~CM_CLKSEL_DPLL_N_MASK; | |
250 | temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK; | |
251 | ||
252 | writel(temp, &dpll_regs->cm_clksel_dpll); | |
253 | ||
254 | /* Lock */ | |
255 | if (lock) | |
256 | do_lock_dpll(base); | |
257 | ||
78f455c0 | 258 | setup_post_dividers: |
2e5ba489 | 259 | setup_post_dividers(base, params); |
3776801d A |
260 | |
261 | /* Wait till the DPLL locks */ | |
262 | if (lock) | |
263 | wait_for_lock(base); | |
264 | } | |
265 | ||
2e5ba489 | 266 | u32 omap_ddr_clk(void) |
3776801d | 267 | { |
2e5ba489 | 268 | u32 ddr_clk, sys_clk_khz, omap_rev, divider; |
3776801d A |
269 | const struct dpll_params *core_dpll_params; |
270 | ||
2e5ba489 | 271 | omap_rev = omap_revision(); |
3776801d A |
272 | sys_clk_khz = get_sys_clk_freq() / 1000; |
273 | ||
ee9447bf | 274 | core_dpll_params = get_core_dpll_params(*dplls_data); |
3776801d A |
275 | |
276 | debug("sys_clk %d\n ", sys_clk_khz * 1000); | |
277 | ||
278 | /* Find Core DPLL locked frequency first */ | |
279 | ddr_clk = sys_clk_khz * 2 * core_dpll_params->m / | |
280 | (core_dpll_params->n + 1); | |
3776801d | 281 | |
2e5ba489 S |
282 | if (omap_rev < OMAP5430_ES1_0) { |
283 | /* | |
284 | * DDR frequency is PHY_ROOT_CLK/2 | |
285 | * PHY_ROOT_CLK = Fdpll/2/M2 | |
286 | */ | |
287 | divider = 4; | |
288 | } else { | |
289 | /* | |
290 | * DDR frequency is PHY_ROOT_CLK | |
291 | * PHY_ROOT_CLK = Fdpll/2/M2 | |
292 | */ | |
293 | divider = 2; | |
294 | } | |
295 | ||
296 | ddr_clk = ddr_clk / divider / core_dpll_params->m2; | |
3776801d A |
297 | ddr_clk *= 1000; /* convert to Hz */ |
298 | debug("ddr_clk %d\n ", ddr_clk); | |
299 | ||
300 | return ddr_clk; | |
301 | } | |
302 | ||
b4dc6442 A |
303 | /* |
304 | * Lock MPU dpll | |
305 | * | |
306 | * Resulting MPU frequencies: | |
307 | * 4430 ES1.0 : 600 MHz | |
308 | * 4430 ES2.x : 792 MHz (OPP Turbo) | |
309 | * 4460 : 920 MHz (OPP Turbo) - DCC disabled | |
310 | */ | |
311 | void configure_mpu_dpll(void) | |
312 | { | |
313 | const struct dpll_params *params; | |
314 | struct dpll_regs *mpu_dpll_regs; | |
2e5ba489 S |
315 | u32 omap_rev; |
316 | omap_rev = omap_revision(); | |
b4dc6442 | 317 | |
2e5ba489 S |
318 | /* |
319 | * DCC and clock divider settings for 4460. | |
320 | * DCC is required, if more than a certain frequency is required. | |
321 | * For, 4460 > 1GHZ. | |
322 | * 5430 > 1.4GHZ. | |
323 | */ | |
324 | if ((omap_rev >= OMAP4460_ES1_0) && (omap_rev < OMAP5430_ES1_0)) { | |
b4dc6442 | 325 | mpu_dpll_regs = |
01b753ff S |
326 | (struct dpll_regs *)((*prcm)->cm_clkmode_dpll_mpu); |
327 | bypass_dpll((*prcm)->cm_clkmode_dpll_mpu); | |
328 | clrbits_le32((*prcm)->cm_mpu_mpu_clkctrl, | |
b4dc6442 | 329 | MPU_CLKCTRL_CLKSEL_EMIF_DIV_MODE_MASK); |
01b753ff | 330 | setbits_le32((*prcm)->cm_mpu_mpu_clkctrl, |
b4dc6442 A |
331 | MPU_CLKCTRL_CLKSEL_ABE_DIV_MODE_MASK); |
332 | clrbits_le32(&mpu_dpll_regs->cm_clksel_dpll, | |
333 | CM_CLKSEL_DCC_EN_MASK); | |
334 | } | |
335 | ||
ee9447bf | 336 | params = get_mpu_dpll_params(*dplls_data); |
78f455c0 | 337 | |
01b753ff | 338 | do_setup_dpll((*prcm)->cm_clkmode_dpll_mpu, params, DPLL_LOCK, "mpu"); |
b4dc6442 A |
339 | debug("MPU DPLL locked\n"); |
340 | } | |
341 | ||
d861a333 | 342 | #if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP) |
860004c1 G |
343 | static void setup_usb_dpll(void) |
344 | { | |
345 | const struct dpll_params *params; | |
346 | u32 sys_clk_khz, sd_div, num, den; | |
347 | ||
348 | sys_clk_khz = get_sys_clk_freq() / 1000; | |
349 | /* | |
350 | * USB: | |
351 | * USB dpll is J-type. Need to set DPLL_SD_DIV for jitter correction | |
352 | * DPLL_SD_DIV = CEILING ([DPLL_MULT/(DPLL_DIV+1)]* CLKINP / 250) | |
353 | * - where CLKINP is sys_clk in MHz | |
354 | * Use CLKINP in KHz and adjust the denominator accordingly so | |
355 | * that we have enough accuracy and at the same time no overflow | |
356 | */ | |
ee9447bf | 357 | params = get_usb_dpll_params(*dplls_data); |
860004c1 G |
358 | num = params->m * sys_clk_khz; |
359 | den = (params->n + 1) * 250 * 1000; | |
360 | num += den - 1; | |
361 | sd_div = num / den; | |
01b753ff | 362 | clrsetbits_le32((*prcm)->cm_clksel_dpll_usb, |
860004c1 G |
363 | CM_CLKSEL_DPLL_DPLL_SD_DIV_MASK, |
364 | sd_div << CM_CLKSEL_DPLL_DPLL_SD_DIV_SHIFT); | |
365 | ||
366 | /* Now setup the dpll with the regular function */ | |
01b753ff | 367 | do_setup_dpll((*prcm)->cm_clkmode_dpll_usb, params, DPLL_LOCK, "usb"); |
860004c1 G |
368 | } |
369 | #endif | |
370 | ||
3776801d A |
371 | static void setup_dplls(void) |
372 | { | |
164a7507 | 373 | u32 temp; |
3776801d | 374 | const struct dpll_params *params; |
7c352cd3 | 375 | struct emif_reg_struct *emif = (struct emif_reg_struct *)EMIF1_BASE; |
3776801d | 376 | |
164a7507 | 377 | debug("setup_dplls\n"); |
3776801d A |
378 | |
379 | /* CORE dpll */ | |
ee9447bf | 380 | params = get_core_dpll_params(*dplls_data); /* default - safest */ |
3776801d A |
381 | /* |
382 | * Do not lock the core DPLL now. Just set it up. | |
383 | * Core DPLL will be locked after setting up EMIF | |
384 | * using the FREQ_UPDATE method(freq_update_core()) | |
385 | */ | |
7c352cd3 TR |
386 | if (emif_sdram_type(readl(&emif->emif_sdram_config)) == |
387 | EMIF_SDRAM_TYPE_LPDDR2) | |
01b753ff | 388 | do_setup_dpll((*prcm)->cm_clkmode_dpll_core, params, |
753bae8c LV |
389 | DPLL_NO_LOCK, "core"); |
390 | else | |
01b753ff | 391 | do_setup_dpll((*prcm)->cm_clkmode_dpll_core, params, |
753bae8c | 392 | DPLL_LOCK, "core"); |
3776801d A |
393 | /* Set the ratios for CORE_CLK, L3_CLK, L4_CLK */ |
394 | temp = (CLKSEL_CORE_X2_DIV_1 << CLKSEL_CORE_SHIFT) | | |
395 | (CLKSEL_L3_CORE_DIV_2 << CLKSEL_L3_SHIFT) | | |
396 | (CLKSEL_L4_L3_DIV_2 << CLKSEL_L4_SHIFT); | |
01b753ff | 397 | writel(temp, (*prcm)->cm_clksel_core); |
3776801d A |
398 | debug("Core DPLL configured\n"); |
399 | ||
400 | /* lock PER dpll */ | |
ee9447bf | 401 | params = get_per_dpll_params(*dplls_data); |
01b753ff | 402 | do_setup_dpll((*prcm)->cm_clkmode_dpll_per, |
78f455c0 | 403 | params, DPLL_LOCK, "per"); |
3776801d A |
404 | debug("PER DPLL locked\n"); |
405 | ||
406 | /* MPU dpll */ | |
b4dc6442 | 407 | configure_mpu_dpll(); |
860004c1 | 408 | |
d861a333 | 409 | #if defined(CONFIG_USB_EHCI_OMAP) || defined(CONFIG_USB_XHCI_OMAP) |
860004c1 G |
410 | setup_usb_dpll(); |
411 | #endif | |
ea8eff1f LV |
412 | params = get_ddr_dpll_params(*dplls_data); |
413 | do_setup_dpll((*prcm)->cm_clkmode_dpll_ddrphy, | |
414 | params, DPLL_LOCK, "ddr"); | |
65e9d56f LV |
415 | |
416 | #ifdef CONFIG_DRIVER_TI_CPSW | |
417 | params = get_gmac_dpll_params(*dplls_data); | |
418 | do_setup_dpll((*prcm)->cm_clkmode_dpll_gmac, params, | |
419 | DPLL_LOCK, "gmac"); | |
420 | #endif | |
3776801d A |
421 | } |
422 | ||
3fcdd4a5 | 423 | u32 get_offset_code(u32 volt_offset, struct pmic_data *pmic) |
d506719f | 424 | { |
3fcdd4a5 | 425 | u32 offset_code; |
d506719f | 426 | |
3fcdd4a5 | 427 | volt_offset -= pmic->base_offset; |
d506719f | 428 | |
3fcdd4a5 | 429 | offset_code = (volt_offset + pmic->step - 1) / pmic->step; |
3acb5534 | 430 | |
3fcdd4a5 S |
431 | /* |
432 | * Offset codes 1-6 all give the base voltage in Palmas | |
433 | * Offset code 0 switches OFF the SMPS | |
434 | */ | |
435 | return offset_code + pmic->start_code; | |
d506719f A |
436 | } |
437 | ||
3fcdd4a5 | 438 | void do_scale_vcore(u32 vcore_reg, u32 volt_mv, struct pmic_data *pmic) |
3776801d | 439 | { |
a78274b2 | 440 | u32 offset_code; |
3776801d | 441 | u32 offset = volt_mv; |
b558af81 | 442 | #ifndef CONFIG_DRA7XX |
3fcdd4a5 | 443 | int ret = 0; |
b558af81 | 444 | #endif |
3fcdd4a5 | 445 | |
63fc0c77 LV |
446 | if (!volt_mv) |
447 | return; | |
448 | ||
4ca94d81 | 449 | pmic->pmic_bus_init(); |
b558af81 | 450 | #ifndef CONFIG_DRA7XX |
3fcdd4a5 S |
451 | /* See if we can first get the GPIO if needed */ |
452 | if (pmic->gpio_en) | |
453 | ret = gpio_request(pmic->gpio, "PMIC_GPIO"); | |
454 | ||
455 | if (ret < 0) { | |
456 | printf("%s: gpio %d request failed %d\n", __func__, | |
457 | pmic->gpio, ret); | |
458 | return; | |
459 | } | |
460 | ||
461 | /* Pull the GPIO low to select SET0 register, while we program SET1 */ | |
462 | if (pmic->gpio_en) | |
463 | gpio_direction_output(pmic->gpio, 0); | |
b558af81 | 464 | #endif |
3776801d A |
465 | /* convert to uV for better accuracy in the calculations */ |
466 | offset *= 1000; | |
467 | ||
3fcdd4a5 | 468 | offset_code = get_offset_code(offset, pmic); |
3776801d A |
469 | |
470 | debug("do_scale_vcore: volt - %d offset_code - 0x%x\n", volt_mv, | |
471 | offset_code); | |
8de17f46 | 472 | |
4ca94d81 | 473 | if (pmic->pmic_write(pmic->i2c_slave_addr, vcore_reg, offset_code)) |
3776801d | 474 | printf("Scaling voltage failed for 0x%x\n", vcore_reg); |
b558af81 | 475 | #ifndef CONFIG_DRA7XX |
3fcdd4a5 S |
476 | if (pmic->gpio_en) |
477 | gpio_direction_output(pmic->gpio, 1); | |
b558af81 | 478 | #endif |
3fcdd4a5 S |
479 | } |
480 | ||
18c9d55a NM |
481 | static u32 optimize_vcore_voltage(struct volts const *v) |
482 | { | |
483 | u32 val; | |
484 | if (!v->value) | |
485 | return 0; | |
486 | if (!v->efuse.reg) | |
487 | return v->value; | |
488 | ||
489 | switch (v->efuse.reg_bits) { | |
490 | case 16: | |
491 | val = readw(v->efuse.reg); | |
492 | break; | |
493 | case 32: | |
494 | val = readl(v->efuse.reg); | |
495 | break; | |
496 | default: | |
497 | printf("Error: efuse 0x%08x bits=%d unknown\n", | |
498 | v->efuse.reg, v->efuse.reg_bits); | |
499 | return v->value; | |
500 | } | |
501 | ||
502 | if (!val) { | |
503 | printf("Error: efuse 0x%08x bits=%d val=0, using %d\n", | |
504 | v->efuse.reg, v->efuse.reg_bits, v->value); | |
505 | return v->value; | |
506 | } | |
507 | ||
508 | debug("%s:efuse 0x%08x bits=%d Vnom=%d, using efuse value %d\n", | |
509 | __func__, v->efuse.reg, v->efuse.reg_bits, v->value, val); | |
510 | return val; | |
511 | } | |
512 | ||
eda6fbcc LV |
513 | #ifdef CONFIG_IODELAY_RECALIBRATION |
514 | void __weak recalibrate_iodelay(void) | |
515 | { | |
516 | } | |
517 | #endif | |
518 | ||
3fcdd4a5 | 519 | /* |
b558af81 LP |
520 | * Setup the voltages for the main SoC core power domains. |
521 | * We start with the maximum voltages allowed here, as set in the corresponding | |
522 | * vcores_data struct, and then scale (usually down) to the fused values that | |
523 | * are retrieved from the SoC. The scaling happens only if the efuse.reg fields | |
524 | * are initialised. | |
525 | * Rail grouping is supported for the DRA7xx SoCs only, therefore the code is | |
526 | * compiled conditionally. Note that the new code writes the scaled (or zeroed) | |
527 | * values back to the vcores_data struct for eventual reuse. Zero values mean | |
528 | * that the corresponding rails are not controlled separately, and are not sent | |
529 | * to the PMIC. | |
3fcdd4a5 S |
530 | */ |
531 | void scale_vcores(struct vcores_data const *vcores) | |
532 | { | |
b558af81 LP |
533 | #if defined(CONFIG_DRA7XX) |
534 | int i; | |
535 | struct volts *pv = (struct volts *)vcores; | |
536 | struct volts *px; | |
537 | ||
538 | for (i=0; i<(sizeof(struct vcores_data)/sizeof(struct volts)); i++) { | |
539 | debug("%d -> ", pv->value); | |
540 | if (pv->value) { | |
541 | /* Handle non-empty members only */ | |
542 | pv->value = optimize_vcore_voltage(pv); | |
543 | px = (struct volts *)vcores; | |
544 | while (px < pv) { | |
545 | /* | |
546 | * Scan already handled non-empty members to see | |
547 | * if we have a group and find the max voltage, | |
548 | * which is set to the first occurance of the | |
549 | * particular SMPS; the other group voltages are | |
550 | * zeroed. | |
551 | */ | |
552 | if (px->value) { | |
553 | if ((pv->pmic->i2c_slave_addr == | |
554 | px->pmic->i2c_slave_addr) && | |
555 | (pv->addr == px->addr)) { | |
556 | /* Same PMIC, same SMPS */ | |
557 | if (pv->value > px->value) | |
558 | px->value = pv->value; | |
559 | ||
560 | pv->value = 0; | |
561 | } | |
562 | } | |
563 | px++; | |
564 | } | |
565 | } | |
566 | debug("%d\n", pv->value); | |
567 | pv++; | |
568 | } | |
569 | ||
570 | debug("cor: %d\n", vcores->core.value); | |
571 | do_scale_vcore(vcores->core.addr, vcores->core.value, vcores->core.pmic); | |
eda6fbcc LV |
572 | /* |
573 | * IO delay recalibration should be done immediately after | |
574 | * adjusting AVS voltages for VDD_CORE_L. | |
575 | * Respective boards should call __recalibrate_iodelay() | |
576 | * with proper mux, virtual and manual mode configurations. | |
577 | */ | |
578 | #ifdef CONFIG_IODELAY_RECALIBRATION | |
579 | recalibrate_iodelay(); | |
580 | #endif | |
581 | ||
b558af81 LP |
582 | debug("mpu: %d\n", vcores->mpu.value); |
583 | do_scale_vcore(vcores->mpu.addr, vcores->mpu.value, vcores->mpu.pmic); | |
584 | /* Configure MPU ABB LDO after scale */ | |
585 | abb_setup((*ctrl)->control_std_fuse_opp_vdd_mpu_2, | |
586 | (*ctrl)->control_wkup_ldovbb_mpu_voltage_ctrl, | |
587 | (*prcm)->prm_abbldo_mpu_setup, | |
588 | (*prcm)->prm_abbldo_mpu_ctrl, | |
589 | (*prcm)->prm_irqstatus_mpu_2, | |
590 | OMAP_ABB_MPU_TXDONE_MASK, | |
591 | OMAP_ABB_FAST_OPP); | |
592 | ||
593 | /* The .mm member is not used for the DRA7xx */ | |
594 | ||
595 | debug("gpu: %d\n", vcores->gpu.value); | |
596 | do_scale_vcore(vcores->gpu.addr, vcores->gpu.value, vcores->gpu.pmic); | |
597 | debug("eve: %d\n", vcores->eve.value); | |
598 | do_scale_vcore(vcores->eve.addr, vcores->eve.value, vcores->eve.pmic); | |
599 | debug("iva: %d\n", vcores->iva.value); | |
600 | do_scale_vcore(vcores->iva.addr, vcores->iva.value, vcores->iva.pmic); | |
601 | /* Might need udelay(1000) here if debug is enabled to see all prints */ | |
602 | #else | |
18c9d55a NM |
603 | u32 val; |
604 | ||
605 | val = optimize_vcore_voltage(&vcores->core); | |
606 | do_scale_vcore(vcores->core.addr, val, vcores->core.pmic); | |
3fcdd4a5 | 607 | |
eda6fbcc LV |
608 | /* |
609 | * IO delay recalibration should be done immediately after | |
610 | * adjusting AVS voltages for VDD_CORE_L. | |
611 | * Respective boards should call __recalibrate_iodelay() | |
612 | * with proper mux, virtual and manual mode configurations. | |
613 | */ | |
614 | #ifdef CONFIG_IODELAY_RECALIBRATION | |
615 | recalibrate_iodelay(); | |
616 | #endif | |
617 | ||
18c9d55a NM |
618 | val = optimize_vcore_voltage(&vcores->mpu); |
619 | do_scale_vcore(vcores->mpu.addr, val, vcores->mpu.pmic); | |
3fcdd4a5 | 620 | |
e69c585d AT |
621 | /* Configure MPU ABB LDO after scale */ |
622 | abb_setup((*ctrl)->control_std_fuse_opp_vdd_mpu_2, | |
623 | (*ctrl)->control_wkup_ldovbb_mpu_voltage_ctrl, | |
624 | (*prcm)->prm_abbldo_mpu_setup, | |
625 | (*prcm)->prm_abbldo_mpu_ctrl, | |
626 | (*prcm)->prm_irqstatus_mpu_2, | |
627 | OMAP_ABB_MPU_TXDONE_MASK, | |
628 | OMAP_ABB_FAST_OPP); | |
629 | ||
18c9d55a NM |
630 | val = optimize_vcore_voltage(&vcores->mm); |
631 | do_scale_vcore(vcores->mm.addr, val, vcores->mm.pmic); | |
3fcdd4a5 | 632 | |
18c9d55a NM |
633 | val = optimize_vcore_voltage(&vcores->gpu); |
634 | do_scale_vcore(vcores->gpu.addr, val, vcores->gpu.pmic); | |
63fc0c77 | 635 | |
18c9d55a NM |
636 | val = optimize_vcore_voltage(&vcores->eve); |
637 | do_scale_vcore(vcores->eve.addr, val, vcores->eve.pmic); | |
63fc0c77 | 638 | |
18c9d55a NM |
639 | val = optimize_vcore_voltage(&vcores->iva); |
640 | do_scale_vcore(vcores->iva.addr, val, vcores->iva.pmic); | |
b558af81 | 641 | #endif |
3776801d A |
642 | } |
643 | ||
01b753ff | 644 | static inline void enable_clock_domain(u32 const clkctrl_reg, u32 enable_mode) |
3776801d A |
645 | { |
646 | clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK, | |
647 | enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT); | |
01b753ff | 648 | debug("Enable clock domain - %x\n", clkctrl_reg); |
3776801d A |
649 | } |
650 | ||
01b753ff | 651 | static inline void wait_for_clk_enable(u32 clkctrl_addr) |
3776801d A |
652 | { |
653 | u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED; | |
654 | u32 bound = LDELAY; | |
655 | ||
656 | while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) || | |
657 | (idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) { | |
658 | ||
659 | clkctrl = readl(clkctrl_addr); | |
660 | idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >> | |
661 | MODULE_CLKCTRL_IDLEST_SHIFT; | |
662 | if (--bound == 0) { | |
01b753ff | 663 | printf("Clock enable failed for 0x%x idlest 0x%x\n", |
3776801d A |
664 | clkctrl_addr, clkctrl); |
665 | return; | |
666 | } | |
667 | } | |
668 | } | |
669 | ||
01b753ff | 670 | static inline void enable_clock_module(u32 const clkctrl_addr, u32 enable_mode, |
3776801d A |
671 | u32 wait_for_enable) |
672 | { | |
673 | clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK, | |
674 | enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT); | |
01b753ff | 675 | debug("Enable clock module - %x\n", clkctrl_addr); |
3776801d A |
676 | if (wait_for_enable) |
677 | wait_for_clk_enable(clkctrl_addr); | |
678 | } | |
679 | ||
3776801d A |
680 | void freq_update_core(void) |
681 | { | |
682 | u32 freq_config1 = 0; | |
683 | const struct dpll_params *core_dpll_params; | |
f4010734 | 684 | u32 omap_rev = omap_revision(); |
3776801d | 685 | |
ee9447bf | 686 | core_dpll_params = get_core_dpll_params(*dplls_data); |
3776801d | 687 | /* Put EMIF clock domain in sw wakeup mode */ |
01b753ff | 688 | enable_clock_domain((*prcm)->cm_memif_clkstctrl, |
3776801d | 689 | CD_CLKCTRL_CLKTRCTRL_SW_WKUP); |
01b753ff S |
690 | wait_for_clk_enable((*prcm)->cm_memif_emif_1_clkctrl); |
691 | wait_for_clk_enable((*prcm)->cm_memif_emif_2_clkctrl); | |
3776801d A |
692 | |
693 | freq_config1 = SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK | | |
694 | SHADOW_FREQ_CONFIG1_DLL_RESET_MASK; | |
695 | ||
696 | freq_config1 |= (DPLL_EN_LOCK << SHADOW_FREQ_CONFIG1_DPLL_EN_SHIFT) & | |
697 | SHADOW_FREQ_CONFIG1_DPLL_EN_MASK; | |
698 | ||
699 | freq_config1 |= (core_dpll_params->m2 << | |
700 | SHADOW_FREQ_CONFIG1_M2_DIV_SHIFT) & | |
701 | SHADOW_FREQ_CONFIG1_M2_DIV_MASK; | |
702 | ||
01b753ff | 703 | writel(freq_config1, (*prcm)->cm_shadow_freq_config1); |
3776801d | 704 | if (!wait_on_value(SHADOW_FREQ_CONFIG1_FREQ_UPDATE_MASK, 0, |
01b753ff | 705 | (u32 *) (*prcm)->cm_shadow_freq_config1, LDELAY)) { |
3776801d A |
706 | puts("FREQ UPDATE procedure failed!!"); |
707 | hang(); | |
708 | } | |
709 | ||
f4010734 S |
710 | /* |
711 | * Putting EMIF in HW_AUTO is seen to be causing issues with | |
a8f408a8 | 712 | * EMIF clocks and the master DLL. Keep EMIF in SW_WKUP |
f4010734 S |
713 | * in OMAP5430 ES1.0 silicon |
714 | */ | |
715 | if (omap_rev != OMAP5430_ES1_0) { | |
716 | /* Put EMIF clock domain back in hw auto mode */ | |
01b753ff | 717 | enable_clock_domain((*prcm)->cm_memif_clkstctrl, |
f4010734 | 718 | CD_CLKCTRL_CLKTRCTRL_HW_AUTO); |
01b753ff S |
719 | wait_for_clk_enable((*prcm)->cm_memif_emif_1_clkctrl); |
720 | wait_for_clk_enable((*prcm)->cm_memif_emif_2_clkctrl); | |
f4010734 | 721 | } |
3776801d A |
722 | } |
723 | ||
01b753ff | 724 | void bypass_dpll(u32 const base) |
3776801d A |
725 | { |
726 | do_bypass_dpll(base); | |
727 | wait_for_bypass(base); | |
728 | } | |
729 | ||
01b753ff | 730 | void lock_dpll(u32 const base) |
3776801d A |
731 | { |
732 | do_lock_dpll(base); | |
733 | wait_for_lock(base); | |
734 | } | |
735 | ||
bcae7211 A |
736 | void setup_clocks_for_console(void) |
737 | { | |
738 | /* Do not add any spl_debug prints in this function */ | |
01b753ff | 739 | clrsetbits_le32((*prcm)->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, |
bcae7211 A |
740 | CD_CLKCTRL_CLKTRCTRL_SW_WKUP << |
741 | CD_CLKCTRL_CLKTRCTRL_SHIFT); | |
742 | ||
743 | /* Enable all UARTs - console will be on one of them */ | |
01b753ff | 744 | clrsetbits_le32((*prcm)->cm_l4per_uart1_clkctrl, |
bcae7211 A |
745 | MODULE_CLKCTRL_MODULEMODE_MASK, |
746 | MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << | |
747 | MODULE_CLKCTRL_MODULEMODE_SHIFT); | |
748 | ||
01b753ff | 749 | clrsetbits_le32((*prcm)->cm_l4per_uart2_clkctrl, |
bcae7211 A |
750 | MODULE_CLKCTRL_MODULEMODE_MASK, |
751 | MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << | |
752 | MODULE_CLKCTRL_MODULEMODE_SHIFT); | |
753 | ||
01b753ff | 754 | clrsetbits_le32((*prcm)->cm_l4per_uart3_clkctrl, |
bcae7211 A |
755 | MODULE_CLKCTRL_MODULEMODE_MASK, |
756 | MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << | |
757 | MODULE_CLKCTRL_MODULEMODE_SHIFT); | |
758 | ||
a8f408a8 | 759 | clrsetbits_le32((*prcm)->cm_l4per_uart4_clkctrl, |
bcae7211 A |
760 | MODULE_CLKCTRL_MODULEMODE_MASK, |
761 | MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN << | |
762 | MODULE_CLKCTRL_MODULEMODE_SHIFT); | |
763 | ||
01b753ff | 764 | clrsetbits_le32((*prcm)->cm_l4per_clkstctrl, CD_CLKCTRL_CLKTRCTRL_MASK, |
bcae7211 A |
765 | CD_CLKCTRL_CLKTRCTRL_HW_AUTO << |
766 | CD_CLKCTRL_CLKTRCTRL_SHIFT); | |
767 | } | |
768 | ||
01b753ff S |
769 | void do_enable_clocks(u32 const *clk_domains, |
770 | u32 const *clk_modules_hw_auto, | |
771 | u32 const *clk_modules_explicit_en, | |
2e5ba489 S |
772 | u8 wait_for_enable) |
773 | { | |
774 | u32 i, max = 100; | |
775 | ||
776 | /* Put the clock domains in SW_WKUP mode */ | |
777 | for (i = 0; (i < max) && clk_domains[i]; i++) { | |
778 | enable_clock_domain(clk_domains[i], | |
779 | CD_CLKCTRL_CLKTRCTRL_SW_WKUP); | |
780 | } | |
781 | ||
782 | /* Clock modules that need to be put in HW_AUTO */ | |
783 | for (i = 0; (i < max) && clk_modules_hw_auto[i]; i++) { | |
784 | enable_clock_module(clk_modules_hw_auto[i], | |
785 | MODULE_CLKCTRL_MODULEMODE_HW_AUTO, | |
786 | wait_for_enable); | |
787 | }; | |
788 | ||
789 | /* Clock modules that need to be put in SW_EXPLICIT_EN mode */ | |
790 | for (i = 0; (i < max) && clk_modules_explicit_en[i]; i++) { | |
791 | enable_clock_module(clk_modules_explicit_en[i], | |
792 | MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN, | |
793 | wait_for_enable); | |
794 | }; | |
795 | ||
796 | /* Put the clock domains in HW_AUTO mode now */ | |
797 | for (i = 0; (i < max) && clk_domains[i]; i++) { | |
798 | enable_clock_domain(clk_domains[i], | |
799 | CD_CLKCTRL_CLKTRCTRL_HW_AUTO); | |
800 | } | |
801 | } | |
802 | ||
3776801d A |
803 | void prcm_init(void) |
804 | { | |
508a58fa | 805 | switch (omap_hw_init_context()) { |
3776801d A |
806 | case OMAP_INIT_CONTEXT_SPL: |
807 | case OMAP_INIT_CONTEXT_UBOOT_FROM_NOR: | |
808 | case OMAP_INIT_CONTEXT_UBOOT_AFTER_CH: | |
25223a68 | 809 | enable_basic_clocks(); |
3332b244 | 810 | timer_init(); |
3fcdd4a5 | 811 | scale_vcores(*omap_vcores); |
3776801d | 812 | setup_dplls(); |
0b1b60c7 | 813 | setup_warmreset_time(); |
3776801d A |
814 | break; |
815 | default: | |
816 | break; | |
817 | } | |
78f455c0 S |
818 | |
819 | if (OMAP_INIT_CONTEXT_SPL != omap_hw_init_context()) | |
820 | enable_basic_uboot_clocks(); | |
3776801d | 821 | } |
63fc0c77 LV |
822 | |
823 | void gpi2c_init(void) | |
824 | { | |
825 | static int gpi2c = 1; | |
826 | ||
827 | if (gpi2c) { | |
6789e84e HS |
828 | i2c_init(CONFIG_SYS_OMAP24_I2C_SPEED, |
829 | CONFIG_SYS_OMAP24_I2C_SLAVE); | |
63fc0c77 LV |
830 | gpi2c = 0; |
831 | } | |
832 | } |