xref: /rk3399_rockchip-uboot/arch/arm/mach-at91/armv7/clock.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
162011840SMasahiro Yamada /*
262011840SMasahiro Yamada  * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
362011840SMasahiro Yamada  *
462011840SMasahiro Yamada  * Copyright (C) 2005 David Brownell
562011840SMasahiro Yamada  * Copyright (C) 2005 Ivan Kokshaysky
662011840SMasahiro Yamada  * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
762011840SMasahiro Yamada  * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
8c1900055SWenyou Yang  * Copyright (C) 2015 Wenyou Yang <wenyou.yang@atmel.com>
962011840SMasahiro Yamada  *
1062011840SMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
1162011840SMasahiro Yamada  */
1262011840SMasahiro Yamada 
1362011840SMasahiro Yamada #include <common.h>
14*1221ce45SMasahiro Yamada #include <linux/errno.h>
1562011840SMasahiro Yamada #include <asm/io.h>
1662011840SMasahiro Yamada #include <asm/arch/hardware.h>
1762011840SMasahiro Yamada #include <asm/arch/at91_pmc.h>
1862011840SMasahiro Yamada #include <asm/arch/clk.h>
1962011840SMasahiro Yamada 
2062011840SMasahiro Yamada #if !defined(CONFIG_AT91FAMILY)
2162011840SMasahiro Yamada # error You need to define CONFIG_AT91FAMILY in your board config!
2262011840SMasahiro Yamada #endif
2362011840SMasahiro Yamada 
2462011840SMasahiro Yamada DECLARE_GLOBAL_DATA_PTR;
2562011840SMasahiro Yamada 
at91_css_to_rate(unsigned long css)2662011840SMasahiro Yamada static unsigned long at91_css_to_rate(unsigned long css)
2762011840SMasahiro Yamada {
2862011840SMasahiro Yamada 	switch (css) {
2962011840SMasahiro Yamada 	case AT91_PMC_MCKR_CSS_SLOW:
3062011840SMasahiro Yamada 		return CONFIG_SYS_AT91_SLOW_CLOCK;
3162011840SMasahiro Yamada 	case AT91_PMC_MCKR_CSS_MAIN:
3262011840SMasahiro Yamada 		return gd->arch.main_clk_rate_hz;
3362011840SMasahiro Yamada 	case AT91_PMC_MCKR_CSS_PLLA:
3462011840SMasahiro Yamada 		return gd->arch.plla_rate_hz;
3562011840SMasahiro Yamada 	}
3662011840SMasahiro Yamada 
3762011840SMasahiro Yamada 	return 0;
3862011840SMasahiro Yamada }
3962011840SMasahiro Yamada 
at91_pll_rate(u32 freq,u32 reg)4062011840SMasahiro Yamada static u32 at91_pll_rate(u32 freq, u32 reg)
4162011840SMasahiro Yamada {
4262011840SMasahiro Yamada 	unsigned mul, div;
4362011840SMasahiro Yamada 
4462011840SMasahiro Yamada 	div = reg & 0xff;
4562011840SMasahiro Yamada 	mul = (reg >> 18) & 0x7f;
4662011840SMasahiro Yamada 	if (div && mul) {
4762011840SMasahiro Yamada 		freq /= div;
4862011840SMasahiro Yamada 		freq *= mul + 1;
4962011840SMasahiro Yamada 	} else {
5062011840SMasahiro Yamada 		freq = 0;
5162011840SMasahiro Yamada 	}
5262011840SMasahiro Yamada 
5362011840SMasahiro Yamada 	return freq;
5462011840SMasahiro Yamada }
5562011840SMasahiro Yamada 
at91_clock_init(unsigned long main_clock)5662011840SMasahiro Yamada int at91_clock_init(unsigned long main_clock)
5762011840SMasahiro Yamada {
5862011840SMasahiro Yamada 	unsigned freq, mckr;
5962011840SMasahiro Yamada 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
6062011840SMasahiro Yamada #ifndef CONFIG_SYS_AT91_MAIN_CLOCK
6162011840SMasahiro Yamada 	unsigned tmp;
6262011840SMasahiro Yamada 	/*
6362011840SMasahiro Yamada 	 * When the bootloader initialized the main oscillator correctly,
6462011840SMasahiro Yamada 	 * there's no problem using the cycle counter.  But if it didn't,
6562011840SMasahiro Yamada 	 * or when using oscillator bypass mode, we must be told the speed
6662011840SMasahiro Yamada 	 * of the main clock.
6762011840SMasahiro Yamada 	 */
6862011840SMasahiro Yamada 	if (!main_clock) {
6962011840SMasahiro Yamada 		do {
7062011840SMasahiro Yamada 			tmp = readl(&pmc->mcfr);
7162011840SMasahiro Yamada 		} while (!(tmp & AT91_PMC_MCFR_MAINRDY));
7262011840SMasahiro Yamada 		tmp &= AT91_PMC_MCFR_MAINF_MASK;
7362011840SMasahiro Yamada 		main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
7462011840SMasahiro Yamada 	}
7562011840SMasahiro Yamada #endif
7662011840SMasahiro Yamada 	gd->arch.main_clk_rate_hz = main_clock;
7762011840SMasahiro Yamada 
7862011840SMasahiro Yamada 	/* report if PLLA is more than mildly overclocked */
7962011840SMasahiro Yamada 	gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
8062011840SMasahiro Yamada 
8162011840SMasahiro Yamada 	/*
8262011840SMasahiro Yamada 	 * MCK and CPU derive from one of those primary clocks.
8362011840SMasahiro Yamada 	 * For now, assume this parentage won't change.
8462011840SMasahiro Yamada 	 */
8562011840SMasahiro Yamada 	mckr = readl(&pmc->mckr);
8662011840SMasahiro Yamada 
8762011840SMasahiro Yamada 	/* plla divisor by 2 */
8862011840SMasahiro Yamada 	if (mckr & (1 << 12))
8962011840SMasahiro Yamada 		gd->arch.plla_rate_hz >>= 1;
9062011840SMasahiro Yamada 
9162011840SMasahiro Yamada 	gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
9262011840SMasahiro Yamada 	freq = gd->arch.mck_rate_hz;
9362011840SMasahiro Yamada 
9462011840SMasahiro Yamada 	/* prescale */
9562011840SMasahiro Yamada 	freq >>= mckr & AT91_PMC_MCKR_PRES_MASK;
9662011840SMasahiro Yamada 
9762011840SMasahiro Yamada 	switch (mckr & AT91_PMC_MCKR_MDIV_MASK) {
9862011840SMasahiro Yamada 	case AT91_PMC_MCKR_MDIV_2:
9962011840SMasahiro Yamada 		gd->arch.mck_rate_hz = freq / 2;
10062011840SMasahiro Yamada 		break;
10162011840SMasahiro Yamada 	case AT91_PMC_MCKR_MDIV_3:
10262011840SMasahiro Yamada 		gd->arch.mck_rate_hz = freq / 3;
10362011840SMasahiro Yamada 		break;
10462011840SMasahiro Yamada 	case AT91_PMC_MCKR_MDIV_4:
10562011840SMasahiro Yamada 		gd->arch.mck_rate_hz = freq / 4;
10662011840SMasahiro Yamada 		break;
10762011840SMasahiro Yamada 	default:
10862011840SMasahiro Yamada 		break;
10962011840SMasahiro Yamada 	}
11062011840SMasahiro Yamada 
11162011840SMasahiro Yamada 	gd->arch.cpu_clk_rate_hz = freq;
11262011840SMasahiro Yamada 
11362011840SMasahiro Yamada 	return 0;
11462011840SMasahiro Yamada }
11562011840SMasahiro Yamada 
at91_plla_init(u32 pllar)11662011840SMasahiro Yamada void at91_plla_init(u32 pllar)
11762011840SMasahiro Yamada {
11862011840SMasahiro Yamada 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
11962011840SMasahiro Yamada 
12062011840SMasahiro Yamada 	writel(pllar, &pmc->pllar);
12162011840SMasahiro Yamada 	while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
12262011840SMasahiro Yamada 		;
12362011840SMasahiro Yamada }
12462011840SMasahiro Yamada 
at91_mck_init(u32 mckr)12562011840SMasahiro Yamada void at91_mck_init(u32 mckr)
12662011840SMasahiro Yamada {
12762011840SMasahiro Yamada 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
12862011840SMasahiro Yamada 	u32 tmp;
12962011840SMasahiro Yamada 
13062011840SMasahiro Yamada 	tmp = readl(&pmc->mckr);
13162011840SMasahiro Yamada 	tmp &= ~(AT91_PMC_MCKR_CSS_MASK  |
13262011840SMasahiro Yamada 		 AT91_PMC_MCKR_PRES_MASK |
13362011840SMasahiro Yamada 		 AT91_PMC_MCKR_MDIV_MASK |
13462011840SMasahiro Yamada 		 AT91_PMC_MCKR_PLLADIV_2);
13562011840SMasahiro Yamada #ifdef CPU_HAS_H32MXDIV
13662011840SMasahiro Yamada 	tmp &= ~AT91_PMC_MCKR_H32MXDIV;
13762011840SMasahiro Yamada #endif
13862011840SMasahiro Yamada 
13962011840SMasahiro Yamada 	tmp |= mckr & (AT91_PMC_MCKR_CSS_MASK  |
14062011840SMasahiro Yamada 		       AT91_PMC_MCKR_PRES_MASK |
14162011840SMasahiro Yamada 		       AT91_PMC_MCKR_MDIV_MASK |
14262011840SMasahiro Yamada 		       AT91_PMC_MCKR_PLLADIV_2);
14362011840SMasahiro Yamada #ifdef CPU_HAS_H32MXDIV
14462011840SMasahiro Yamada 	tmp |= mckr & AT91_PMC_MCKR_H32MXDIV;
14562011840SMasahiro Yamada #endif
14662011840SMasahiro Yamada 
14762011840SMasahiro Yamada 	writel(tmp, &pmc->mckr);
14862011840SMasahiro Yamada 
14962011840SMasahiro Yamada 	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
15062011840SMasahiro Yamada 		;
15162011840SMasahiro Yamada }
15262011840SMasahiro Yamada 
at91_enable_periph_generated_clk(u32 id,u32 clk_source,u32 div)153c1900055SWenyou Yang int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div)
154c1900055SWenyou Yang {
155c1900055SWenyou Yang 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
156c1900055SWenyou Yang 	u32 regval, status;
157c1900055SWenyou Yang 	u32 timeout = 1000;
158c1900055SWenyou Yang 
159c1900055SWenyou Yang 	if (id > AT91_PMC_PCR_PID_MASK)
160c1900055SWenyou Yang 		return -EINVAL;
161c1900055SWenyou Yang 
162c1900055SWenyou Yang 	if (div > 0xff)
163c1900055SWenyou Yang 		return -EINVAL;
164c1900055SWenyou Yang 
1654adf6a71SWenyou Yang 	if (clk_source == GCK_CSS_UPLL_CLK) {
1664adf6a71SWenyou Yang 		if (at91_upll_clk_enable())
1674adf6a71SWenyou Yang 			return -ENODEV;
1684adf6a71SWenyou Yang 	}
1694adf6a71SWenyou Yang 
170c1900055SWenyou Yang 	writel(id, &pmc->pcr);
171c1900055SWenyou Yang 	regval = readl(&pmc->pcr);
172c1900055SWenyou Yang 	regval &= ~AT91_PMC_PCR_GCKCSS;
173c1900055SWenyou Yang 	regval &= ~AT91_PMC_PCR_GCKDIV;
174c1900055SWenyou Yang 
175c1900055SWenyou Yang 	switch (clk_source) {
176c1900055SWenyou Yang 	case GCK_CSS_SLOW_CLK:
177c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_SLOW_CLK;
178c1900055SWenyou Yang 		break;
179c1900055SWenyou Yang 	case GCK_CSS_MAIN_CLK:
180c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_MAIN_CLK;
181c1900055SWenyou Yang 		break;
182c1900055SWenyou Yang 	case GCK_CSS_PLLA_CLK:
183c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_PLLA_CLK;
184c1900055SWenyou Yang 		break;
185c1900055SWenyou Yang 	case GCK_CSS_UPLL_CLK:
186c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_UPLL_CLK;
187c1900055SWenyou Yang 		break;
188c1900055SWenyou Yang 	case GCK_CSS_MCK_CLK:
189c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_MCK_CLK;
190c1900055SWenyou Yang 		break;
191c1900055SWenyou Yang 	case GCK_CSS_AUDIO_CLK:
192c1900055SWenyou Yang 		regval |= AT91_PMC_PCR_GCKCSS_AUDIO_CLK;
193c1900055SWenyou Yang 		break;
194c1900055SWenyou Yang 	default:
195c1900055SWenyou Yang 		printf("Error GCK clock source selection!\n");
196c1900055SWenyou Yang 		return -EINVAL;
197c1900055SWenyou Yang 	}
198c1900055SWenyou Yang 
199c1900055SWenyou Yang 	regval |= AT91_PMC_PCR_CMD_WRITE |
200c1900055SWenyou Yang 		  AT91_PMC_PCR_GCKDIV_(div) |
201c1900055SWenyou Yang 		  AT91_PMC_PCR_GCKEN;
202c1900055SWenyou Yang 
203c1900055SWenyou Yang 	writel(regval, &pmc->pcr);
204c1900055SWenyou Yang 
205c1900055SWenyou Yang 	do {
206c1900055SWenyou Yang 		udelay(1);
207c1900055SWenyou Yang 		status = readl(&pmc->sr);
208c1900055SWenyou Yang 	} while ((!!(--timeout)) && (!(status & AT91_PMC_GCKRDY)));
209c1900055SWenyou Yang 
210c1900055SWenyou Yang 	if (!timeout)
211c1900055SWenyou Yang 		printf("Timeout waiting for GCK ready!\n");
212c1900055SWenyou Yang 
213c1900055SWenyou Yang 	return 0;
214c1900055SWenyou Yang }
215c1900055SWenyou Yang 
at91_get_periph_generated_clk(u32 id)216c1900055SWenyou Yang u32 at91_get_periph_generated_clk(u32 id)
217c1900055SWenyou Yang {
218c1900055SWenyou Yang 	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
219c1900055SWenyou Yang 	u32 regval, clk_source, div;
220c1900055SWenyou Yang 	u32 freq;
221c1900055SWenyou Yang 
222c1900055SWenyou Yang 	if (id > AT91_PMC_PCR_PID_MASK)
223c1900055SWenyou Yang 		return 0;
224c1900055SWenyou Yang 
225c1900055SWenyou Yang 	writel(id, &pmc->pcr);
226c1900055SWenyou Yang 	regval = readl(&pmc->pcr);
227c1900055SWenyou Yang 
228c1900055SWenyou Yang 	clk_source = regval & AT91_PMC_PCR_GCKCSS;
229c1900055SWenyou Yang 	switch (clk_source) {
230c1900055SWenyou Yang 	case AT91_PMC_PCR_GCKCSS_SLOW_CLK:
231c1900055SWenyou Yang 		freq = CONFIG_SYS_AT91_SLOW_CLOCK;
232c1900055SWenyou Yang 		break;
233c1900055SWenyou Yang 	case AT91_PMC_PCR_GCKCSS_MAIN_CLK:
234c1900055SWenyou Yang 		freq = gd->arch.main_clk_rate_hz;
235c1900055SWenyou Yang 		break;
236c1900055SWenyou Yang 	case AT91_PMC_PCR_GCKCSS_PLLA_CLK:
237c1900055SWenyou Yang 		freq = gd->arch.plla_rate_hz;
238c1900055SWenyou Yang 		break;
2397a91e1a3SWenyou Yang 	case AT91_PMC_PCR_GCKCSS_UPLL_CLK:
2407a91e1a3SWenyou Yang 		freq = AT91_UTMI_PLL_CLK_FREQ;
2417a91e1a3SWenyou Yang 		break;
2427a91e1a3SWenyou Yang 	case AT91_PMC_PCR_GCKCSS_MCK_CLK:
2437a91e1a3SWenyou Yang 		freq = gd->arch.mck_rate_hz;
2447a91e1a3SWenyou Yang 		break;
245c1900055SWenyou Yang 	default:
246c1900055SWenyou Yang 		printf("Improper GCK clock source selection!\n");
247c1900055SWenyou Yang 		freq = 0;
248c1900055SWenyou Yang 		break;
249c1900055SWenyou Yang 	}
250c1900055SWenyou Yang 
251c1900055SWenyou Yang 	div = ((regval & AT91_PMC_PCR_GCKDIV) >> AT91_PMC_PCR_GCKDIV_OFFSET);
252c1900055SWenyou Yang 	div += 1;
253c1900055SWenyou Yang 
254c1900055SWenyou Yang 	return freq / div;
255c1900055SWenyou Yang }
256