tizen 2.4 release
[profile/mobile/platform/kernel/u-boot-tm1.git] / arch / arm / cpu / arm926ejs / sc8800x / clk_config.c
1 #include <config.h>
2 #include <asm/io.h>
3 #include <asm/arch/bits.h>
4 #include <asm/arch/regs_global.h>
5 #include <asm/arch/regs_ahb.h>
6 #include <linux/types.h>
7
8 /*************************************************
9  * determine the clock input, by the strap pin
10  * the strap bit shows the crytal input clock
11  * 1 : 26Mhz
12  * 0 : 13Mhz
13  *
14  * return value is frequency in Mhz, 26 or 13
15  * ***********************************************/
16 uint32_t get_input_clk(void)
17 {
18         uint32_t reg_content;
19         reg_content = readl(GR_GEN1);
20         
21         if(reg_content & GEN1_CLK_26MHZ_EN){
22                 return 26;
23         }else {
24                 return 13;
25         }
26 }
27
28 /****************************************************************
29  * calculate the greatest common divisor for two input integer
30  * the two input value should be non-zero integer
31  *
32  * return is the greatest common divisor
33  * 0 is failed
34  * *************************************************************/
35 uint32_t cal_g_divisor(uint32_t val_one, uint32_t val_two)
36 {
37         if(val_one == 0 || val_two == 0)
38                 return 0;
39
40         uint32_t div;
41         
42         uint32_t big_val, sml_val;
43         
44         if(val_one >= val_two) {
45                 big_val = val_one;
46                 sml_val = val_two;
47         }else{
48                 big_val = val_two;
49                 sml_val = val_one;
50         }
51
52         div = big_val%sml_val;
53         while(div != 0) {
54                 big_val = sml_val;
55                 sml_val = div;
56                 div = big_val%sml_val;
57         }
58         return sml_val;
59 }
60 /*************************************************
61  * config pll, AHB, AMR,EMC clock
62  * the config value is get from board specific
63  * config file
64  *
65  * return is ahb clock for further configuration
66  * ************************************************/
67 uint32_t config_clk(void)
68 {
69         uint32_t input_clk, ahb_clk, pll_clk, ahb_div, arm_div, emc_div, xahb_div;
70         uint32_t pll_div_m, pll_div_n;
71         uint32_t reg_config;
72         uint32_t great_divisor;
73         int i;
74
75         // get the input clock
76         input_clk = get_input_clk();    
77         pll_clk = CONFIG_SYS_PLL_MHZ;
78         if(pll_clk <= 0)
79                 pll_clk = input_clk;  // cpu run frequency should not below input clk
80
81         //calculate the divisor
82         great_divisor = cal_g_divisor(pll_clk, input_clk);
83         if(great_divisor <= 0)
84                 return 0;
85
86         pll_div_m = input_clk / great_divisor;
87         if(pll_div_m <= 0)
88                 pll_div_m = 1;
89         else if(pll_div_m > PLLMN_M_MAX)
90                 pll_div_m = PLLMN_M_MAX;
91
92         pll_div_n = pll_clk / great_divisor;
93         if(pll_div_n > PLLMN_N_MAX){
94                 pll_div_n = PLLMN_N_MAX;
95                 pll_div_m = (input_clk * pll_div_n)/pll_clk;
96         }else if(pll_div_n <= 0)
97                 pll_div_n = 1;
98         
99         reg_config = readl(GR_GEN1);  //enable mpll write
100         reg_config |= GEN1_MPLLMN_WN;
101         writel(reg_config,GR_GEN1);
102         reg_config = (pll_div_m <<PLLMN_M_SHIFT) | (pll_div_n << PLLMN_N_SHIFT);
103         writel(reg_config, GR_MPLL_MN); //config mpll register
104         reg_config = readl(GR_GEN1);   //disable mpll write
105         reg_config &= ~(GEN1_MPLLMN_WN);
106         writel(reg_config, GR_GEN1);
107         //delay some time
108         for(i = 0; i<100; i++);
109
110         ahb_div = CONFIG_SYS_AHB_DIV;
111         if(ahb_div <= 0)
112                 ahb_div = 1;
113         else if(ahb_div > AHB_CLK_DIV_MAX)
114                 ahb_div = AHB_CLK_DIV_MAX;
115
116         arm_div = CONFIG_SYS_ARM_DIV;
117         if(arm_div <= 0)
118                 arm_div = 1;
119         else if (arm_div > ARM_CLK_DIV_MAX)
120                 arm_div = ARM_CLK_DIV_MAX;
121
122         emc_div = CONFIG_SYS_EMC_DIV;
123         if(emc_div <= 0)
124                 emc_div = 1;
125         else if (emc_div > EMC_CLK_DIV_MAX)
126                 emc_div = EMC_CLK_DIV_MAX;
127
128         xahb_div = ahb_div/arm_div;
129
130         //config AHB ARM CLK register
131         reg_config = ((ahb_div-1) << AHB_CLK_DIV_SHIFT) | ((arm_div-1) << ARM_CLK_DIV_SHIFT) | ((emc_div-1) << EMC_CLK_DIV_SHIFT) | ((xahb_div-1) << XAHB_CLK_DIV_SHIFT);
132         writel(reg_config, AHB_AHB_ARM_CLK);
133
134         //delay some time
135         for(i=0; i<100; i++);
136
137         ahb_clk = pll_clk/ahb_div;
138         return ahb_clk;
139 }