diff options
Diffstat (limited to 'recipes-bsp/u-boot/u-boot-2012.04.01/0017-mx5-Add-clock-config-interface.patch')
-rw-r--r-- | recipes-bsp/u-boot/u-boot-2012.04.01/0017-mx5-Add-clock-config-interface.patch | 574 |
1 files changed, 574 insertions, 0 deletions
diff --git a/recipes-bsp/u-boot/u-boot-2012.04.01/0017-mx5-Add-clock-config-interface.patch b/recipes-bsp/u-boot/u-boot-2012.04.01/0017-mx5-Add-clock-config-interface.patch new file mode 100644 index 0000000..a995502 --- /dev/null +++ b/recipes-bsp/u-boot/u-boot-2012.04.01/0017-mx5-Add-clock-config-interface.patch | |||
@@ -0,0 +1,574 @@ | |||
1 | From a835391f8dddc9ca51c880e5328979577cb0685d Mon Sep 17 00:00:00 2001 | ||
2 | From: Fabio Estevam <festevam@gmail.com> | ||
3 | Date: Mon, 30 Apr 2012 08:12:02 +0000 | ||
4 | Subject: [PATCH 17/56] mx5: Add clock config interface | ||
5 | |||
6 | mx5: Add clock config interface | ||
7 | |||
8 | Add clock config interface support, so that we | ||
9 | can configure CPU or DDR clock in the later init | ||
10 | |||
11 | Signed-off-by: Jason Liu <jason.hui@linaro.org> | ||
12 | Signed-off-by: Eric Miao <eric.miao@linaro.org> | ||
13 | Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com> | ||
14 | --- | ||
15 | arch/arm/cpu/armv7/mx5/clock.c | 448 +++++++++++++++++++++++++++++- | ||
16 | arch/arm/include/asm/arch-mx5/clock.h | 5 +- | ||
17 | arch/arm/include/asm/arch-mx5/crm_regs.h | 6 + | ||
18 | 3 files changed, 454 insertions(+), 5 deletions(-) | ||
19 | |||
20 | diff --git a/arch/arm/cpu/armv7/mx5/clock.c b/arch/arm/cpu/armv7/mx5/clock.c | ||
21 | index 903e207..fc2406b 100644 | ||
22 | --- a/arch/arm/cpu/armv7/mx5/clock.c | ||
23 | +++ b/arch/arm/cpu/armv7/mx5/clock.c | ||
24 | @@ -49,6 +49,42 @@ struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = { | ||
25 | #endif | ||
26 | }; | ||
27 | |||
28 | +#define AHB_CLK_ROOT 133333333 | ||
29 | +#define SZ_DEC_1M 1000000 | ||
30 | +#define PLL_PD_MAX 16 /* Actual pd+1 */ | ||
31 | +#define PLL_MFI_MAX 15 | ||
32 | +#define PLL_MFI_MIN 5 | ||
33 | +#define ARM_DIV_MAX 8 | ||
34 | +#define IPG_DIV_MAX 4 | ||
35 | +#define AHB_DIV_MAX 8 | ||
36 | +#define EMI_DIV_MAX 8 | ||
37 | +#define NFC_DIV_MAX 8 | ||
38 | + | ||
39 | +#define MX5_CBCMR 0x00015154 | ||
40 | +#define MX5_CBCDR 0x02888945 | ||
41 | + | ||
42 | +struct fixed_pll_mfd { | ||
43 | + u32 ref_clk_hz; | ||
44 | + u32 mfd; | ||
45 | +}; | ||
46 | + | ||
47 | +const struct fixed_pll_mfd fixed_mfd[] = { | ||
48 | + {CONFIG_SYS_MX5_HCLK, 24 * 16}, | ||
49 | +}; | ||
50 | + | ||
51 | +struct pll_param { | ||
52 | + u32 pd; | ||
53 | + u32 mfi; | ||
54 | + u32 mfn; | ||
55 | + u32 mfd; | ||
56 | +}; | ||
57 | + | ||
58 | +#define PLL_FREQ_MAX(ref_clk) (4 * (ref_clk) * PLL_MFI_MAX) | ||
59 | +#define PLL_FREQ_MIN(ref_clk) \ | ||
60 | + ((2 * (ref_clk) * (PLL_MFI_MIN - 1)) / PLL_PD_MAX) | ||
61 | +#define MAX_DDR_CLK 420000000 | ||
62 | +#define NFC_CLK_MAX 34000000 | ||
63 | + | ||
64 | struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE; | ||
65 | |||
66 | void set_usboh3_clk(void) | ||
67 | @@ -291,7 +327,7 @@ static u32 get_uart_clk(void) | ||
68 | /* | ||
69 | * This function returns the low power audio clock. | ||
70 | */ | ||
71 | -u32 get_lp_apm(void) | ||
72 | +static u32 get_lp_apm(void) | ||
73 | { | ||
74 | u32 ret_val = 0; | ||
75 | u32 ccsr = __raw_readl(&mxc_ccm->ccsr); | ||
76 | @@ -307,7 +343,7 @@ u32 get_lp_apm(void) | ||
77 | /* | ||
78 | * get cspi clock rate. | ||
79 | */ | ||
80 | -u32 imx_get_cspiclk(void) | ||
81 | +static u32 imx_get_cspiclk(void) | ||
82 | { | ||
83 | u32 ret_val = 0, pdf, pre_pdf, clk_sel; | ||
84 | u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1); | ||
85 | @@ -344,8 +380,77 @@ u32 imx_get_cspiclk(void) | ||
86 | return ret_val; | ||
87 | } | ||
88 | |||
89 | +static u32 get_axi_a_clk(void) | ||
90 | +{ | ||
91 | + u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr); | ||
92 | + u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_A_PODF_MASK) \ | ||
93 | + >> MXC_CCM_CBCDR_AXI_A_PODF_OFFSET; | ||
94 | + | ||
95 | + return get_periph_clk() / (pdf + 1); | ||
96 | +} | ||
97 | + | ||
98 | +static u32 get_axi_b_clk(void) | ||
99 | +{ | ||
100 | + u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr); | ||
101 | + u32 pdf = (cbcdr & MXC_CCM_CBCDR_AXI_B_PODF_MASK) \ | ||
102 | + >> MXC_CCM_CBCDR_AXI_B_PODF_OFFSET; | ||
103 | + | ||
104 | + return get_periph_clk() / (pdf + 1); | ||
105 | +} | ||
106 | + | ||
107 | +static u32 get_emi_slow_clk(void) | ||
108 | +{ | ||
109 | + u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr); | ||
110 | + u32 emi_clk_sel = cbcdr & MXC_CCM_CBCDR_EMI_CLK_SEL; | ||
111 | + u32 pdf = (cbcdr & MXC_CCM_CBCDR_EMI_PODF_MASK) \ | ||
112 | + >> MXC_CCM_CBCDR_EMI_PODF_OFFSET; | ||
113 | + | ||
114 | + if (emi_clk_sel) | ||
115 | + return get_ahb_clk() / (pdf + 1); | ||
116 | + | ||
117 | + return get_periph_clk() / (pdf + 1); | ||
118 | +} | ||
119 | + | ||
120 | +static u32 get_ddr_clk(void) | ||
121 | +{ | ||
122 | + u32 ret_val = 0; | ||
123 | + u32 cbcmr = __raw_readl(&mxc_ccm->cbcmr); | ||
124 | + u32 ddr_clk_sel = (cbcmr & MXC_CCM_CBCMR_DDR_CLK_SEL_MASK) \ | ||
125 | + >> MXC_CCM_CBCMR_DDR_CLK_SEL_OFFSET; | ||
126 | +#ifdef CONFIG_MX51 | ||
127 | + u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr); | ||
128 | + if (cbcdr & MXC_CCM_CBCDR_DDR_HIFREQ_SEL) { | ||
129 | + u32 ddr_clk_podf = (cbcdr & MXC_CCM_CBCDR_DDR_PODF_MASK) >> \ | ||
130 | + MXC_CCM_CBCDR_DDR_PODF_OFFSET; | ||
131 | + | ||
132 | + ret_val = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK); | ||
133 | + ret_val /= ddr_clk_podf + 1; | ||
134 | + | ||
135 | + return ret_val; | ||
136 | + } | ||
137 | +#endif | ||
138 | + switch (ddr_clk_sel) { | ||
139 | + case 0: | ||
140 | + ret_val = get_axi_a_clk(); | ||
141 | + break; | ||
142 | + case 1: | ||
143 | + ret_val = get_axi_b_clk(); | ||
144 | + break; | ||
145 | + case 2: | ||
146 | + ret_val = get_emi_slow_clk(); | ||
147 | + break; | ||
148 | + case 3: | ||
149 | + ret_val = get_ahb_clk(); | ||
150 | + break; | ||
151 | + default: | ||
152 | + break; | ||
153 | + } | ||
154 | + | ||
155 | + return ret_val; | ||
156 | +} | ||
157 | + | ||
158 | /* | ||
159 | - * The API of get mxc clockes. | ||
160 | + * The API of get mxc clocks. | ||
161 | */ | ||
162 | unsigned int mxc_get_clock(enum mxc_clock clk) | ||
163 | { | ||
164 | @@ -367,10 +472,12 @@ unsigned int mxc_get_clock(enum mxc_clock clk) | ||
165 | CONFIG_SYS_MX5_HCLK); | ||
166 | case MXC_SATA_CLK: | ||
167 | return get_ahb_clk(); | ||
168 | + case MXC_DDR_CLK: | ||
169 | + return get_ddr_clk(); | ||
170 | default: | ||
171 | break; | ||
172 | } | ||
173 | - return -1; | ||
174 | + return -EINVAL; | ||
175 | } | ||
176 | |||
177 | u32 imx_get_uartclk(void) | ||
178 | @@ -384,6 +491,338 @@ u32 imx_get_fecclk(void) | ||
179 | return mxc_get_clock(MXC_IPG_CLK); | ||
180 | } | ||
181 | |||
182 | +static int gcd(int m, int n) | ||
183 | +{ | ||
184 | + int t; | ||
185 | + while (m > 0) { | ||
186 | + if (n > m) { | ||
187 | + t = m; | ||
188 | + m = n; | ||
189 | + n = t; | ||
190 | + } /* swap */ | ||
191 | + m -= n; | ||
192 | + } | ||
193 | + return n; | ||
194 | +} | ||
195 | + | ||
196 | +/* | ||
197 | + * This is to calculate various parameters based on reference clock and | ||
198 | + * targeted clock based on the equation: | ||
199 | + * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1) | ||
200 | + * This calculation is based on a fixed MFD value for simplicity. | ||
201 | + */ | ||
202 | +static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll) | ||
203 | +{ | ||
204 | + u64 pd, mfi = 1, mfn, mfd, t1; | ||
205 | + u32 n_target = target; | ||
206 | + u32 n_ref = ref, i; | ||
207 | + | ||
208 | + /* | ||
209 | + * Make sure targeted freq is in the valid range. | ||
210 | + * Otherwise the following calculation might be wrong!!! | ||
211 | + */ | ||
212 | + if (n_target < PLL_FREQ_MIN(ref) || | ||
213 | + n_target > PLL_FREQ_MAX(ref)) { | ||
214 | + printf("Targeted peripheral clock should be" | ||
215 | + "within [%d - %d]\n", | ||
216 | + PLL_FREQ_MIN(ref) / SZ_DEC_1M, | ||
217 | + PLL_FREQ_MAX(ref) / SZ_DEC_1M); | ||
218 | + return -EINVAL; | ||
219 | + } | ||
220 | + | ||
221 | + for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) { | ||
222 | + if (fixed_mfd[i].ref_clk_hz == ref) { | ||
223 | + mfd = fixed_mfd[i].mfd; | ||
224 | + break; | ||
225 | + } | ||
226 | + } | ||
227 | + | ||
228 | + if (i == ARRAY_SIZE(fixed_mfd)) | ||
229 | + return -EINVAL; | ||
230 | + | ||
231 | + /* Use n_target and n_ref to avoid overflow */ | ||
232 | + for (pd = 1; pd <= PLL_PD_MAX; pd++) { | ||
233 | + t1 = n_target * pd; | ||
234 | + do_div(t1, (4 * n_ref)); | ||
235 | + mfi = t1; | ||
236 | + if (mfi > PLL_MFI_MAX) | ||
237 | + return -EINVAL; | ||
238 | + else if (mfi < 5) | ||
239 | + continue; | ||
240 | + break; | ||
241 | + } | ||
242 | + /* | ||
243 | + * Now got pd and mfi already | ||
244 | + * | ||
245 | + * mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref; | ||
246 | + */ | ||
247 | + t1 = n_target * pd; | ||
248 | + do_div(t1, 4); | ||
249 | + t1 -= n_ref * mfi; | ||
250 | + t1 *= mfd; | ||
251 | + do_div(t1, n_ref); | ||
252 | + mfn = t1; | ||
253 | + debug("ref=%d, target=%d, pd=%d," "mfi=%d,mfn=%d, mfd=%d\n", | ||
254 | + ref, n_target, (u32)pd, (u32)mfi, (u32)mfn, (u32)mfd); | ||
255 | + i = 1; | ||
256 | + if (mfn != 0) | ||
257 | + i = gcd(mfd, mfn); | ||
258 | + pll->pd = (u32)pd; | ||
259 | + pll->mfi = (u32)mfi; | ||
260 | + do_div(mfn, i); | ||
261 | + pll->mfn = (u32)mfn; | ||
262 | + do_div(mfd, i); | ||
263 | + pll->mfd = (u32)mfd; | ||
264 | + | ||
265 | + return 0; | ||
266 | +} | ||
267 | + | ||
268 | +#define calc_div(tgt_clk, src_clk, limit) ({ \ | ||
269 | + u32 v = 0; \ | ||
270 | + if (((src_clk) % (tgt_clk)) <= 100) \ | ||
271 | + v = (src_clk) / (tgt_clk); \ | ||
272 | + else \ | ||
273 | + v = ((src_clk) / (tgt_clk)) + 1;\ | ||
274 | + if (v > limit) \ | ||
275 | + v = limit; \ | ||
276 | + (v - 1); \ | ||
277 | + }) | ||
278 | + | ||
279 | +#define CHANGE_PLL_SETTINGS(pll, pd, fi, fn, fd) \ | ||
280 | + { \ | ||
281 | + __raw_writel(0x1232, &pll->ctrl); \ | ||
282 | + __raw_writel(0x2, &pll->config); \ | ||
283 | + __raw_writel((((pd) - 1) << 0) | ((fi) << 4), \ | ||
284 | + &pll->op); \ | ||
285 | + __raw_writel(fn, &(pll->mfn)); \ | ||
286 | + __raw_writel((fd) - 1, &pll->mfd); \ | ||
287 | + __raw_writel((((pd) - 1) << 0) | ((fi) << 4), \ | ||
288 | + &pll->hfs_op); \ | ||
289 | + __raw_writel(fn, &pll->hfs_mfn); \ | ||
290 | + __raw_writel((fd) - 1, &pll->hfs_mfd); \ | ||
291 | + __raw_writel(0x1232, &pll->ctrl); \ | ||
292 | + while (!__raw_readl(&pll->ctrl) & 0x1) \ | ||
293 | + ;\ | ||
294 | + } | ||
295 | + | ||
296 | +static int config_pll_clk(enum pll_clocks index, struct pll_param *pll_param) | ||
297 | +{ | ||
298 | + u32 ccsr = __raw_readl(&mxc_ccm->ccsr); | ||
299 | + struct mxc_pll_reg *pll = mxc_plls[index]; | ||
300 | + | ||
301 | + switch (index) { | ||
302 | + case PLL1_CLOCK: | ||
303 | + /* Switch ARM to PLL2 clock */ | ||
304 | + __raw_writel(ccsr | 0x4, &mxc_ccm->ccsr); | ||
305 | + CHANGE_PLL_SETTINGS(pll, pll_param->pd, | ||
306 | + pll_param->mfi, pll_param->mfn, | ||
307 | + pll_param->mfd); | ||
308 | + /* Switch back */ | ||
309 | + __raw_writel(ccsr & ~0x4, &mxc_ccm->ccsr); | ||
310 | + break; | ||
311 | + case PLL2_CLOCK: | ||
312 | + /* Switch to pll2 bypass clock */ | ||
313 | + __raw_writel(ccsr | 0x2, &mxc_ccm->ccsr); | ||
314 | + CHANGE_PLL_SETTINGS(pll, pll_param->pd, | ||
315 | + pll_param->mfi, pll_param->mfn, | ||
316 | + pll_param->mfd); | ||
317 | + /* Switch back */ | ||
318 | + __raw_writel(ccsr & ~0x2, &mxc_ccm->ccsr); | ||
319 | + break; | ||
320 | + case PLL3_CLOCK: | ||
321 | + /* Switch to pll3 bypass clock */ | ||
322 | + __raw_writel(ccsr | 0x1, &mxc_ccm->ccsr); | ||
323 | + CHANGE_PLL_SETTINGS(pll, pll_param->pd, | ||
324 | + pll_param->mfi, pll_param->mfn, | ||
325 | + pll_param->mfd); | ||
326 | + /* Switch back */ | ||
327 | + __raw_writel(ccsr & ~0x1, &mxc_ccm->ccsr); | ||
328 | + break; | ||
329 | + case PLL4_CLOCK: | ||
330 | + /* Switch to pll4 bypass clock */ | ||
331 | + __raw_writel(ccsr | 0x20, &mxc_ccm->ccsr); | ||
332 | + CHANGE_PLL_SETTINGS(pll, pll_param->pd, | ||
333 | + pll_param->mfi, pll_param->mfn, | ||
334 | + pll_param->mfd); | ||
335 | + /* Switch back */ | ||
336 | + __raw_writel(ccsr & ~0x20, &mxc_ccm->ccsr); | ||
337 | + break; | ||
338 | + default: | ||
339 | + return -EINVAL; | ||
340 | + } | ||
341 | + | ||
342 | + return 0; | ||
343 | +} | ||
344 | + | ||
345 | +/* Config CPU clock */ | ||
346 | +static int config_core_clk(u32 ref, u32 freq) | ||
347 | +{ | ||
348 | + int ret = 0; | ||
349 | + struct pll_param pll_param; | ||
350 | + | ||
351 | + memset(&pll_param, 0, sizeof(struct pll_param)); | ||
352 | + | ||
353 | + /* The case that periph uses PLL1 is not considered here */ | ||
354 | + ret = calc_pll_params(ref, freq, &pll_param); | ||
355 | + if (ret != 0) { | ||
356 | + printf("Error:Can't find pll parameters: %d\n", ret); | ||
357 | + return ret; | ||
358 | + } | ||
359 | + | ||
360 | + return config_pll_clk(PLL1_CLOCK, &pll_param); | ||
361 | +} | ||
362 | + | ||
363 | +static int config_nfc_clk(u32 nfc_clk) | ||
364 | +{ | ||
365 | + u32 reg; | ||
366 | + u32 parent_rate = get_emi_slow_clk(); | ||
367 | + u32 div = parent_rate / nfc_clk; | ||
368 | + | ||
369 | + if (nfc_clk <= 0) | ||
370 | + return -EINVAL; | ||
371 | + if (div == 0) | ||
372 | + div++; | ||
373 | + if (parent_rate / div > NFC_CLK_MAX) | ||
374 | + div++; | ||
375 | + reg = __raw_readl(&mxc_ccm->cbcdr); | ||
376 | + reg &= ~MXC_CCM_CBCDR_NFC_PODF_MASK; | ||
377 | + reg |= (div - 1) << MXC_CCM_CBCDR_NFC_PODF_OFFSET; | ||
378 | + __raw_writel(reg, &mxc_ccm->cbcdr); | ||
379 | + while (__raw_readl(&mxc_ccm->cdhipr) != 0) | ||
380 | + ; | ||
381 | + return 0; | ||
382 | +} | ||
383 | + | ||
384 | +/* Config main_bus_clock for periphs */ | ||
385 | +static int config_periph_clk(u32 ref, u32 freq) | ||
386 | +{ | ||
387 | + int ret = 0; | ||
388 | + struct pll_param pll_param; | ||
389 | + | ||
390 | + memset(&pll_param, 0, sizeof(struct pll_param)); | ||
391 | + | ||
392 | + if (__raw_readl(&mxc_ccm->cbcdr) & MXC_CCM_CBCDR_PERIPH_CLK_SEL) { | ||
393 | + ret = calc_pll_params(ref, freq, &pll_param); | ||
394 | + if (ret != 0) { | ||
395 | + printf("Error:Can't find pll parameters: %d\n", | ||
396 | + ret); | ||
397 | + return ret; | ||
398 | + } | ||
399 | + switch ((__raw_readl(&mxc_ccm->cbcmr) & \ | ||
400 | + MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >> \ | ||
401 | + MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) { | ||
402 | + case 0: | ||
403 | + return config_pll_clk(PLL1_CLOCK, &pll_param); | ||
404 | + break; | ||
405 | + case 1: | ||
406 | + return config_pll_clk(PLL3_CLOCK, &pll_param); | ||
407 | + break; | ||
408 | + default: | ||
409 | + return -EINVAL; | ||
410 | + } | ||
411 | + } | ||
412 | + | ||
413 | + return 0; | ||
414 | +} | ||
415 | + | ||
416 | +static int config_ddr_clk(u32 emi_clk) | ||
417 | +{ | ||
418 | + u32 clk_src; | ||
419 | + s32 shift = 0, clk_sel, div = 1; | ||
420 | + u32 cbcmr = __raw_readl(&mxc_ccm->cbcmr); | ||
421 | + u32 cbcdr = __raw_readl(&mxc_ccm->cbcdr); | ||
422 | + | ||
423 | + if (emi_clk > MAX_DDR_CLK) { | ||
424 | + printf("Warning:DDR clock should not exceed %d MHz\n", | ||
425 | + MAX_DDR_CLK / SZ_DEC_1M); | ||
426 | + emi_clk = MAX_DDR_CLK; | ||
427 | + } | ||
428 | + | ||
429 | + clk_src = get_periph_clk(); | ||
430 | + /* Find DDR clock input */ | ||
431 | + clk_sel = (cbcmr >> 10) & 0x3; | ||
432 | + switch (clk_sel) { | ||
433 | + case 0: | ||
434 | + shift = 16; | ||
435 | + break; | ||
436 | + case 1: | ||
437 | + shift = 19; | ||
438 | + break; | ||
439 | + case 2: | ||
440 | + shift = 22; | ||
441 | + break; | ||
442 | + case 3: | ||
443 | + shift = 10; | ||
444 | + break; | ||
445 | + default: | ||
446 | + return -EINVAL; | ||
447 | + } | ||
448 | + | ||
449 | + if ((clk_src % emi_clk) < 10000000) | ||
450 | + div = clk_src / emi_clk; | ||
451 | + else | ||
452 | + div = (clk_src / emi_clk) + 1; | ||
453 | + if (div > 8) | ||
454 | + div = 8; | ||
455 | + | ||
456 | + cbcdr = cbcdr & ~(0x7 << shift); | ||
457 | + cbcdr |= ((div - 1) << shift); | ||
458 | + __raw_writel(cbcdr, &mxc_ccm->cbcdr); | ||
459 | + while (__raw_readl(&mxc_ccm->cdhipr) != 0) | ||
460 | + ; | ||
461 | + __raw_writel(0x0, &mxc_ccm->ccdr); | ||
462 | + | ||
463 | + return 0; | ||
464 | +} | ||
465 | + | ||
466 | +/* | ||
467 | + * This function assumes the expected core clock has to be changed by | ||
468 | + * modifying the PLL. This is NOT true always but for most of the times, | ||
469 | + * it is. So it assumes the PLL output freq is the same as the expected | ||
470 | + * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN. | ||
471 | + * In the latter case, it will try to increase the presc value until | ||
472 | + * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to | ||
473 | + * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based | ||
474 | + * on the targeted PLL and reference input clock to the PLL. Lastly, | ||
475 | + * it sets the register based on these values along with the dividers. | ||
476 | + * Note 1) There is no value checking for the passed-in divider values | ||
477 | + * so the caller has to make sure those values are sensible. | ||
478 | + * 2) Also adjust the NFC divider such that the NFC clock doesn't | ||
479 | + * exceed NFC_CLK_MAX. | ||
480 | + * 3) IPU HSP clock is independent of AHB clock. Even it can go up to | ||
481 | + * 177MHz for higher voltage, this function fixes the max to 133MHz. | ||
482 | + * 4) This function should not have allowed diag_printf() calls since | ||
483 | + * the serial driver has been stoped. But leave then here to allow | ||
484 | + * easy debugging by NOT calling the cyg_hal_plf_serial_stop(). | ||
485 | + */ | ||
486 | +int mxc_set_clock(u32 ref, u32 freq, enum mxc_clock clk) | ||
487 | +{ | ||
488 | + freq *= SZ_DEC_1M; | ||
489 | + | ||
490 | + switch (clk) { | ||
491 | + case MXC_ARM_CLK: | ||
492 | + if (config_core_clk(ref, freq)) | ||
493 | + return -EINVAL; | ||
494 | + break; | ||
495 | + case MXC_PERIPH_CLK: | ||
496 | + if (config_periph_clk(ref, freq)) | ||
497 | + return -EINVAL; | ||
498 | + break; | ||
499 | + case MXC_DDR_CLK: | ||
500 | + if (config_ddr_clk(freq)) | ||
501 | + return -EINVAL; | ||
502 | + break; | ||
503 | + case MXC_NFC_CLK: | ||
504 | + if (config_nfc_clk(freq)) | ||
505 | + return -EINVAL; | ||
506 | + break; | ||
507 | + default: | ||
508 | + printf("Warning:Unsupported or invalid clock type\n"); | ||
509 | + } | ||
510 | + | ||
511 | + return 0; | ||
512 | +} | ||
513 | + | ||
514 | #ifdef CONFIG_MX53 | ||
515 | /* | ||
516 | * The clock for the external interface can be set to use internal clock | ||
517 | @@ -430,6 +869,7 @@ int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) | ||
518 | printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000); | ||
519 | printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000); | ||
520 | printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000); | ||
521 | + printf("DDR %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | diff --git a/arch/arm/include/asm/arch-mx5/clock.h b/arch/arm/include/asm/arch-mx5/clock.h | ||
526 | index e822809..35ee815 100644 | ||
527 | --- a/arch/arm/include/asm/arch-mx5/clock.h | ||
528 | +++ b/arch/arm/include/asm/arch-mx5/clock.h | ||
529 | @@ -33,6 +33,9 @@ enum mxc_clock { | ||
530 | MXC_CSPI_CLK, | ||
531 | MXC_FEC_CLK, | ||
532 | MXC_SATA_CLK, | ||
533 | + MXC_DDR_CLK, | ||
534 | + MXC_NFC_CLK, | ||
535 | + MXC_PERIPH_CLK, | ||
536 | }; | ||
537 | |||
538 | unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref); | ||
539 | @@ -40,7 +43,7 @@ unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref); | ||
540 | u32 imx_get_uartclk(void); | ||
541 | u32 imx_get_fecclk(void); | ||
542 | unsigned int mxc_get_clock(enum mxc_clock clk); | ||
543 | - | ||
544 | +int mxc_set_clock(u32 ref, u32 freq, u32 clk_type); | ||
545 | void set_usb_phy2_clk(void); | ||
546 | void enable_usb_phy2_clk(unsigned char enable); | ||
547 | void set_usboh3_clk(void); | ||
548 | diff --git a/arch/arm/include/asm/arch-mx5/crm_regs.h b/arch/arm/include/asm/arch-mx5/crm_regs.h | ||
549 | index bdeafbc..4e0fc1b 100644 | ||
550 | --- a/arch/arm/include/asm/arch-mx5/crm_regs.h | ||
551 | +++ b/arch/arm/include/asm/arch-mx5/crm_regs.h | ||
552 | @@ -76,6 +76,9 @@ struct mxc_ccm_reg { | ||
553 | u32 CCGR4; | ||
554 | u32 CCGR5; | ||
555 | u32 CCGR6; /* 0x0080 */ | ||
556 | +#ifdef CONFIG_MX53 | ||
557 | + u32 CCGR7; /* 0x0084 */ | ||
558 | +#endif | ||
559 | u32 cmeor; | ||
560 | }; | ||
561 | |||
562 | @@ -84,6 +87,9 @@ struct mxc_ccm_reg { | ||
563 | #define MXC_CCM_CACRR_ARM_PODF_MASK 0x7 | ||
564 | |||
565 | /* Define the bits in register CBCDR */ | ||
566 | +#define MXC_CCM_CBCDR_DDR_HIFREQ_SEL (0x1 << 30) | ||
567 | +#define MXC_CCM_CBCDR_DDR_PODF_MASK (0x7 << 27) | ||
568 | +#define MXC_CCM_CBCDR_DDR_PODF_OFFSET 27 | ||
569 | #define MXC_CCM_CBCDR_EMI_CLK_SEL (0x1 << 26) | ||
570 | #define MXC_CCM_CBCDR_PERIPH_CLK_SEL (0x1 << 25) | ||
571 | #define MXC_CCM_CBCDR_EMI_PODF_OFFSET 22 | ||
572 | -- | ||
573 | 1.7.10 | ||
574 | |||