1 From 9667c8061fcfe407b2fa2055b09e0509dc7cc041 Mon Sep 17 00:00:00 2001
2 From: Terry Lv <r65388@freescale.com>
3 Date: Fri, 7 May 2010 21:19:41 +0800
4 Subject: [PATCH] ENGR00123278: Support clock operation functions
6 Support clock operation functions.
8 Signed-off-by: Terry Lv <r65388@freescale.com>
10 board/freescale/mx53_evk/flash_header.S | 2 +-
12 common/cmd_clk.c | 76 +++++++
13 common/cmd_mmc.c | 2 +-
14 cpu/arm_cortexa8/mx51/cmd_fuse.c | 2 +-
15 cpu/arm_cortexa8/mx53/generic.c | 334 ++++++++++++++++++++++++++++++-
16 include/asm-arm/clock.h | 42 ++++
17 include/configs/mx53_arm2.h | 3 +
18 include/configs/mx53_evk.h | 3 +
19 9 files changed, 461 insertions(+), 4 deletions(-)
21 diff --git a/board/freescale/mx53_evk/flash_header.S b/board/freescale/mx53_evk/flash_header.S
22 index 38497c8..8d23242 100644
23 --- a/board/freescale/mx53_evk/flash_header.S
24 +++ b/board/freescale/mx53_evk/flash_header.S
25 @@ -49,7 +49,7 @@ app_code_csf: .word 0x0
28 boot_data: .word 0x77800000
29 -image_len: .word 256 * 1024
30 +image_len: .word _end - TEXT_BASE
33 #ifdef CONFIG_MX53_EVK
34 diff --git a/common/Makefile b/common/Makefile
35 index 37629a7..3b8ef59 100644
38 @@ -76,6 +76,7 @@ COBJS-$(CONFIG_CMD_BEDBUG) += bedbug.o cmd_bedbug.o
39 COBJS-$(CONFIG_CMD_BMP) += cmd_bmp.o
40 COBJS-$(CONFIG_CMD_BOOTLDR) += cmd_bootldr.o
41 COBJS-$(CONFIG_CMD_CACHE) += cmd_cache.o
42 +COBJS-$(CONFIG_CMD_CLOCK) += cmd_clk.o
43 COBJS-$(CONFIG_CMD_CONSOLE) += cmd_console.o
44 COBJS-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o
45 COBJS-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o
46 diff --git a/common/cmd_clk.c b/common/cmd_clk.c
48 index 0000000..2f81492
50 +++ b/common/cmd_clk.c
53 + * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
56 + * See file CREDITS for list of people who contributed to this
59 + * This program is free software; you can redistribute it and/or
60 + * modify it under the terms of the GNU General Public License as
61 + * published by the Free Software Foundation; either version 2 of
62 + * the License, or (at your option) any later version.
64 + * This program is distributed in the hope that it will be useful,
65 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
66 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
67 + * GNU General Public License for more details.
69 + * You should have received a copy of the GNU General Public License
70 + * along with this program; if not, write to the Free Software
71 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
75 +#include <linux/types.h>
78 +#include <asm/clock.h>
80 +int do_clkops(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
90 + if (strcmp(argv[1], "core") == 0)
92 + else if (strcmp(argv[1], "ddr") == 0)
95 + printf("Unsupported clock type!\n");
98 + freq = simple_strtoul(argv[2], NULL, 10);
99 + if (strcmp(argv[1], "core") == 0)
100 + clk_config(CONFIG_REF_CLK_FREQ, freq, CPU_CLK);
101 + else if (strcmp(argv[1], "ddr") == 0)
102 + clk_config(CONFIG_REF_CLK_FREQ, freq, DDR_CLK);
104 + printf("Unsupported clock type!\n");
108 + printf("Too much parameters.\n");
109 + printf("Usage:\n%s\n", cmdtp->usage);
117 + clk, 3, 1, do_clkops,
118 + "Clock sub system",
119 + "Setup/Display clock\n"
120 + "clk - Display all clocks\n"
121 + "clk core <core clock in MHz> - Setup/Display core clock\n"
122 + "clk ddr <DDR clock in MHz> - Setup/Display DDR clock\n"
124 + "clk - Show various clocks\n"
125 + "clk core 665 - Set core clock to 665MHz\n"
126 + "clk ddr 166 - Set DDR clock to 166MHz");
128 diff --git a/common/cmd_mmc.c b/common/cmd_mmc.c
129 index b8d494b..cd7d16f 100644
130 --- a/common/cmd_mmc.c
131 +++ b/common/cmd_mmc.c
132 @@ -179,7 +179,7 @@ int do_mmcinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
135 U_BOOT_CMD(mmcinfo, 2, 0, do_mmcinfo,
136 - "mmcinfo <dev num>-- display MMC info\n",
137 + "mmcinfo <dev num>-- display MMC info",
141 diff --git a/cpu/arm_cortexa8/mx51/cmd_fuse.c b/cpu/arm_cortexa8/mx51/cmd_fuse.c
142 index 1d32e3a..24eb193 100644
143 --- a/cpu/arm_cortexa8/mx51/cmd_fuse.c
144 +++ b/cpu/arm_cortexa8/mx51/cmd_fuse.c
145 @@ -88,5 +88,5 @@ U_BOOT_CMD(
146 "blow scc <value> - Blow scc value\n"
147 "blow srk <value> - Blow srk value\n"
148 "blow fecmac <0x##:0x##:0x##:0x##:0x##:0x##>"
149 - "- Blow FEC Mac address\n");
150 + "- Blow FEC Mac address");
152 diff --git a/cpu/arm_cortexa8/mx53/generic.c b/cpu/arm_cortexa8/mx53/generic.c
153 index cdd9d7c..812e040 100644
154 --- a/cpu/arm_cortexa8/mx53/generic.c
155 +++ b/cpu/arm_cortexa8/mx53/generic.c
158 #include <asm/arch/mx53.h>
159 #include <asm/errno.h>
161 #include "crm_regs.h"
162 +#ifdef CONFIG_CMD_CLOCK
163 +#include <asm/clock.h>
166 #ifdef CONFIG_ARCH_CPU_INIT
167 #include <asm/cache-cp15.h>
169 @@ -42,6 +47,47 @@ enum pll_sw_clocks {
173 +#ifdef CONFIG_CMD_CLOCK
174 +#define SZ_DEC_1M 1000000
175 +#define PLL_PD_MAX 16 /* Actual pd+1 */
176 +#define PLL_MFI_MAX 15
177 +#define PLL_MFI_MIN 5
178 +#define ARM_DIV_MAX 8
179 +#define IPG_DIV_MAX 4
180 +#define AHB_DIV_MAX 8
181 +#define EMI_DIV_MAX 8
182 +#define NFC_DIV_MAX 8
184 +struct fixed_pll_mfd {
189 +const struct fixed_pll_mfd fixed_mfd[4] = {
190 + {0, 0}, /* reserved */
191 + {0, 0}, /* reserved */
192 + {CONFIG_MX53_HCLK_FREQ, 24 * 16}, /* 384 */
193 + {0, 0}, /* reserved */
203 +#define PLL_FREQ_MAX(_ref_clk_) \
204 + (4 * _ref_clk_ * PLL_MFI_MAX)
205 +#define PLL_FREQ_MIN(_ref_clk_) \
206 + ((2 * _ref_clk_ * (PLL_MFI_MIN - 1)) / PLL_PD_MAX)
207 +#define MAX_DDR_CLK 420000000
208 +#define AHB_CLK_MAX 133333333
209 +#define IPG_CLK_MAX (AHB_CLK_MAX / 2)
210 +#define NFC_CLK_MAX 25000000
211 +#define HSP_CLK_MAX 133333333
214 static u32 __decode_pll(enum pll_clocks pll, u32 infreq)
216 u32 mfi, mfn, mfd, pd;
217 @@ -101,7 +147,7 @@ static u32 __get_ipg_per_clk(void)
218 u32 pred1, pred2, podf;
219 if (__REG(MXC_CCM_CBCMR) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
220 return __get_ipg_clk();
221 - /* Fixme: not handle what about lpm*/
222 + /* Fixme: not handle what about lpm */
223 podf = __REG(MXC_CCM_CBCDR);
224 pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
225 MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
226 @@ -359,6 +405,7 @@ static u32 __get_esdhc4_clk(void)
228 return __get_esdhc1_clk();
231 unsigned int mxc_get_clock(enum mxc_clock clk)
234 @@ -420,6 +467,291 @@ void mxc_dump_clocks(void)
235 printf("esdhc4 clock : %dHz\n", mxc_get_clock(MXC_ESDHC4_CLK));
238 +#ifdef CONFIG_CMD_CLOCK
239 +/* precondition: m>0 and n>0. Let g=gcd(m,n). */
240 +static int gcd(int m, int n)
255 + * This is to calculate various parameters based on reference clock and
256 + * targeted clock based on the equation:
257 + * t_clk = 2*ref_freq*(mfi + mfn/(mfd+1))/(pd+1)
258 + * This calculation is based on a fixed MFD value for simplicity.
260 + * @param ref reference clock freq in Hz
261 + * @param target targeted clock in Hz
262 + * @param pll pll_param structure.
264 + * @return 0 if successful; non-zero otherwise.
266 +static int calc_pll_params(u32 ref, u32 target, struct pll_param *pll)
268 + u64 pd, mfi = 1, mfn, mfd;
269 + u32 n_target = target;
270 + u32 n_ref = ref, i;
274 + * Make sure targeted freq is in the valid range.
275 + * Otherwise the following calculation might be wrong!!!
277 + if (n_target < PLL_FREQ_MIN(ref) ||
278 + n_target > PLL_FREQ_MAX(ref))
281 + for (i = 0; i < ARRAY_SIZE(fixed_mfd); i++) {
282 + if (fixed_mfd[i].ref_clk_hz == ref) {
283 + mfd = fixed_mfd[i].mfd;
288 + if (i == ARRAY_SIZE(fixed_mfd))
291 + /* Use n_target and n_ref to avoid overflow */
292 + for (pd = 1; pd <= PLL_PD_MAX; pd++) {
293 + t1 = n_target * pd;
294 + do_div(t1, (4 * n_ref));
296 + if (mfi > PLL_MFI_MAX)
302 + /* Now got pd and mfi already */
304 + mfn = (((n_target * pd) / 4 - n_ref * mfi) * mfd) / n_ref;
306 + t1 = n_target * pd;
312 +#ifdef CMD_CLOCK_DEBUG
313 + printf("%d: ref=%d, target=%d, pd=%d,"
314 + "mfi=%d,mfn=%d, mfd=%d\n",
315 + __LINE__, ref, (u32)n_target,
316 + (u32)pd, (u32)mfi, (u32)mfn,
323 + pll->mfi = (u32)mfi;
325 + pll->mfn = (u32)mfn;
327 + pll->mfd = (u32)mfd;
332 +int clk_info(u32 clk_type)
334 + switch (clk_type) {
336 + printf("CPU Clock: %dHz\n",
337 + mxc_get_clock(MXC_ARM_CLK));
340 + printf("AHB Clock: %dHz\n",
341 + mxc_get_clock(MXC_AHB_CLK));
344 + printf("IPG Clock: %dHz\n",
345 + mxc_get_clock(MXC_IPG_CLK));
348 + printf("IPG_PER Clock: %dHz\n",
349 + mxc_get_clock(MXC_IPG_PERCLK));
352 + printf("UART Clock: %dHz\n",
353 + mxc_get_clock(MXC_UART_CLK));
356 + printf("CSPI Clock: %dHz\n",
357 + mxc_get_clock(MXC_CSPI_CLK));
360 + printf("DDR Clock: %dHz\n",
361 + mxc_get_clock(MXC_DDR_CLK));
364 + printf("cpu clock: %dHz\n",
365 + mxc_get_clock(MXC_ARM_CLK));
369 + printf("Unsupported clock type! :(\n");
375 +int config_core_clk(struct pll_param *pll_param)
377 + u32 ccsr = readl(CCM_BASE_ADDR + CLKCTL_CCSR);
379 + /* Switch ARM to PLL2 clock */
380 + writel(ccsr | 0x4, CCM_BASE_ADDR + CLKCTL_CCSR);
382 + /* Adjust pll settings */
383 + writel(((pll_param->pd - 1) << 0) | (pll_param->mfi << 4),
384 + PLL1_BASE_ADDR + PLL_DP_OP);
385 + writel(pll_param->mfn,
386 + PLL1_BASE_ADDR + PLL_DP_MFN);
387 + writel(pll_param->mfd - 1,
388 + PLL1_BASE_ADDR + PLL_DP_MFD);
389 + writel(((pll_param->pd - 1) << 0) | (pll_param->mfi << 4),
390 + PLL1_BASE_ADDR + PLL_DP_HFS_OP);
391 + writel(pll_param->mfn,
392 + PLL1_BASE_ADDR + PLL_DP_HFS_MFN);
393 + writel(pll_param->mfd - 1,
394 + PLL1_BASE_ADDR + PLL_DP_HFS_MFD);
396 + /* Switch ARM back to PLL1 */
397 + writel((ccsr & ~0x4), CCM_BASE_ADDR + CLKCTL_CCSR);
402 +int config_ddr_clk(u32 emi_clk)
405 + s32 shift = 0, clk_sel, div = 1;
406 + u32 cbcmr = readl(CCM_BASE_ADDR + CLKCTL_CBCMR);
407 + u32 cbcdr = readl(CCM_BASE_ADDR + CLKCTL_CBCDR);
409 + clk_src = __get_periph_clk();
410 + /* Find DDR clock input */
411 + clk_sel = (cbcmr >> 10) & 0x3;
429 + if ((clk_src % emi_clk) == 0)
430 + div = clk_src / emi_clk;
432 + div = (clk_src / emi_clk) + 1;
436 + cbcdr = cbcdr & ~(0x7 << shift);
437 + cbcdr |= ((div - 1) << shift);
438 + writel(cbcdr, CCM_BASE_ADDR + CLKCTL_CBCDR);
439 + while (readl(CCM_BASE_ADDR + CLKCTL_CDHIPR) != 0)
441 + writel(0x0, CCM_BASE_ADDR + CLKCTL_CCDR);
447 + * This function assumes the expected core clock has to be changed by
448 + * modifying the PLL. This is NOT true always but for most of the times,
449 + * it is. So it assumes the PLL output freq is the same as the expected
450 + * core clock (presc=1) unless the core clock is less than PLL_FREQ_MIN.
451 + * In the latter case, it will try to increase the presc value until
452 + * (presc*core_clk) is greater than PLL_FREQ_MIN. It then makes call to
453 + * calc_pll_params() and obtains the values of PD, MFI,MFN, MFD based
454 + * on the targeted PLL and reference input clock to the PLL. Lastly,
455 + * it sets the register based on these values along with the dividers.
456 + * Note 1) There is no value checking for the passed-in divider values
457 + * so the caller has to make sure those values are sensible.
458 + * 2) Also adjust the NFC divider such that the NFC clock doesn't
459 + * exceed NFC_CLK_MAX.
460 + * 3) IPU HSP clock is independent of AHB clock. Even it can go up to
461 + * 177MHz for higher voltage, this function fixes the max to 133MHz.
462 + * 4) This function should not have allowed diag_printf() calls since
463 + * the serial driver has been stoped. But leave then here to allow
464 + * easy debugging by NOT calling the cyg_hal_plf_serial_stop().
466 + * @param ref pll input reference clock (24MHz)
467 + * @param freq core clock in Hz
468 + * @param clk_type clock type, e.g CPU_CLK, DDR_CLK, etc.
469 + * @return 0 if successful; non-zero otherwise
471 +int clk_config(u32 ref, u32 freq, u32 clk_type)
474 + struct pll_param pll_param;
479 + switch (clk_type) {
481 + if ((freq < PLL_FREQ_MIN(ref)) ||
482 + (freq > PLL_FREQ_MAX(ref))) {
483 + printf("Targeted core clock should be"
484 + "within [%d - %d]\n",
485 + PLL_FREQ_MIN(ref) / SZ_DEC_1M,
486 + PLL_FREQ_MAX(ref) / SZ_DEC_1M);
491 + ret = calc_pll_params(ref, pll, &pll_param);
493 + printf("Can't find pll parameters: %d\n",
497 +#ifdef CMD_CLOCK_DEBUG
498 + printf("ref=%d, pll=%d, pd=%d, "
499 + "mfi=%d,mfn=%d, mfd=%d\n",
500 + ref, pll, pll_param.pd, pll_param.mfi,
501 + pll_param.mfn, pll_param.mfd);
503 + config_core_clk(&pll_param);
506 + if (freq > MAX_DDR_CLK) {
507 + printf("DDR clock should be less than"
508 + "%d MHz, assuming max value \n",
509 + (MAX_DDR_CLK / SZ_DEC_1M));
510 + freq = MAX_DDR_CLK;
513 + config_ddr_clk(freq);
516 + printf("Unsupported or invalid clock type! :(\n");
523 #if defined(CONFIG_DISPLAY_CPUINFO)
524 int print_cpuinfo(void)
526 diff --git a/include/asm-arm/clock.h b/include/asm-arm/clock.h
528 index 0000000..95afb89
530 +++ b/include/asm-arm/clock.h
533 + * (C) Copyright 2008-2010 Freescale Semiconductor, Inc.
536 + * See file CREDITS for list of people who contributed to this
539 + * This program is free software; you can redistribute it and/or
540 + * modify it under the terms of the GNU General Public License as
541 + * published by the Free Software Foundation; either version 2 of
542 + * the License, or (at your option) any later version.
544 + * This program is distributed in the hope that it will be useful,
545 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
546 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
547 + * GNU General Public License for more details.
549 + * You should have received a copy of the GNU General Public License
550 + * along with this program; if not, write to the Free Software
551 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
552 + * MA 02111-1307 USA
555 +#ifndef __ASM_ARCH_CLOCK_H__
556 +#define __ASM_ARCH_CLOCK_H__
557 +#include <linux/types.h>
570 +int clk_config(u32 ref, u32 freq, u32 clk_type);
571 +int clk_info(u32 clk_type);
574 diff --git a/include/configs/mx53_arm2.h b/include/configs/mx53_arm2.h
575 index 5517459..7265062 100644
576 --- a/include/configs/mx53_arm2.h
577 +++ b/include/configs/mx53_arm2.h
579 #define CONFIG_CMD_MMC
580 #define CONFIG_CMD_ENV
582 +#define CONFIG_CMD_CLOCK
583 +#define CONFIG_REF_CLK_FREQ CONFIG_MX53_HCLK_FREQ
585 #undef CONFIG_CMD_IMLS
587 #define CONFIG_BOOTDELAY 3
588 diff --git a/include/configs/mx53_evk.h b/include/configs/mx53_evk.h
589 index 85bd02f..760d4ac 100644
590 --- a/include/configs/mx53_evk.h
591 +++ b/include/configs/mx53_evk.h
593 #define CONFIG_CMD_MMC
594 #define CONFIG_CMD_ENV
596 +#define CONFIG_CMD_CLOCK
597 +#define CONFIG_REF_CLK_FREQ CONFIG_MX53_HCLK_FREQ
599 #undef CONFIG_CMD_IMLS
601 #define CONFIG_BOOTDELAY 3