blob: 4d92c53b95466b00ba8ca5de8aedc630bcae1ca9 [file] [log] [blame]
Minkyu Kang008a3512011-01-24 15:22:23 +09001/*
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
Chander Kashyap393cb362011-12-06 23:34:12 +000029/* exynos4: return pll clock frequency */
30static unsigned long exynos4_get_pll_clk(int pllreg)
Minkyu Kang008a3512011-01-24 15:22:23 +090031{
Chander Kashyap393cb362011-12-06 23:34:12 +000032 struct exynos4_clock *clk =
33 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +090034 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
Chander Kashyap5e46f832012-02-05 23:01:45 +000075 freq = CONFIG_SYS_CLK_FREQ;
Minkyu Kang008a3512011-01-24 15:22:23 +090076
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
Chander Kashyap393cb362011-12-06 23:34:12 +000095/* exynos4: return ARM clock frequency */
96static unsigned long exynos4_get_arm_clk(void)
Minkyu Kang008a3512011-01-24 15:22:23 +090097{
Chander Kashyap393cb362011-12-06 23:34:12 +000098 struct exynos4_clock *clk =
99 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900100 unsigned long div;
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000101 unsigned long armclk;
102 unsigned int core_ratio;
103 unsigned int core2_ratio;
Minkyu Kang008a3512011-01-24 15:22:23 +0900104
105 div = readl(&clk->div_cpu0);
106
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000107 /* CORE_RATIO: [2:0], CORE2_RATIO: [30:28] */
108 core_ratio = (div >> 0) & 0x7;
109 core2_ratio = (div >> 28) & 0x7;
Minkyu Kang008a3512011-01-24 15:22:23 +0900110
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000111 armclk = get_pll_clk(APLL) / (core_ratio + 1);
112 armclk /= (core2_ratio + 1);
Minkyu Kang008a3512011-01-24 15:22:23 +0900113
Chander Kashyapdb68bc22011-12-18 22:56:44 +0000114 return armclk;
Minkyu Kang008a3512011-01-24 15:22:23 +0900115}
116
Chander Kashyap393cb362011-12-06 23:34:12 +0000117/* exynos4: return pwm clock frequency */
118static unsigned long exynos4_get_pwm_clk(void)
Minkyu Kang008a3512011-01-24 15:22:23 +0900119{
Chander Kashyap393cb362011-12-06 23:34:12 +0000120 struct exynos4_clock *clk =
121 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900122 unsigned long pclk, sclk;
123 unsigned int sel;
124 unsigned int ratio;
125
Minkyu Kangb4f73912011-05-18 16:57:55 +0900126 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;
Minkyu Kang008a3512011-01-24 15:22:23 +0900133
Minkyu Kangb4f73912011-05-18 16:57:55 +0900134 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) {
Minkyu Kang008a3512011-01-24 15:22:23 +0900150 sclk = get_pll_clk(MPLL);
Minkyu Kangb4f73912011-05-18 16:57:55 +0900151 ratio = 8;
152 } else
Minkyu Kang008a3512011-01-24 15:22:23 +0900153 return 0;
154
Minkyu Kang008a3512011-01-24 15:22:23 +0900155 pclk = sclk / (ratio + 1);
156
157 return pclk;
158}
159
Chander Kashyap393cb362011-12-06 23:34:12 +0000160/* exynos4: return uart clock frequency */
161static unsigned long exynos4_get_uart_clk(int dev_index)
Minkyu Kang008a3512011-01-24 15:22:23 +0900162{
Chander Kashyap393cb362011-12-06 23:34:12 +0000163 struct exynos4_clock *clk =
164 (struct exynos4_clock *)samsung_get_base_clock();
Minkyu Kang008a3512011-01-24 15:22:23 +0900165 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
Chander Kashyap393cb362011-12-06 23:34:12 +0000207/* exynos4: set the mmc clock */
208static void exynos4_set_mmc_clk(int dev_index, unsigned int div)
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000209{
Chander Kashyap393cb362011-12-06 23:34:12 +0000210 struct exynos4_clock *clk =
211 (struct exynos4_clock *)samsung_get_base_clock();
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000212 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
Minkyu Kang008a3512011-01-24 15:22:23 +0900234unsigned long get_pll_clk(int pllreg)
235{
Chander Kashyap393cb362011-12-06 23:34:12 +0000236 return exynos4_get_pll_clk(pllreg);
Minkyu Kang008a3512011-01-24 15:22:23 +0900237}
238
239unsigned long get_arm_clk(void)
240{
Chander Kashyap393cb362011-12-06 23:34:12 +0000241 return exynos4_get_arm_clk();
Minkyu Kang008a3512011-01-24 15:22:23 +0900242}
243
244unsigned long get_pwm_clk(void)
245{
Chander Kashyap393cb362011-12-06 23:34:12 +0000246 return exynos4_get_pwm_clk();
Minkyu Kang008a3512011-01-24 15:22:23 +0900247}
248
249unsigned long get_uart_clk(int dev_index)
250{
Chander Kashyap393cb362011-12-06 23:34:12 +0000251 return exynos4_get_uart_clk(dev_index);
Minkyu Kang008a3512011-01-24 15:22:23 +0900252}
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000253
254void set_mmc_clk(int dev_index, unsigned int div)
255{
Chander Kashyap393cb362011-12-06 23:34:12 +0000256 exynos4_set_mmc_clk(dev_index, div);
Jaehoon Chung68a8cbf2011-05-17 21:19:17 +0000257}