]> git.ipfire.org Git - people/ms/u-boot.git/blob - arch/arm/cpu/armv7/s5pc2xx/clock.c
tegra2: Don't use board pointer before it is set up
[people/ms/u-boot.git] / arch / arm / cpu / armv7 / s5pc2xx / clock.c
1 /*
2 * Copyright (C) 2010 Samsung Electronics
3 * Minkyu Kang <mk7.kang@samsung.com>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24 #include <common.h>
25 #include <asm/io.h>
26 #include <asm/arch/clock.h>
27 #include <asm/arch/clk.h>
28
29 #ifndef CONFIG_SYS_CLK_FREQ_C210
30 #define CONFIG_SYS_CLK_FREQ_C210 24000000
31 #endif
32
33 /* s5pc210: return pll clock frequency */
34 static unsigned long s5pc210_get_pll_clk(int pllreg)
35 {
36 struct s5pc210_clock *clk =
37 (struct s5pc210_clock *)samsung_get_base_clock();
38 unsigned long r, m, p, s, k = 0, mask, fout;
39 unsigned int freq;
40
41 switch (pllreg) {
42 case APLL:
43 r = readl(&clk->apll_con0);
44 break;
45 case MPLL:
46 r = readl(&clk->mpll_con0);
47 break;
48 case EPLL:
49 r = readl(&clk->epll_con0);
50 k = readl(&clk->epll_con1);
51 break;
52 case VPLL:
53 r = readl(&clk->vpll_con0);
54 k = readl(&clk->vpll_con1);
55 break;
56 default:
57 printf("Unsupported PLL (%d)\n", pllreg);
58 return 0;
59 }
60
61 /*
62 * APLL_CON: MIDV [25:16]
63 * MPLL_CON: MIDV [25:16]
64 * EPLL_CON: MIDV [24:16]
65 * VPLL_CON: MIDV [24:16]
66 */
67 if (pllreg == APLL || pllreg == MPLL)
68 mask = 0x3ff;
69 else
70 mask = 0x1ff;
71
72 m = (r >> 16) & mask;
73
74 /* PDIV [13:8] */
75 p = (r >> 8) & 0x3f;
76 /* SDIV [2:0] */
77 s = r & 0x7;
78
79 freq = CONFIG_SYS_CLK_FREQ_C210;
80
81 if (pllreg == EPLL) {
82 k = k & 0xffff;
83 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
84 fout = (m + k / 65536) * (freq / (p * (1 << s)));
85 } else if (pllreg == VPLL) {
86 k = k & 0xfff;
87 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
88 fout = (m + k / 1024) * (freq / (p * (1 << s)));
89 } else {
90 if (s < 1)
91 s = 1;
92 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
93 fout = m * (freq / (p * (1 << (s - 1))));
94 }
95
96 return fout;
97 }
98
99 /* s5pc210: return ARM clock frequency */
100 static unsigned long s5pc210_get_arm_clk(void)
101 {
102 struct s5pc210_clock *clk =
103 (struct s5pc210_clock *)samsung_get_base_clock();
104 unsigned long div;
105 unsigned long dout_apll;
106 unsigned int apll_ratio;
107
108 div = readl(&clk->div_cpu0);
109
110 /* APLL_RATIO: [26:24] */
111 apll_ratio = (div >> 24) & 0x7;
112
113 dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
114
115 return dout_apll;
116 }
117
118 /* s5pc210: return pwm clock frequency */
119 static unsigned long s5pc210_get_pwm_clk(void)
120 {
121 struct s5pc210_clock *clk =
122 (struct s5pc210_clock *)samsung_get_base_clock();
123 unsigned long pclk, sclk;
124 unsigned int sel;
125 unsigned int ratio;
126
127 if (s5p_get_cpu_rev() == 0) {
128 /*
129 * CLK_SRC_PERIL0
130 * PWM_SEL [27:24]
131 */
132 sel = readl(&clk->src_peril0);
133 sel = (sel >> 24) & 0xf;
134
135 if (sel == 0x6)
136 sclk = get_pll_clk(MPLL);
137 else if (sel == 0x7)
138 sclk = get_pll_clk(EPLL);
139 else if (sel == 0x8)
140 sclk = get_pll_clk(VPLL);
141 else
142 return 0;
143
144 /*
145 * CLK_DIV_PERIL3
146 * PWM_RATIO [3:0]
147 */
148 ratio = readl(&clk->div_peril3);
149 ratio = ratio & 0xf;
150 } else if (s5p_get_cpu_rev() == 1) {
151 sclk = get_pll_clk(MPLL);
152 ratio = 8;
153 } else
154 return 0;
155
156 pclk = sclk / (ratio + 1);
157
158 return pclk;
159 }
160
161 /* s5pc210: return uart clock frequency */
162 static unsigned long s5pc210_get_uart_clk(int dev_index)
163 {
164 struct s5pc210_clock *clk =
165 (struct s5pc210_clock *)samsung_get_base_clock();
166 unsigned long uclk, sclk;
167 unsigned int sel;
168 unsigned int ratio;
169
170 /*
171 * CLK_SRC_PERIL0
172 * UART0_SEL [3:0]
173 * UART1_SEL [7:4]
174 * UART2_SEL [8:11]
175 * UART3_SEL [12:15]
176 * UART4_SEL [16:19]
177 * UART5_SEL [23:20]
178 */
179 sel = readl(&clk->src_peril0);
180 sel = (sel >> (dev_index << 2)) & 0xf;
181
182 if (sel == 0x6)
183 sclk = get_pll_clk(MPLL);
184 else if (sel == 0x7)
185 sclk = get_pll_clk(EPLL);
186 else if (sel == 0x8)
187 sclk = get_pll_clk(VPLL);
188 else
189 return 0;
190
191 /*
192 * CLK_DIV_PERIL0
193 * UART0_RATIO [3:0]
194 * UART1_RATIO [7:4]
195 * UART2_RATIO [8:11]
196 * UART3_RATIO [12:15]
197 * UART4_RATIO [16:19]
198 * UART5_RATIO [23:20]
199 */
200 ratio = readl(&clk->div_peril0);
201 ratio = (ratio >> (dev_index << 2)) & 0xf;
202
203 uclk = sclk / (ratio + 1);
204
205 return uclk;
206 }
207
208 /* s5pc210: set the mmc clock */
209 static void s5pc210_set_mmc_clk(int dev_index, unsigned int div)
210 {
211 struct s5pc210_clock *clk =
212 (struct s5pc210_clock *)samsung_get_base_clock();
213 unsigned int addr;
214 unsigned int val;
215
216 /*
217 * CLK_DIV_FSYS1
218 * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
219 * CLK_DIV_FSYS2
220 * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
221 */
222 if (dev_index < 2) {
223 addr = (unsigned int)&clk->div_fsys1;
224 } else {
225 addr = (unsigned int)&clk->div_fsys2;
226 dev_index -= 2;
227 }
228
229 val = readl(addr);
230 val &= ~(0xff << ((dev_index << 4) + 8));
231 val |= (div & 0xff) << ((dev_index << 4) + 8);
232 writel(val, addr);
233 }
234
235 unsigned long get_pll_clk(int pllreg)
236 {
237 return s5pc210_get_pll_clk(pllreg);
238 }
239
240 unsigned long get_arm_clk(void)
241 {
242 return s5pc210_get_arm_clk();
243 }
244
245 unsigned long get_pwm_clk(void)
246 {
247 return s5pc210_get_pwm_clk();
248 }
249
250 unsigned long get_uart_clk(int dev_index)
251 {
252 return s5pc210_get_uart_clk(dev_index);
253 }
254
255 void set_mmc_clk(int dev_index, unsigned int div)
256 {
257 s5pc210_set_mmc_clk(dev_index, div);
258 }