]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/exynos/clock.c
Exynos: Clock.c: Use CONFIG_SYS_CLK_FREQ macro
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / exynos / 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 /* exynos4: return pll clock frequency */
30 static unsigned long exynos4_get_pll_clk(int pllreg)
31 {
32         struct exynos4_clock *clk =
33                 (struct exynos4_clock *)samsung_get_base_clock();
34         unsigned long r, m, p, s, k = 0, mask, fout;
35         unsigned int freq;
36
37         switch (pllreg) {
38         case APLL:
39                 r = readl(&clk->apll_con0);
40                 break;
41         case MPLL:
42                 r = readl(&clk->mpll_con0);
43                 break;
44         case EPLL:
45                 r = readl(&clk->epll_con0);
46                 k = readl(&clk->epll_con1);
47                 break;
48         case VPLL:
49                 r = readl(&clk->vpll_con0);
50                 k = readl(&clk->vpll_con1);
51                 break;
52         default:
53                 printf("Unsupported PLL (%d)\n", pllreg);
54                 return 0;
55         }
56
57         /*
58          * APLL_CON: MIDV [25:16]
59          * MPLL_CON: MIDV [25:16]
60          * EPLL_CON: MIDV [24:16]
61          * VPLL_CON: MIDV [24:16]
62          */
63         if (pllreg == APLL || pllreg == MPLL)
64                 mask = 0x3ff;
65         else
66                 mask = 0x1ff;
67
68         m = (r >> 16) & mask;
69
70         /* PDIV [13:8] */
71         p = (r >> 8) & 0x3f;
72         /* SDIV [2:0] */
73         s = r & 0x7;
74
75         freq = CONFIG_SYS_CLK_FREQ;
76
77         if (pllreg == EPLL) {
78                 k = k & 0xffff;
79                 /* FOUT = (MDIV + K / 65536) * FIN / (PDIV * 2^SDIV) */
80                 fout = (m + k / 65536) * (freq / (p * (1 << s)));
81         } else if (pllreg == VPLL) {
82                 k = k & 0xfff;
83                 /* FOUT = (MDIV + K / 1024) * FIN / (PDIV * 2^SDIV) */
84                 fout = (m + k / 1024) * (freq / (p * (1 << s)));
85         } else {
86                 if (s < 1)
87                         s = 1;
88                 /* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
89                 fout = m * (freq / (p * (1 << (s - 1))));
90         }
91
92         return fout;
93 }
94
95 /* exynos4: return ARM clock frequency */
96 static unsigned long exynos4_get_arm_clk(void)
97 {
98         struct exynos4_clock *clk =
99                 (struct exynos4_clock *)samsung_get_base_clock();
100         unsigned long div;
101         unsigned long armclk;
102         unsigned int core_ratio;
103         unsigned int core2_ratio;
104
105         div = readl(&clk->div_cpu0);
106
107         /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
108         core_ratio = (div >> 0) & 0x7;
109         core2_ratio = (div >> 28) & 0x7;
110
111         armclk = get_pll_clk(APLL) / (core_ratio + 1);
112         armclk /= (core2_ratio + 1);
113
114         return armclk;
115 }
116
117 /* exynos4: return pwm clock frequency */
118 static unsigned long exynos4_get_pwm_clk(void)
119 {
120         struct exynos4_clock *clk =
121                 (struct exynos4_clock *)samsung_get_base_clock();
122         unsigned long pclk, sclk;
123         unsigned int sel;
124         unsigned int ratio;
125
126         if (s5p_get_cpu_rev() == 0) {
127                 /*
128                  * CLK_SRC_PERIL0
129                  * PWM_SEL [27:24]
130                  */
131                 sel = readl(&clk->src_peril0);
132                 sel = (sel >> 24) & 0xf;
133
134                 if (sel == 0x6)
135                         sclk = get_pll_clk(MPLL);
136                 else if (sel == 0x7)
137                         sclk = get_pll_clk(EPLL);
138                 else if (sel == 0x8)
139                         sclk = get_pll_clk(VPLL);
140                 else
141                         return 0;
142
143                 /*
144                  * CLK_DIV_PERIL3
145                  * PWM_RATIO [3:0]
146                  */
147                 ratio = readl(&clk->div_peril3);
148                 ratio = ratio & 0xf;
149         } else if (s5p_get_cpu_rev() == 1) {
150                 sclk = get_pll_clk(MPLL);
151                 ratio = 8;
152         } else
153                 return 0;
154
155         pclk = sclk / (ratio + 1);
156
157         return pclk;
158 }
159
160 /* exynos4: return uart clock frequency */
161 static unsigned long exynos4_get_uart_clk(int dev_index)
162 {
163         struct exynos4_clock *clk =
164                 (struct exynos4_clock *)samsung_get_base_clock();
165         unsigned long uclk, sclk;
166         unsigned int sel;
167         unsigned int ratio;
168
169         /*
170          * CLK_SRC_PERIL0
171          * UART0_SEL [3:0]
172          * UART1_SEL [7:4]
173          * UART2_SEL [8:11]
174          * UART3_SEL [12:15]
175          * UART4_SEL [16:19]
176          * UART5_SEL [23:20]
177          */
178         sel = readl(&clk->src_peril0);
179         sel = (sel >> (dev_index << 2)) & 0xf;
180
181         if (sel == 0x6)
182                 sclk = get_pll_clk(MPLL);
183         else if (sel == 0x7)
184                 sclk = get_pll_clk(EPLL);
185         else if (sel == 0x8)
186                 sclk = get_pll_clk(VPLL);
187         else
188                 return 0;
189
190         /*
191          * CLK_DIV_PERIL0
192          * UART0_RATIO [3:0]
193          * UART1_RATIO [7:4]
194          * UART2_RATIO [8:11]
195          * UART3_RATIO [12:15]
196          * UART4_RATIO [16:19]
197          * UART5_RATIO [23:20]
198          */
199         ratio = readl(&clk->div_peril0);
200         ratio = (ratio >> (dev_index << 2)) & 0xf;
201
202         uclk = sclk / (ratio + 1);
203
204         return uclk;
205 }
206
207 /* exynos4: set the mmc clock */
208 static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
209 {
210         struct exynos4_clock *clk =
211                 (struct exynos4_clock *)samsung_get_base_clock();
212         unsigned int addr;
213         unsigned int val;
214
215         /*
216          * CLK_DIV_FSYS1
217          * MMC0_PRE_RATIO [15:8], MMC1_PRE_RATIO [31:24]
218          * CLK_DIV_FSYS2
219          * MMC2_PRE_RATIO [15:8], MMC3_PRE_RATIO [31:24]
220          */
221         if (dev_index < 2) {
222                 addr = (unsigned int)&clk->div_fsys1;
223         } else {
224                 addr = (unsigned int)&clk->div_fsys2;
225                 dev_index -= 2;
226         }
227
228         val = readl(addr);
229         val &= ~(0xff << ((dev_index << 4) + 8));
230         val |= (div & 0xff) << ((dev_index << 4) + 8);
231         writel(val, addr);
232 }
233
234 unsigned long get_pll_clk(int pllreg)
235 {
236         return exynos4_get_pll_clk(pllreg);
237 }
238
239 unsigned long get_arm_clk(void)
240 {
241         return exynos4_get_arm_clk();
242 }
243
244 unsigned long get_pwm_clk(void)
245 {
246         return exynos4_get_pwm_clk();
247 }
248
249 unsigned long get_uart_clk(int dev_index)
250 {
251         return exynos4_get_uart_clk(dev_index);
252 }
253
254 void set_mmc_clk(int dev_index, unsigned int div)
255 {
256         exynos4_set_mmc_clk(dev_index, div);
257 }