xref: /openbmc/u-boot/arch/arm/mach-s5pc1xx/clock.c (revision 83d290c56fab2d38cd1ab4c4cc7099559c1d5046)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2225f5eecSMinkyu Kang /*
3225f5eecSMinkyu Kang  * Copyright (C) 2009 Samsung Electronics
4225f5eecSMinkyu Kang  * Minkyu Kang <mk7.kang@samsung.com>
5225f5eecSMinkyu Kang  * Heungjun Kim <riverful.kim@samsung.com>
6225f5eecSMinkyu Kang  */
7225f5eecSMinkyu Kang 
8225f5eecSMinkyu Kang #include <common.h>
9225f5eecSMinkyu Kang #include <asm/io.h>
10225f5eecSMinkyu Kang #include <asm/arch/clock.h>
11225f5eecSMinkyu Kang #include <asm/arch/clk.h>
12225f5eecSMinkyu Kang 
13225f5eecSMinkyu Kang #define CLK_M	0
14225f5eecSMinkyu Kang #define CLK_D	1
15225f5eecSMinkyu Kang #define CLK_P	2
16225f5eecSMinkyu Kang 
17225f5eecSMinkyu Kang #ifndef CONFIG_SYS_CLK_FREQ_C100
18225f5eecSMinkyu Kang #define CONFIG_SYS_CLK_FREQ_C100	12000000
19225f5eecSMinkyu Kang #endif
20225f5eecSMinkyu Kang #ifndef CONFIG_SYS_CLK_FREQ_C110
21225f5eecSMinkyu Kang #define CONFIG_SYS_CLK_FREQ_C110	24000000
22225f5eecSMinkyu Kang #endif
23225f5eecSMinkyu Kang 
24225f5eecSMinkyu Kang /* s5pc110: return pll clock frequency */
s5pc100_get_pll_clk(int pllreg)25225f5eecSMinkyu Kang static unsigned long s5pc100_get_pll_clk(int pllreg)
26225f5eecSMinkyu Kang {
27225f5eecSMinkyu Kang 	struct s5pc100_clock *clk =
28225f5eecSMinkyu Kang 		(struct s5pc100_clock *)samsung_get_base_clock();
29225f5eecSMinkyu Kang 	unsigned long r, m, p, s, mask, fout;
30225f5eecSMinkyu Kang 	unsigned int freq;
31225f5eecSMinkyu Kang 
32225f5eecSMinkyu Kang 	switch (pllreg) {
33225f5eecSMinkyu Kang 	case APLL:
34225f5eecSMinkyu Kang 		r = readl(&clk->apll_con);
35225f5eecSMinkyu Kang 		break;
36225f5eecSMinkyu Kang 	case MPLL:
37225f5eecSMinkyu Kang 		r = readl(&clk->mpll_con);
38225f5eecSMinkyu Kang 		break;
39225f5eecSMinkyu Kang 	case EPLL:
40225f5eecSMinkyu Kang 		r = readl(&clk->epll_con);
41225f5eecSMinkyu Kang 		break;
42225f5eecSMinkyu Kang 	case HPLL:
43225f5eecSMinkyu Kang 		r = readl(&clk->hpll_con);
44225f5eecSMinkyu Kang 		break;
45225f5eecSMinkyu Kang 	default:
46225f5eecSMinkyu Kang 		printf("Unsupported PLL (%d)\n", pllreg);
47225f5eecSMinkyu Kang 		return 0;
48225f5eecSMinkyu Kang 	}
49225f5eecSMinkyu Kang 
50225f5eecSMinkyu Kang 	/*
51225f5eecSMinkyu Kang 	 * APLL_CON: MIDV [25:16]
52225f5eecSMinkyu Kang 	 * MPLL_CON: MIDV [23:16]
53225f5eecSMinkyu Kang 	 * EPLL_CON: MIDV [23:16]
54225f5eecSMinkyu Kang 	 * HPLL_CON: MIDV [23:16]
55225f5eecSMinkyu Kang 	 */
56225f5eecSMinkyu Kang 	if (pllreg == APLL)
57225f5eecSMinkyu Kang 		mask = 0x3ff;
58225f5eecSMinkyu Kang 	else
59225f5eecSMinkyu Kang 		mask = 0x0ff;
60225f5eecSMinkyu Kang 
61225f5eecSMinkyu Kang 	m = (r >> 16) & mask;
62225f5eecSMinkyu Kang 
63225f5eecSMinkyu Kang 	/* PDIV [13:8] */
64225f5eecSMinkyu Kang 	p = (r >> 8) & 0x3f;
65225f5eecSMinkyu Kang 	/* SDIV [2:0] */
66225f5eecSMinkyu Kang 	s = r & 0x7;
67225f5eecSMinkyu Kang 
68225f5eecSMinkyu Kang 	/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
69225f5eecSMinkyu Kang 	freq = CONFIG_SYS_CLK_FREQ_C100;
70225f5eecSMinkyu Kang 	fout = m * (freq / (p * (1 << s)));
71225f5eecSMinkyu Kang 
72225f5eecSMinkyu Kang 	return fout;
73225f5eecSMinkyu Kang }
74225f5eecSMinkyu Kang 
75225f5eecSMinkyu Kang /* s5pc100: return pll clock frequency */
s5pc110_get_pll_clk(int pllreg)76225f5eecSMinkyu Kang static unsigned long s5pc110_get_pll_clk(int pllreg)
77225f5eecSMinkyu Kang {
78225f5eecSMinkyu Kang 	struct s5pc110_clock *clk =
79225f5eecSMinkyu Kang 		(struct s5pc110_clock *)samsung_get_base_clock();
80225f5eecSMinkyu Kang 	unsigned long r, m, p, s, mask, fout;
81225f5eecSMinkyu Kang 	unsigned int freq;
82225f5eecSMinkyu Kang 
83225f5eecSMinkyu Kang 	switch (pllreg) {
84225f5eecSMinkyu Kang 	case APLL:
85225f5eecSMinkyu Kang 		r = readl(&clk->apll_con);
86225f5eecSMinkyu Kang 		break;
87225f5eecSMinkyu Kang 	case MPLL:
88225f5eecSMinkyu Kang 		r = readl(&clk->mpll_con);
89225f5eecSMinkyu Kang 		break;
90225f5eecSMinkyu Kang 	case EPLL:
91225f5eecSMinkyu Kang 		r = readl(&clk->epll_con);
92225f5eecSMinkyu Kang 		break;
93225f5eecSMinkyu Kang 	case VPLL:
94225f5eecSMinkyu Kang 		r = readl(&clk->vpll_con);
95225f5eecSMinkyu Kang 		break;
96225f5eecSMinkyu Kang 	default:
97225f5eecSMinkyu Kang 		printf("Unsupported PLL (%d)\n", pllreg);
98225f5eecSMinkyu Kang 		return 0;
99225f5eecSMinkyu Kang 	}
100225f5eecSMinkyu Kang 
101225f5eecSMinkyu Kang 	/*
102225f5eecSMinkyu Kang 	 * APLL_CON: MIDV [25:16]
103225f5eecSMinkyu Kang 	 * MPLL_CON: MIDV [25:16]
104225f5eecSMinkyu Kang 	 * EPLL_CON: MIDV [24:16]
105225f5eecSMinkyu Kang 	 * VPLL_CON: MIDV [24:16]
106225f5eecSMinkyu Kang 	 */
107225f5eecSMinkyu Kang 	if (pllreg == APLL || pllreg == MPLL)
108225f5eecSMinkyu Kang 		mask = 0x3ff;
109225f5eecSMinkyu Kang 	else
110225f5eecSMinkyu Kang 		mask = 0x1ff;
111225f5eecSMinkyu Kang 
112225f5eecSMinkyu Kang 	m = (r >> 16) & mask;
113225f5eecSMinkyu Kang 
114225f5eecSMinkyu Kang 	/* PDIV [13:8] */
115225f5eecSMinkyu Kang 	p = (r >> 8) & 0x3f;
116225f5eecSMinkyu Kang 	/* SDIV [2:0] */
117225f5eecSMinkyu Kang 	s = r & 0x7;
118225f5eecSMinkyu Kang 
119225f5eecSMinkyu Kang 	freq = CONFIG_SYS_CLK_FREQ_C110;
120225f5eecSMinkyu Kang 	if (pllreg == APLL) {
121225f5eecSMinkyu Kang 		if (s < 1)
122225f5eecSMinkyu Kang 			s = 1;
123225f5eecSMinkyu Kang 		/* FOUT = MDIV * FIN / (PDIV * 2^(SDIV - 1)) */
124225f5eecSMinkyu Kang 		fout = m * (freq / (p * (1 << (s - 1))));
125225f5eecSMinkyu Kang 	} else
126225f5eecSMinkyu Kang 		/* FOUT = MDIV * FIN / (PDIV * 2^SDIV) */
127225f5eecSMinkyu Kang 		fout = m * (freq / (p * (1 << s)));
128225f5eecSMinkyu Kang 
129225f5eecSMinkyu Kang 	return fout;
130225f5eecSMinkyu Kang }
131225f5eecSMinkyu Kang 
132225f5eecSMinkyu Kang /* s5pc110: return ARM clock frequency */
s5pc110_get_arm_clk(void)133225f5eecSMinkyu Kang static unsigned long s5pc110_get_arm_clk(void)
134225f5eecSMinkyu Kang {
135225f5eecSMinkyu Kang 	struct s5pc110_clock *clk =
136225f5eecSMinkyu Kang 		(struct s5pc110_clock *)samsung_get_base_clock();
137225f5eecSMinkyu Kang 	unsigned long div;
138225f5eecSMinkyu Kang 	unsigned long dout_apll, armclk;
139225f5eecSMinkyu Kang 	unsigned int apll_ratio;
140225f5eecSMinkyu Kang 
141225f5eecSMinkyu Kang 	div = readl(&clk->div0);
142225f5eecSMinkyu Kang 
143225f5eecSMinkyu Kang 	/* APLL_RATIO: [2:0] */
144225f5eecSMinkyu Kang 	apll_ratio = div & 0x7;
145225f5eecSMinkyu Kang 
146225f5eecSMinkyu Kang 	dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
147225f5eecSMinkyu Kang 	armclk = dout_apll;
148225f5eecSMinkyu Kang 
149225f5eecSMinkyu Kang 	return armclk;
150225f5eecSMinkyu Kang }
151225f5eecSMinkyu Kang 
152225f5eecSMinkyu Kang /* s5pc100: return ARM clock frequency */
s5pc100_get_arm_clk(void)153225f5eecSMinkyu Kang static unsigned long s5pc100_get_arm_clk(void)
154225f5eecSMinkyu Kang {
155225f5eecSMinkyu Kang 	struct s5pc100_clock *clk =
156225f5eecSMinkyu Kang 		(struct s5pc100_clock *)samsung_get_base_clock();
157225f5eecSMinkyu Kang 	unsigned long div;
158225f5eecSMinkyu Kang 	unsigned long dout_apll, armclk;
159225f5eecSMinkyu Kang 	unsigned int apll_ratio, arm_ratio;
160225f5eecSMinkyu Kang 
161225f5eecSMinkyu Kang 	div = readl(&clk->div0);
162225f5eecSMinkyu Kang 
163225f5eecSMinkyu Kang 	/* ARM_RATIO: [6:4] */
164225f5eecSMinkyu Kang 	arm_ratio = (div >> 4) & 0x7;
165225f5eecSMinkyu Kang 	/* APLL_RATIO: [0] */
166225f5eecSMinkyu Kang 	apll_ratio = div & 0x1;
167225f5eecSMinkyu Kang 
168225f5eecSMinkyu Kang 	dout_apll = get_pll_clk(APLL) / (apll_ratio + 1);
169225f5eecSMinkyu Kang 	armclk = dout_apll / (arm_ratio + 1);
170225f5eecSMinkyu Kang 
171225f5eecSMinkyu Kang 	return armclk;
172225f5eecSMinkyu Kang }
173225f5eecSMinkyu Kang 
174225f5eecSMinkyu Kang /* s5pc100: return HCLKD0 frequency */
get_hclk(void)175225f5eecSMinkyu Kang static unsigned long get_hclk(void)
176225f5eecSMinkyu Kang {
177225f5eecSMinkyu Kang 	struct s5pc100_clock *clk =
178225f5eecSMinkyu Kang 		(struct s5pc100_clock *)samsung_get_base_clock();
179225f5eecSMinkyu Kang 	unsigned long hclkd0;
180225f5eecSMinkyu Kang 	uint div, d0_bus_ratio;
181225f5eecSMinkyu Kang 
182225f5eecSMinkyu Kang 	div = readl(&clk->div0);
183225f5eecSMinkyu Kang 	/* D0_BUS_RATIO: [10:8] */
184225f5eecSMinkyu Kang 	d0_bus_ratio = (div >> 8) & 0x7;
185225f5eecSMinkyu Kang 
186225f5eecSMinkyu Kang 	hclkd0 = get_arm_clk() / (d0_bus_ratio + 1);
187225f5eecSMinkyu Kang 
188225f5eecSMinkyu Kang 	return hclkd0;
189225f5eecSMinkyu Kang }
190225f5eecSMinkyu Kang 
191225f5eecSMinkyu Kang /* s5pc100: return PCLKD1 frequency */
get_pclkd1(void)192225f5eecSMinkyu Kang static unsigned long get_pclkd1(void)
193225f5eecSMinkyu Kang {
194225f5eecSMinkyu Kang 	struct s5pc100_clock *clk =
195225f5eecSMinkyu Kang 		(struct s5pc100_clock *)samsung_get_base_clock();
196225f5eecSMinkyu Kang 	unsigned long d1_bus, pclkd1;
197225f5eecSMinkyu Kang 	uint div, d1_bus_ratio, pclkd1_ratio;
198225f5eecSMinkyu Kang 
199225f5eecSMinkyu Kang 	div = readl(&clk->div0);
200225f5eecSMinkyu Kang 	/* D1_BUS_RATIO: [14:12] */
201225f5eecSMinkyu Kang 	d1_bus_ratio = (div >> 12) & 0x7;
202225f5eecSMinkyu Kang 	/* PCLKD1_RATIO: [18:16] */
203225f5eecSMinkyu Kang 	pclkd1_ratio = (div >> 16) & 0x7;
204225f5eecSMinkyu Kang 
205225f5eecSMinkyu Kang 	/* ASYNC Mode */
206225f5eecSMinkyu Kang 	d1_bus = get_pll_clk(MPLL) / (d1_bus_ratio + 1);
207225f5eecSMinkyu Kang 	pclkd1 = d1_bus / (pclkd1_ratio + 1);
208225f5eecSMinkyu Kang 
209225f5eecSMinkyu Kang 	return pclkd1;
210225f5eecSMinkyu Kang }
211225f5eecSMinkyu Kang 
212225f5eecSMinkyu Kang /* s5pc110: return HCLKs frequency */
get_hclk_sys(int dom)213225f5eecSMinkyu Kang static unsigned long get_hclk_sys(int dom)
214225f5eecSMinkyu Kang {
215225f5eecSMinkyu Kang 	struct s5pc110_clock *clk =
216225f5eecSMinkyu Kang 		(struct s5pc110_clock *)samsung_get_base_clock();
217225f5eecSMinkyu Kang 	unsigned long hclk;
218225f5eecSMinkyu Kang 	unsigned int div;
219225f5eecSMinkyu Kang 	unsigned int offset;
220225f5eecSMinkyu Kang 	unsigned int hclk_sys_ratio;
221225f5eecSMinkyu Kang 
222225f5eecSMinkyu Kang 	if (dom == CLK_M)
223225f5eecSMinkyu Kang 		return get_hclk();
224225f5eecSMinkyu Kang 
225225f5eecSMinkyu Kang 	div = readl(&clk->div0);
226225f5eecSMinkyu Kang 
227225f5eecSMinkyu Kang 	/*
228225f5eecSMinkyu Kang 	 * HCLK_MSYS_RATIO: [10:8]
229225f5eecSMinkyu Kang 	 * HCLK_DSYS_RATIO: [19:16]
230225f5eecSMinkyu Kang 	 * HCLK_PSYS_RATIO: [27:24]
231225f5eecSMinkyu Kang 	 */
232225f5eecSMinkyu Kang 	offset = 8 + (dom << 0x3);
233225f5eecSMinkyu Kang 
234225f5eecSMinkyu Kang 	hclk_sys_ratio = (div >> offset) & 0xf;
235225f5eecSMinkyu Kang 
236225f5eecSMinkyu Kang 	hclk = get_pll_clk(MPLL) / (hclk_sys_ratio + 1);
237225f5eecSMinkyu Kang 
238225f5eecSMinkyu Kang 	return hclk;
239225f5eecSMinkyu Kang }
240225f5eecSMinkyu Kang 
241225f5eecSMinkyu Kang /* s5pc110: return PCLKs frequency */
get_pclk_sys(int dom)242225f5eecSMinkyu Kang static unsigned long get_pclk_sys(int dom)
243225f5eecSMinkyu Kang {
244225f5eecSMinkyu Kang 	struct s5pc110_clock *clk =
245225f5eecSMinkyu Kang 		(struct s5pc110_clock *)samsung_get_base_clock();
246225f5eecSMinkyu Kang 	unsigned long pclk;
247225f5eecSMinkyu Kang 	unsigned int div;
248225f5eecSMinkyu Kang 	unsigned int offset;
249225f5eecSMinkyu Kang 	unsigned int pclk_sys_ratio;
250225f5eecSMinkyu Kang 
251225f5eecSMinkyu Kang 	div = readl(&clk->div0);
252225f5eecSMinkyu Kang 
253225f5eecSMinkyu Kang 	/*
254225f5eecSMinkyu Kang 	 * PCLK_MSYS_RATIO: [14:12]
255225f5eecSMinkyu Kang 	 * PCLK_DSYS_RATIO: [22:20]
256225f5eecSMinkyu Kang 	 * PCLK_PSYS_RATIO: [30:28]
257225f5eecSMinkyu Kang 	 */
258225f5eecSMinkyu Kang 	offset = 12 + (dom << 0x3);
259225f5eecSMinkyu Kang 
260225f5eecSMinkyu Kang 	pclk_sys_ratio = (div >> offset) & 0x7;
261225f5eecSMinkyu Kang 
262225f5eecSMinkyu Kang 	pclk = get_hclk_sys(dom) / (pclk_sys_ratio + 1);
263225f5eecSMinkyu Kang 
264225f5eecSMinkyu Kang 	return pclk;
265225f5eecSMinkyu Kang }
266225f5eecSMinkyu Kang 
267225f5eecSMinkyu Kang /* s5pc110: return peripheral clock frequency */
s5pc110_get_pclk(void)268225f5eecSMinkyu Kang static unsigned long s5pc110_get_pclk(void)
269225f5eecSMinkyu Kang {
270225f5eecSMinkyu Kang 	return get_pclk_sys(CLK_P);
271225f5eecSMinkyu Kang }
272225f5eecSMinkyu Kang 
273225f5eecSMinkyu Kang /* s5pc100: return peripheral clock frequency */
s5pc100_get_pclk(void)274225f5eecSMinkyu Kang static unsigned long s5pc100_get_pclk(void)
275225f5eecSMinkyu Kang {
276225f5eecSMinkyu Kang 	return get_pclkd1();
277225f5eecSMinkyu Kang }
278225f5eecSMinkyu Kang 
279225f5eecSMinkyu Kang /* s5pc1xx: return uart clock frequency */
s5pc1xx_get_uart_clk(int dev_index)280225f5eecSMinkyu Kang static unsigned long s5pc1xx_get_uart_clk(int dev_index)
281225f5eecSMinkyu Kang {
282225f5eecSMinkyu Kang 	if (cpu_is_s5pc110())
283225f5eecSMinkyu Kang 		return s5pc110_get_pclk();
284225f5eecSMinkyu Kang 	else
285225f5eecSMinkyu Kang 		return s5pc100_get_pclk();
286225f5eecSMinkyu Kang }
287225f5eecSMinkyu Kang 
288225f5eecSMinkyu Kang /* s5pc1xx: return pwm clock frequency */
s5pc1xx_get_pwm_clk(void)289225f5eecSMinkyu Kang static unsigned long s5pc1xx_get_pwm_clk(void)
290225f5eecSMinkyu Kang {
291225f5eecSMinkyu Kang 	if (cpu_is_s5pc110())
292225f5eecSMinkyu Kang 		return s5pc110_get_pclk();
293225f5eecSMinkyu Kang 	else
294225f5eecSMinkyu Kang 		return s5pc100_get_pclk();
295225f5eecSMinkyu Kang }
296225f5eecSMinkyu Kang 
get_pll_clk(int pllreg)297225f5eecSMinkyu Kang unsigned long get_pll_clk(int pllreg)
298225f5eecSMinkyu Kang {
299225f5eecSMinkyu Kang 	if (cpu_is_s5pc110())
300225f5eecSMinkyu Kang 		return s5pc110_get_pll_clk(pllreg);
301225f5eecSMinkyu Kang 	else
302225f5eecSMinkyu Kang 		return s5pc100_get_pll_clk(pllreg);
303225f5eecSMinkyu Kang }
304225f5eecSMinkyu Kang 
get_arm_clk(void)305225f5eecSMinkyu Kang unsigned long get_arm_clk(void)
306225f5eecSMinkyu Kang {
307225f5eecSMinkyu Kang 	if (cpu_is_s5pc110())
308225f5eecSMinkyu Kang 		return s5pc110_get_arm_clk();
309225f5eecSMinkyu Kang 	else
310225f5eecSMinkyu Kang 		return s5pc100_get_arm_clk();
311225f5eecSMinkyu Kang }
312225f5eecSMinkyu Kang 
get_pwm_clk(void)313225f5eecSMinkyu Kang unsigned long get_pwm_clk(void)
314225f5eecSMinkyu Kang {
315225f5eecSMinkyu Kang 	return s5pc1xx_get_pwm_clk();
316225f5eecSMinkyu Kang }
317225f5eecSMinkyu Kang 
get_uart_clk(int dev_index)318225f5eecSMinkyu Kang unsigned long get_uart_clk(int dev_index)
319225f5eecSMinkyu Kang {
320225f5eecSMinkyu Kang 	return s5pc1xx_get_uart_clk(dev_index);
321225f5eecSMinkyu Kang }
322225f5eecSMinkyu Kang 
set_mmc_clk(int dev_index,unsigned int div)323225f5eecSMinkyu Kang void set_mmc_clk(int dev_index, unsigned int div)
324225f5eecSMinkyu Kang {
325225f5eecSMinkyu Kang 	/* Do NOTHING */
326225f5eecSMinkyu Kang }
327