1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Copyright (C) 2011 Andreas Bießmann
5*4882a593Smuzhiyun * Copyright (C) 2005 David Brownell
6*4882a593Smuzhiyun * Copyright (C) 2005 Ivan Kokshaysky
7*4882a593Smuzhiyun * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun #include <common.h>
12*4882a593Smuzhiyun #include <asm/io.h>
13*4882a593Smuzhiyun #include <asm/arch/hardware.h>
14*4882a593Smuzhiyun #include <asm/arch/at91_pmc.h>
15*4882a593Smuzhiyun #include <asm/arch/clk.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #if !defined(CONFIG_AT91FAMILY)
18*4882a593Smuzhiyun # error You need to define CONFIG_AT91FAMILY in your board config!
19*4882a593Smuzhiyun #endif
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define EN_PLLB_TIMEOUT 500
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun DECLARE_GLOBAL_DATA_PTR;
24*4882a593Smuzhiyun
at91_css_to_rate(unsigned long css)25*4882a593Smuzhiyun static unsigned long at91_css_to_rate(unsigned long css)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun switch (css) {
28*4882a593Smuzhiyun case AT91_PMC_MCKR_CSS_SLOW:
29*4882a593Smuzhiyun return CONFIG_SYS_AT91_SLOW_CLOCK;
30*4882a593Smuzhiyun case AT91_PMC_MCKR_CSS_MAIN:
31*4882a593Smuzhiyun return gd->arch.main_clk_rate_hz;
32*4882a593Smuzhiyun case AT91_PMC_MCKR_CSS_PLLA:
33*4882a593Smuzhiyun return gd->arch.plla_rate_hz;
34*4882a593Smuzhiyun case AT91_PMC_MCKR_CSS_PLLB:
35*4882a593Smuzhiyun return gd->arch.pllb_rate_hz;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun return 0;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun #ifdef CONFIG_USB_ATMEL
at91_pll_calc(unsigned main_freq,unsigned out_freq)42*4882a593Smuzhiyun static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun unsigned i, div = 0, mul = 0, diff = 1 << 30;
45*4882a593Smuzhiyun unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* PLL output max 240 MHz (or 180 MHz per errata) */
48*4882a593Smuzhiyun if (out_freq > 240000000)
49*4882a593Smuzhiyun goto fail;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun for (i = 1; i < 256; i++) {
52*4882a593Smuzhiyun int diff1;
53*4882a593Smuzhiyun unsigned input, mul1;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /*
56*4882a593Smuzhiyun * PLL input between 1MHz and 32MHz per spec, but lower
57*4882a593Smuzhiyun * frequences seem necessary in some cases so allow 100K.
58*4882a593Smuzhiyun * Warning: some newer products need 2MHz min.
59*4882a593Smuzhiyun */
60*4882a593Smuzhiyun input = main_freq / i;
61*4882a593Smuzhiyun if (input < 100000)
62*4882a593Smuzhiyun continue;
63*4882a593Smuzhiyun if (input > 32000000)
64*4882a593Smuzhiyun continue;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun mul1 = out_freq / input;
67*4882a593Smuzhiyun if (mul1 > 2048)
68*4882a593Smuzhiyun continue;
69*4882a593Smuzhiyun if (mul1 < 2)
70*4882a593Smuzhiyun goto fail;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun diff1 = out_freq - input * mul1;
73*4882a593Smuzhiyun if (diff1 < 0)
74*4882a593Smuzhiyun diff1 = -diff1;
75*4882a593Smuzhiyun if (diff > diff1) {
76*4882a593Smuzhiyun diff = diff1;
77*4882a593Smuzhiyun div = i;
78*4882a593Smuzhiyun mul = mul1;
79*4882a593Smuzhiyun if (diff == 0)
80*4882a593Smuzhiyun break;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun if (i == 256 && diff > (out_freq >> 5))
84*4882a593Smuzhiyun goto fail;
85*4882a593Smuzhiyun return ret | ((mul - 1) << 16) | div;
86*4882a593Smuzhiyun fail:
87*4882a593Smuzhiyun return 0;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun #endif
90*4882a593Smuzhiyun
at91_pll_rate(u32 freq,u32 reg)91*4882a593Smuzhiyun static u32 at91_pll_rate(u32 freq, u32 reg)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun unsigned mul, div;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun div = reg & 0xff;
96*4882a593Smuzhiyun mul = (reg >> 16) & 0x7ff;
97*4882a593Smuzhiyun if (div && mul) {
98*4882a593Smuzhiyun freq /= div;
99*4882a593Smuzhiyun freq *= mul + 1;
100*4882a593Smuzhiyun } else
101*4882a593Smuzhiyun freq = 0;
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun return freq;
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun
at91_clock_init(unsigned long main_clock)106*4882a593Smuzhiyun int at91_clock_init(unsigned long main_clock)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun unsigned freq, mckr;
109*4882a593Smuzhiyun at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
110*4882a593Smuzhiyun #ifndef CONFIG_SYS_AT91_MAIN_CLOCK
111*4882a593Smuzhiyun unsigned tmp;
112*4882a593Smuzhiyun /*
113*4882a593Smuzhiyun * When the bootloader initialized the main oscillator correctly,
114*4882a593Smuzhiyun * there's no problem using the cycle counter. But if it didn't,
115*4882a593Smuzhiyun * or when using oscillator bypass mode, we must be told the speed
116*4882a593Smuzhiyun * of the main clock.
117*4882a593Smuzhiyun */
118*4882a593Smuzhiyun if (!main_clock) {
119*4882a593Smuzhiyun do {
120*4882a593Smuzhiyun tmp = readl(&pmc->mcfr);
121*4882a593Smuzhiyun } while (!(tmp & AT91_PMC_MCFR_MAINRDY));
122*4882a593Smuzhiyun tmp &= AT91_PMC_MCFR_MAINF_MASK;
123*4882a593Smuzhiyun main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun #endif
126*4882a593Smuzhiyun gd->arch.main_clk_rate_hz = main_clock;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* report if PLLA is more than mildly overclocked */
129*4882a593Smuzhiyun gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun #ifdef CONFIG_USB_ATMEL
132*4882a593Smuzhiyun /*
133*4882a593Smuzhiyun * USB clock init: choose 48 MHz PLLB value,
134*4882a593Smuzhiyun * disable 48MHz clock during usb peripheral suspend.
135*4882a593Smuzhiyun *
136*4882a593Smuzhiyun * REVISIT: assumes MCK doesn't derive from PLLB!
137*4882a593Smuzhiyun */
138*4882a593Smuzhiyun gd->arch.at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) |
139*4882a593Smuzhiyun AT91_PMC_PLLBR_USBDIV_2;
140*4882a593Smuzhiyun gd->arch.pllb_rate_hz = at91_pll_rate(main_clock,
141*4882a593Smuzhiyun gd->arch.at91_pllb_usb_init);
142*4882a593Smuzhiyun #endif
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun /*
145*4882a593Smuzhiyun * MCK and CPU derive from one of those primary clocks.
146*4882a593Smuzhiyun * For now, assume this parentage won't change.
147*4882a593Smuzhiyun */
148*4882a593Smuzhiyun mckr = readl(&pmc->mckr);
149*4882a593Smuzhiyun gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
150*4882a593Smuzhiyun freq = gd->arch.mck_rate_hz;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2)); /* prescale */
153*4882a593Smuzhiyun /* mdiv */
154*4882a593Smuzhiyun gd->arch.mck_rate_hz = freq /
155*4882a593Smuzhiyun (1 + ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
156*4882a593Smuzhiyun gd->arch.cpu_clk_rate_hz = freq;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun
at91_pllb_clk_enable(u32 pllbr)161*4882a593Smuzhiyun int at91_pllb_clk_enable(u32 pllbr)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
164*4882a593Smuzhiyun ulong start_time, tmp_time;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun start_time = get_timer(0);
167*4882a593Smuzhiyun writel(pllbr, &pmc->pllbr);
168*4882a593Smuzhiyun while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB) {
169*4882a593Smuzhiyun tmp_time = get_timer(0);
170*4882a593Smuzhiyun if ((tmp_time - start_time) > EN_PLLB_TIMEOUT) {
171*4882a593Smuzhiyun printf("ERROR: failed to enable PLLB\n");
172*4882a593Smuzhiyun return -1;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun return 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
at91_pllb_clk_disable(void)179*4882a593Smuzhiyun int at91_pllb_clk_disable(void)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
182*4882a593Smuzhiyun ulong start_time, tmp_time;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun start_time = get_timer(0);
185*4882a593Smuzhiyun writel(0, &pmc->pllbr);
186*4882a593Smuzhiyun while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != 0) {
187*4882a593Smuzhiyun tmp_time = get_timer(0);
188*4882a593Smuzhiyun if ((tmp_time - start_time) > EN_PLLB_TIMEOUT) {
189*4882a593Smuzhiyun printf("ERROR: failed to disable PLLB\n");
190*4882a593Smuzhiyun return -1;
191*4882a593Smuzhiyun }
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun return 0;
195*4882a593Smuzhiyun }
196