1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (c) 2008 Michael Sevakis
12 * Clock control functions for IMX31 processor
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
25 #include "ccm-imx31.h"
27 /* Return the current source pll for MCU */
28 enum IMX31_PLLS
ccm_get_src_pll(void)
30 return (CCM_PMCR0
& 0xC0000000) == 0 ? PLL_SERIAL
: PLL_MCU
;
33 void ccm_module_clock_gating(enum IMX31_CG_LIST cg
, enum IMX31_CG_MODES mode
)
35 volatile unsigned long *reg
;
39 if (cg
>= CG_NUM_CLOCKS
)
42 reg
= &CCM_CGR0
+ cg
/ 16; /* Select CGR0, CGR1, CGR2 */
43 shift
= 2*(cg
% 16); /* Get field shift */
44 mask
= CG_MASK
<< shift
; /* Select field */
46 imx31_regmod32(reg
, mode
<< shift
, mask
);
49 /* Decode PLL output frequency from register value */
50 unsigned int ccm_calc_pll_rate(unsigned int infreq
, unsigned long regval
)
52 uint32_t mfn
= regval
& 0x3ff;
53 uint32_t pd
= ((regval
>> 26) & 0xf) + 1;
54 uint32_t mfd
= ((regval
>> 16) & 0x3ff) + 1;
55 uint32_t mfi
= (regval
>> 10) & 0xf;
57 mfi
= mfi
<= 5 ? 5 : mfi
;
59 return 2ull*infreq
*(mfi
* mfd
+ mfn
) / (mfd
* pd
);
62 /* Get the PLL reference clock frequency in HZ */
63 unsigned int ccm_get_pll_ref_clk_rate(void)
65 if ((CCM_CCMR
& (3 << 1)) == (1 << 1))
66 return CONFIG_CKIL_FREQ
* 1024;
68 return CONFIG_CKIH_FREQ
;
71 /* Return PLL frequency in HZ */
72 unsigned int ccm_get_pll_rate(enum IMX31_PLLS pll
)
74 return ccm_calc_pll_rate(ccm_get_pll_ref_clk_rate(), (&CCM_MPCTL
)[pll
]);
77 unsigned int ccm_get_mcu_clk(void)
79 unsigned int pllnum
= ccm_get_src_pll();
80 unsigned int fpll
= ccm_get_pll_rate(pllnum
);
81 unsigned int mcu_podf
= (CCM_PDR0
& 0x7) + 1;
83 return fpll
/ mcu_podf
;
86 unsigned int ccm_get_ipg_clk(void)
88 unsigned int pllnum
= ccm_get_src_pll();
89 unsigned int fpll
= ccm_get_pll_rate(pllnum
);
90 uint32_t reg
= CCM_PDR0
;
91 unsigned int max_pdf
= ((reg
>> 3) & 0x7) + 1;
92 unsigned int ipg_pdf
= ((reg
>> 6) & 0x3) + 1;
94 return fpll
/ (max_pdf
* ipg_pdf
);
97 unsigned int ccm_get_ahb_clk(void)
99 unsigned int pllnum
= ccm_get_src_pll();
100 unsigned int fpll
= ccm_get_pll_rate(pllnum
);
101 unsigned int max_pdf
= ((CCM_PDR0
>> 3) & 0x7) + 1;
103 return fpll
/ max_pdf
;
106 unsigned int ccm_get_ata_clk(void)
108 return ccm_get_ipg_clk();
111 /* Write new values to the current PLL and post-dividers */
112 void ccm_set_mcupll_and_pdr(unsigned long pllctl
, unsigned long pdr
)
114 unsigned int pll
= ccm_get_src_pll();
115 volatile unsigned long *pllreg
= &(&CCM_MPCTL
)[pll
];
116 unsigned long fref
= ccm_get_pll_ref_clk_rate();
117 unsigned long curfreq
= ccm_calc_pll_rate(fref
, *pllreg
);
118 unsigned long newfreq
= ccm_calc_pll_rate(fref
, pllctl
);
120 if (newfreq
> curfreq
)
125 if (newfreq
<= curfreq
)