xref: /OK3568_Linux_fs/u-boot/arch/arm/mach-at91/armv7/clock.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (C) 2005 David Brownell
5*4882a593Smuzhiyun  * Copyright (C) 2005 Ivan Kokshaysky
6*4882a593Smuzhiyun  * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
7*4882a593Smuzhiyun  * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
8*4882a593Smuzhiyun  * Copyright (C) 2015 Wenyou Yang <wenyou.yang@atmel.com>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <common.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <asm/io.h>
16*4882a593Smuzhiyun #include <asm/arch/hardware.h>
17*4882a593Smuzhiyun #include <asm/arch/at91_pmc.h>
18*4882a593Smuzhiyun #include <asm/arch/clk.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #if !defined(CONFIG_AT91FAMILY)
21*4882a593Smuzhiyun # error You need to define CONFIG_AT91FAMILY in your board config!
22*4882a593Smuzhiyun #endif
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
25*4882a593Smuzhiyun 
at91_css_to_rate(unsigned long css)26*4882a593Smuzhiyun static unsigned long at91_css_to_rate(unsigned long css)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	switch (css) {
29*4882a593Smuzhiyun 	case AT91_PMC_MCKR_CSS_SLOW:
30*4882a593Smuzhiyun 		return CONFIG_SYS_AT91_SLOW_CLOCK;
31*4882a593Smuzhiyun 	case AT91_PMC_MCKR_CSS_MAIN:
32*4882a593Smuzhiyun 		return gd->arch.main_clk_rate_hz;
33*4882a593Smuzhiyun 	case AT91_PMC_MCKR_CSS_PLLA:
34*4882a593Smuzhiyun 		return gd->arch.plla_rate_hz;
35*4882a593Smuzhiyun 	}
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	return 0;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun 
at91_pll_rate(u32 freq,u32 reg)40*4882a593Smuzhiyun static u32 at91_pll_rate(u32 freq, u32 reg)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	unsigned mul, div;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	div = reg & 0xff;
45*4882a593Smuzhiyun 	mul = (reg >> 18) & 0x7f;
46*4882a593Smuzhiyun 	if (div && mul) {
47*4882a593Smuzhiyun 		freq /= div;
48*4882a593Smuzhiyun 		freq *= mul + 1;
49*4882a593Smuzhiyun 	} else {
50*4882a593Smuzhiyun 		freq = 0;
51*4882a593Smuzhiyun 	}
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	return freq;
54*4882a593Smuzhiyun }
55*4882a593Smuzhiyun 
at91_clock_init(unsigned long main_clock)56*4882a593Smuzhiyun int at91_clock_init(unsigned long main_clock)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	unsigned freq, mckr;
59*4882a593Smuzhiyun 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
60*4882a593Smuzhiyun #ifndef CONFIG_SYS_AT91_MAIN_CLOCK
61*4882a593Smuzhiyun 	unsigned tmp;
62*4882a593Smuzhiyun 	/*
63*4882a593Smuzhiyun 	 * When the bootloader initialized the main oscillator correctly,
64*4882a593Smuzhiyun 	 * there's no problem using the cycle counter.  But if it didn't,
65*4882a593Smuzhiyun 	 * or when using oscillator bypass mode, we must be told the speed
66*4882a593Smuzhiyun 	 * of the main clock.
67*4882a593Smuzhiyun 	 */
68*4882a593Smuzhiyun 	if (!main_clock) {
69*4882a593Smuzhiyun 		do {
70*4882a593Smuzhiyun 			tmp = readl(&pmc->mcfr);
71*4882a593Smuzhiyun 		} while (!(tmp & AT91_PMC_MCFR_MAINRDY));
72*4882a593Smuzhiyun 		tmp &= AT91_PMC_MCFR_MAINF_MASK;
73*4882a593Smuzhiyun 		main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
74*4882a593Smuzhiyun 	}
75*4882a593Smuzhiyun #endif
76*4882a593Smuzhiyun 	gd->arch.main_clk_rate_hz = main_clock;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	/* report if PLLA is more than mildly overclocked */
79*4882a593Smuzhiyun 	gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	/*
82*4882a593Smuzhiyun 	 * MCK and CPU derive from one of those primary clocks.
83*4882a593Smuzhiyun 	 * For now, assume this parentage won't change.
84*4882a593Smuzhiyun 	 */
85*4882a593Smuzhiyun 	mckr = readl(&pmc->mckr);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* plla divisor by 2 */
88*4882a593Smuzhiyun 	if (mckr & (1 << 12))
89*4882a593Smuzhiyun 		gd->arch.plla_rate_hz >>= 1;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
92*4882a593Smuzhiyun 	freq = gd->arch.mck_rate_hz;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	/* prescale */
95*4882a593Smuzhiyun 	freq >>= mckr & AT91_PMC_MCKR_PRES_MASK;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	switch (mckr & AT91_PMC_MCKR_MDIV_MASK) {
98*4882a593Smuzhiyun 	case AT91_PMC_MCKR_MDIV_2:
99*4882a593Smuzhiyun 		gd->arch.mck_rate_hz = freq / 2;
100*4882a593Smuzhiyun 		break;
101*4882a593Smuzhiyun 	case AT91_PMC_MCKR_MDIV_3:
102*4882a593Smuzhiyun 		gd->arch.mck_rate_hz = freq / 3;
103*4882a593Smuzhiyun 		break;
104*4882a593Smuzhiyun 	case AT91_PMC_MCKR_MDIV_4:
105*4882a593Smuzhiyun 		gd->arch.mck_rate_hz = freq / 4;
106*4882a593Smuzhiyun 		break;
107*4882a593Smuzhiyun 	default:
108*4882a593Smuzhiyun 		break;
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	gd->arch.cpu_clk_rate_hz = freq;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
at91_plla_init(u32 pllar)116*4882a593Smuzhiyun void at91_plla_init(u32 pllar)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	writel(pllar, &pmc->pllar);
121*4882a593Smuzhiyun 	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
122*4882a593Smuzhiyun 		;
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
at91_mck_init(u32 mckr)125*4882a593Smuzhiyun void at91_mck_init(u32 mckr)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
128*4882a593Smuzhiyun 	u32 tmp;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	tmp = readl(&pmc->mckr);
131*4882a593Smuzhiyun 	tmp &= ~(AT91_PMC_MCKR_CSS_MASK  |
132*4882a593Smuzhiyun 		 AT91_PMC_MCKR_PRES_MASK |
133*4882a593Smuzhiyun 		 AT91_PMC_MCKR_MDIV_MASK |
134*4882a593Smuzhiyun 		 AT91_PMC_MCKR_PLLADIV_2);
135*4882a593Smuzhiyun #ifdef CPU_HAS_H32MXDIV
136*4882a593Smuzhiyun 	tmp &= ~AT91_PMC_MCKR_H32MXDIV;
137*4882a593Smuzhiyun #endif
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	tmp |= mckr & (AT91_PMC_MCKR_CSS_MASK  |
140*4882a593Smuzhiyun 		       AT91_PMC_MCKR_PRES_MASK |
141*4882a593Smuzhiyun 		       AT91_PMC_MCKR_MDIV_MASK |
142*4882a593Smuzhiyun 		       AT91_PMC_MCKR_PLLADIV_2);
143*4882a593Smuzhiyun #ifdef CPU_HAS_H32MXDIV
144*4882a593Smuzhiyun 	tmp |= mckr & AT91_PMC_MCKR_H32MXDIV;
145*4882a593Smuzhiyun #endif
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	writel(tmp, &pmc->mckr);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
150*4882a593Smuzhiyun 		;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
at91_enable_periph_generated_clk(u32 id,u32 clk_source,u32 div)153*4882a593Smuzhiyun int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
156*4882a593Smuzhiyun 	u32 regval, status;
157*4882a593Smuzhiyun 	u32 timeout = 1000;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (id > AT91_PMC_PCR_PID_MASK)
160*4882a593Smuzhiyun 		return -EINVAL;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (div > 0xff)
163*4882a593Smuzhiyun 		return -EINVAL;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (clk_source == GCK_CSS_UPLL_CLK) {
166*4882a593Smuzhiyun 		if (at91_upll_clk_enable())
167*4882a593Smuzhiyun 			return -ENODEV;
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	writel(id, &pmc->pcr);
171*4882a593Smuzhiyun 	regval = readl(&pmc->pcr);
172*4882a593Smuzhiyun 	regval &= ~AT91_PMC_PCR_GCKCSS;
173*4882a593Smuzhiyun 	regval &= ~AT91_PMC_PCR_GCKDIV;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	switch (clk_source) {
176*4882a593Smuzhiyun 	case GCK_CSS_SLOW_CLK:
177*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_SLOW_CLK;
178*4882a593Smuzhiyun 		break;
179*4882a593Smuzhiyun 	case GCK_CSS_MAIN_CLK:
180*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_MAIN_CLK;
181*4882a593Smuzhiyun 		break;
182*4882a593Smuzhiyun 	case GCK_CSS_PLLA_CLK:
183*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_PLLA_CLK;
184*4882a593Smuzhiyun 		break;
185*4882a593Smuzhiyun 	case GCK_CSS_UPLL_CLK:
186*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_UPLL_CLK;
187*4882a593Smuzhiyun 		break;
188*4882a593Smuzhiyun 	case GCK_CSS_MCK_CLK:
189*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_MCK_CLK;
190*4882a593Smuzhiyun 		break;
191*4882a593Smuzhiyun 	case GCK_CSS_AUDIO_CLK:
192*4882a593Smuzhiyun 		regval |= AT91_PMC_PCR_GCKCSS_AUDIO_CLK;
193*4882a593Smuzhiyun 		break;
194*4882a593Smuzhiyun 	default:
195*4882a593Smuzhiyun 		printf("Error GCK clock source selection!\n");
196*4882a593Smuzhiyun 		return -EINVAL;
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	regval |= AT91_PMC_PCR_CMD_WRITE |
200*4882a593Smuzhiyun 		  AT91_PMC_PCR_GCKDIV_(div) |
201*4882a593Smuzhiyun 		  AT91_PMC_PCR_GCKEN;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	writel(regval, &pmc->pcr);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	do {
206*4882a593Smuzhiyun 		udelay(1);
207*4882a593Smuzhiyun 		status = readl(&pmc->sr);
208*4882a593Smuzhiyun 	} while ((!!(--timeout)) && (!(status & AT91_PMC_GCKRDY)));
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (!timeout)
211*4882a593Smuzhiyun 		printf("Timeout waiting for GCK ready!\n");
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	return 0;
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun 
at91_get_periph_generated_clk(u32 id)216*4882a593Smuzhiyun u32 at91_get_periph_generated_clk(u32 id)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
219*4882a593Smuzhiyun 	u32 regval, clk_source, div;
220*4882a593Smuzhiyun 	u32 freq;
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (id > AT91_PMC_PCR_PID_MASK)
223*4882a593Smuzhiyun 		return 0;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	writel(id, &pmc->pcr);
226*4882a593Smuzhiyun 	regval = readl(&pmc->pcr);
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	clk_source = regval & AT91_PMC_PCR_GCKCSS;
229*4882a593Smuzhiyun 	switch (clk_source) {
230*4882a593Smuzhiyun 	case AT91_PMC_PCR_GCKCSS_SLOW_CLK:
231*4882a593Smuzhiyun 		freq = CONFIG_SYS_AT91_SLOW_CLOCK;
232*4882a593Smuzhiyun 		break;
233*4882a593Smuzhiyun 	case AT91_PMC_PCR_GCKCSS_MAIN_CLK:
234*4882a593Smuzhiyun 		freq = gd->arch.main_clk_rate_hz;
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 	case AT91_PMC_PCR_GCKCSS_PLLA_CLK:
237*4882a593Smuzhiyun 		freq = gd->arch.plla_rate_hz;
238*4882a593Smuzhiyun 		break;
239*4882a593Smuzhiyun 	case AT91_PMC_PCR_GCKCSS_UPLL_CLK:
240*4882a593Smuzhiyun 		freq = AT91_UTMI_PLL_CLK_FREQ;
241*4882a593Smuzhiyun 		break;
242*4882a593Smuzhiyun 	case AT91_PMC_PCR_GCKCSS_MCK_CLK:
243*4882a593Smuzhiyun 		freq = gd->arch.mck_rate_hz;
244*4882a593Smuzhiyun 		break;
245*4882a593Smuzhiyun 	default:
246*4882a593Smuzhiyun 		printf("Improper GCK clock source selection!\n");
247*4882a593Smuzhiyun 		freq = 0;
248*4882a593Smuzhiyun 		break;
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	div = ((regval & AT91_PMC_PCR_GCKDIV) >> AT91_PMC_PCR_GCKDIV_OFFSET);
252*4882a593Smuzhiyun 	div += 1;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	return freq / div;
255*4882a593Smuzhiyun }
256