xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-s5pc1xx/clock.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (C) 2009 Samsung Electronics
3*4882a593Smuzhiyun  * Minkyu Kang <mk7.kang@samsung.com>
4*4882a593Smuzhiyun  * Heungjun Kim <riverful.kim@samsung.com>
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <common.h>
10*4882a593Smuzhiyun #include <asm/io.h>
11*4882a593Smuzhiyun #include <asm/arch/clock.h>
12*4882a593Smuzhiyun #include <asm/arch/clk.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define CLK_M	0
15*4882a593Smuzhiyun #define CLK_D	1
16*4882a593Smuzhiyun #define CLK_P	2
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #ifndef CONFIG_SYS_CLK_FREQ_C100
19*4882a593Smuzhiyun #define CONFIG_SYS_CLK_FREQ_C100	12000000
20*4882a593Smuzhiyun #endif
21*4882a593Smuzhiyun #ifndef CONFIG_SYS_CLK_FREQ_C110
22*4882a593Smuzhiyun #define CONFIG_SYS_CLK_FREQ_C110	24000000
23*4882a593Smuzhiyun #endif
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* s5pc110: return pll clock frequency */
s5pc100_get_pll_clk(int pllreg)26*4882a593Smuzhiyun static unsigned long s5pc100_get_pll_clk(int pllreg)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	struct s5pc100_clock *clk =
29*4882a593Smuzhiyun 		(struct s5pc100_clock *)samsung_get_base_clock();
30*4882a593Smuzhiyun 	unsigned long r, m, p, s, mask, fout;
31*4882a593Smuzhiyun 	unsigned int freq;
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	switch (pllreg) {
34*4882a593Smuzhiyun 	case APLL:
35*4882a593Smuzhiyun 		r = readl(&clk->apll_con);
36*4882a593Smuzhiyun 		break;
37*4882a593Smuzhiyun 	case MPLL:
38*4882a593Smuzhiyun 		r = readl(&clk->mpll_con);
39*4882a593Smuzhiyun 		break;
40*4882a593Smuzhiyun 	case EPLL:
41*4882a593Smuzhiyun 		r = readl(&clk->epll_con);
42*4882a593Smuzhiyun 		break;
43*4882a593Smuzhiyun 	case HPLL:
44*4882a593Smuzhiyun 		r = readl(&clk->hpll_con);
45*4882a593Smuzhiyun 		break;
46*4882a593Smuzhiyun 	default:
47*4882a593Smuzhiyun 		printf("Unsupported PLL (%d)\n", pllreg);
48*4882a593Smuzhiyun 		return 0;
49*4882a593Smuzhiyun 	}
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	/*
52*4882a593Smuzhiyun 	 * APLL_CON: MIDV [25:16]
53*4882a593Smuzhiyun 	 * MPLL_CON: MIDV [23:16]
54*4882a593Smuzhiyun 	 * EPLL_CON: MIDV [23:16]
55*4882a593Smuzhiyun 	 * HPLL_CON: MIDV [23:16]
56*4882a593Smuzhiyun 	 */
57*4882a593Smuzhiyun 	if (pllreg == APLL)
58*4882a593Smuzhiyun 		mask = 0x3ff;
59*4882a593Smuzhiyun 	else
60*4882a593Smuzhiyun 		mask = 0x0ff;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	m = (r >> 16) & mask;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	/* PDIV [13:8] */
65*4882a593Smuzhiyun 	p = (r >> 8) & 0x3f;
66*4882a593Smuzhiyun 	/* SDIV [2:0] */
67*4882a593Smuzhiyun 	s = r & 0x7;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
70*4882a593Smuzhiyun 	freq = CONFIG_SYS_CLK_FREQ_C100;
71*4882a593Smuzhiyun 	fout = m * (freq / (p * (1 << s)));
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	return fout;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* s5pc100: return pll clock frequency */
s5pc110_get_pll_clk(int pllreg)77*4882a593Smuzhiyun static unsigned long s5pc110_get_pll_clk(int pllreg)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct s5pc110_clock *clk =
80*4882a593Smuzhiyun 		(struct s5pc110_clock *)samsung_get_base_clock();
81*4882a593Smuzhiyun 	unsigned long r, m, p, s, mask, fout;
82*4882a593Smuzhiyun 	unsigned int freq;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	switch (pllreg) {
85*4882a593Smuzhiyun 	case APLL:
86*4882a593Smuzhiyun 		r = readl(&clk->apll_con);
87*4882a593Smuzhiyun 		break;
88*4882a593Smuzhiyun 	case MPLL:
89*4882a593Smuzhiyun 		r = readl(&clk->mpll_con);
90*4882a593Smuzhiyun 		break;
91*4882a593Smuzhiyun 	case EPLL:
92*4882a593Smuzhiyun 		r = readl(&clk->epll_con);
93*4882a593Smuzhiyun 		break;
94*4882a593Smuzhiyun 	case VPLL:
95*4882a593Smuzhiyun 		r = readl(&clk->vpll_con);
96*4882a593Smuzhiyun 		break;
97*4882a593Smuzhiyun 	default:
98*4882a593Smuzhiyun 		printf("Unsupported PLL (%d)\n", pllreg);
99*4882a593Smuzhiyun 		return 0;
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	/*
103*4882a593Smuzhiyun 	 * APLL_CON: MIDV [25:16]
104*4882a593Smuzhiyun 	 * MPLL_CON: MIDV [25:16]
105*4882a593Smuzhiyun 	 * EPLL_CON: MIDV [24:16]
106*4882a593Smuzhiyun 	 * VPLL_CON: MIDV [24:16]
107*4882a593Smuzhiyun 	 */
108*4882a593Smuzhiyun 	if (pllreg == APLL || pllreg == MPLL)
109*4882a593Smuzhiyun 		mask = 0x3ff;
110*4882a593Smuzhiyun 	else
111*4882a593Smuzhiyun 		mask = 0x1ff;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	m = (r >> 16) & mask;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	/* PDIV [13:8] */
116*4882a593Smuzhiyun 	p = (r >> 8) & 0x3f;
117*4882a593Smuzhiyun 	/* SDIV [2:0] */
118*4882a593Smuzhiyun 	s = r & 0x7;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	freq = CONFIG_SYS_CLK_FREQ_C110;
121*4882a593Smuzhiyun 	if (pllreg == APLL) {
122*4882a593Smuzhiyun 		if (s < 1)
123*4882a593Smuzhiyun 			s = 1;
124*4882a593Smuzhiyun 		/* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
125*4882a593Smuzhiyun 		fout = m * (freq / (p * (1 << (s - 1))));
126*4882a593Smuzhiyun 	} else
127*4882a593Smuzhiyun 		/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
128*4882a593Smuzhiyun 		fout = m * (freq / (p * (1 << s)));
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	return fout;
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /* s5pc110: return ARM clock frequency */
s5pc110_get_arm_clk(void)134*4882a593Smuzhiyun static unsigned long s5pc110_get_arm_clk(void)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct s5pc110_clock *clk =
137*4882a593Smuzhiyun 		(struct s5pc110_clock *)samsung_get_base_clock();
138*4882a593Smuzhiyun 	unsigned long div;
139*4882a593Smuzhiyun 	unsigned long dout_apll, armclk;
140*4882a593Smuzhiyun 	unsigned int apll_ratio;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	div = readl(&clk->div0);
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	/* APLL_RATIO: [2:0] */
145*4882a593Smuzhiyun 	apll_ratio = div & 0x7;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
148*4882a593Smuzhiyun 	armclk = dout_apll;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return armclk;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun /* s5pc100: return ARM clock frequency */
s5pc100_get_arm_clk(void)154*4882a593Smuzhiyun static unsigned long s5pc100_get_arm_clk(void)
155*4882a593Smuzhiyun {
156*4882a593Smuzhiyun 	struct s5pc100_clock *clk =
157*4882a593Smuzhiyun 		(struct s5pc100_clock *)samsung_get_base_clock();
158*4882a593Smuzhiyun 	unsigned long div;
159*4882a593Smuzhiyun 	unsigned long dout_apll, armclk;
160*4882a593Smuzhiyun 	unsigned int apll_ratio, arm_ratio;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	div = readl(&clk->div0);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* ARM_RATIO: [6:4] */
165*4882a593Smuzhiyun 	arm_ratio = (div >> 4) & 0x7;
166*4882a593Smuzhiyun 	/* APLL_RATIO: [0] */
167*4882a593Smuzhiyun 	apll_ratio = div & 0x1;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
170*4882a593Smuzhiyun 	armclk = dout_apll / (arm_ratio + 1);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	return armclk;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun /* s5pc100: return HCLKD0 frequency */
get_hclk(void)176*4882a593Smuzhiyun static unsigned long get_hclk(void)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct s5pc100_clock *clk =
179*4882a593Smuzhiyun 		(struct s5pc100_clock *)samsung_get_base_clock();
180*4882a593Smuzhiyun 	unsigned long hclkd0;
181*4882a593Smuzhiyun 	uint div, d0_bus_ratio;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	div = readl(&clk->div0);
184*4882a593Smuzhiyun 	/* D0_BUS_RATIO: [10:8] */
185*4882a593Smuzhiyun 	d0_bus_ratio = (div >> 8) & 0x7;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	return hclkd0;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun /* s5pc100: return PCLKD1 frequency */
get_pclkd1(void)193*4882a593Smuzhiyun static unsigned long get_pclkd1(void)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct s5pc100_clock *clk =
196*4882a593Smuzhiyun 		(struct s5pc100_clock *)samsung_get_base_clock();
197*4882a593Smuzhiyun 	unsigned long d1_bus, pclkd1;
198*4882a593Smuzhiyun 	uint div, d1_bus_ratio, pclkd1_ratio;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	div = readl(&clk->div0);
201*4882a593Smuzhiyun 	/* D1_BUS_RATIO: [14:12] */
202*4882a593Smuzhiyun 	d1_bus_ratio = (div >> 12) & 0x7;
203*4882a593Smuzhiyun 	/* PCLKD1_RATIO: [18:16] */
204*4882a593Smuzhiyun 	pclkd1_ratio = (div >> 16) & 0x7;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	/* ASYNC Mode */
207*4882a593Smuzhiyun 	d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
208*4882a593Smuzhiyun 	pclkd1 = d1_bus / (pclkd1_ratio + 1);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	return pclkd1;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /* s5pc110: return HCLKs frequency */
get_hclk_sys(int dom)214*4882a593Smuzhiyun static unsigned long get_hclk_sys(int dom)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct s5pc110_clock *clk =
217*4882a593Smuzhiyun 		(struct s5pc110_clock *)samsung_get_base_clock();
218*4882a593Smuzhiyun 	unsigned long hclk;
219*4882a593Smuzhiyun 	unsigned int div;
220*4882a593Smuzhiyun 	unsigned int offset;
221*4882a593Smuzhiyun 	unsigned int hclk_sys_ratio;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	if (dom == CLK_M)
224*4882a593Smuzhiyun 		return get_hclk();
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	div = readl(&clk->div0);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	/*
229*4882a593Smuzhiyun 	 * HCLK_MSYS_RATIO: [10:8]
230*4882a593Smuzhiyun 	 * HCLK_DSYS_RATIO: [19:16]
231*4882a593Smuzhiyun 	 * HCLK_PSYS_RATIO: [27:24]
232*4882a593Smuzhiyun 	 */
233*4882a593Smuzhiyun 	offset = 8 + (dom << 0x3);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	hclk_sys_ratio = (div >> offset) & 0xf;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return hclk;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun /* s5pc110: return PCLKs frequency */
get_pclk_sys(int dom)243*4882a593Smuzhiyun static unsigned long get_pclk_sys(int dom)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	struct s5pc110_clock *clk =
246*4882a593Smuzhiyun 		(struct s5pc110_clock *)samsung_get_base_clock();
247*4882a593Smuzhiyun 	unsigned long pclk;
248*4882a593Smuzhiyun 	unsigned int div;
249*4882a593Smuzhiyun 	unsigned int offset;
250*4882a593Smuzhiyun 	unsigned int pclk_sys_ratio;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	div = readl(&clk->div0);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/*
255*4882a593Smuzhiyun 	 * PCLK_MSYS_RATIO: [14:12]
256*4882a593Smuzhiyun 	 * PCLK_DSYS_RATIO: [22:20]
257*4882a593Smuzhiyun 	 * PCLK_PSYS_RATIO: [30:28]
258*4882a593Smuzhiyun 	 */
259*4882a593Smuzhiyun 	offset = 12 + (dom << 0x3);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	pclk_sys_ratio = (div >> offset) & 0x7;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	return pclk;
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun /* s5pc110: return peripheral clock frequency */
s5pc110_get_pclk(void)269*4882a593Smuzhiyun static unsigned long s5pc110_get_pclk(void)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	return get_pclk_sys(CLK_P);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun /* s5pc100: return peripheral clock frequency */
s5pc100_get_pclk(void)275*4882a593Smuzhiyun static unsigned long s5pc100_get_pclk(void)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	return get_pclkd1();
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun /* s5pc1xx: return uart clock frequency */
s5pc1xx_get_uart_clk(int dev_index)281*4882a593Smuzhiyun static unsigned long s5pc1xx_get_uart_clk(int dev_index)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	if (cpu_is_s5pc110())
284*4882a593Smuzhiyun 		return s5pc110_get_pclk();
285*4882a593Smuzhiyun 	else
286*4882a593Smuzhiyun 		return s5pc100_get_pclk();
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun /* s5pc1xx: return pwm clock frequency */
s5pc1xx_get_pwm_clk(void)290*4882a593Smuzhiyun static unsigned long s5pc1xx_get_pwm_clk(void)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun 	if (cpu_is_s5pc110())
293*4882a593Smuzhiyun 		return s5pc110_get_pclk();
294*4882a593Smuzhiyun 	else
295*4882a593Smuzhiyun 		return s5pc100_get_pclk();
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun 
get_pll_clk(int pllreg)298*4882a593Smuzhiyun unsigned long get_pll_clk(int pllreg)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun 	if (cpu_is_s5pc110())
301*4882a593Smuzhiyun 		return s5pc110_get_pll_clk(pllreg);
302*4882a593Smuzhiyun 	else
303*4882a593Smuzhiyun 		return s5pc100_get_pll_clk(pllreg);
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun 
get_arm_clk(void)306*4882a593Smuzhiyun unsigned long get_arm_clk(void)
307*4882a593Smuzhiyun {
308*4882a593Smuzhiyun 	if (cpu_is_s5pc110())
309*4882a593Smuzhiyun 		return s5pc110_get_arm_clk();
310*4882a593Smuzhiyun 	else
311*4882a593Smuzhiyun 		return s5pc100_get_arm_clk();
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
get_pwm_clk(void)314*4882a593Smuzhiyun unsigned long get_pwm_clk(void)
315*4882a593Smuzhiyun {
316*4882a593Smuzhiyun 	return s5pc1xx_get_pwm_clk();
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
get_uart_clk(int dev_index)319*4882a593Smuzhiyun unsigned long get_uart_clk(int dev_index)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	return s5pc1xx_get_uart_clk(dev_index);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun 
set_mmc_clk(int dev_index,unsigned int div)324*4882a593Smuzhiyun void set_mmc_clk(int dev_index, unsigned int div)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun 	/* Do NOTHING */
327*4882a593Smuzhiyun }
328