1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
4 *
5 * Copyright (C) 2005 David Brownell
6 * Copyright (C) 2005 Ivan Kokshaysky
7 * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
8 */
9
10#include <common.h>
11#include <asm/global_data.h>
12#include <asm/io.h>
13#include <asm/arch/hardware.h>
14#include <asm/arch/at91_pmc.h>
15#include <asm/arch/clk.h>
16
17#if !defined(CONFIG_AT91FAMILY)
18# error You need to define CONFIG_AT91FAMILY in your board config!
19#endif
20
21#define EN_PLLB_TIMEOUT	500
22
23DECLARE_GLOBAL_DATA_PTR;
24
25static unsigned long at91_css_to_rate(unsigned long css)
26{
27	switch (css) {
28	case AT91_PMC_MCKR_CSS_SLOW:
29		return CFG_SYS_AT91_SLOW_CLOCK;
30	case AT91_PMC_MCKR_CSS_MAIN:
31		return gd->arch.main_clk_rate_hz;
32	case AT91_PMC_MCKR_CSS_PLLA:
33		return gd->arch.plla_rate_hz;
34	case AT91_PMC_MCKR_CSS_PLLB:
35		return gd->arch.pllb_rate_hz;
36	}
37
38	return 0;
39}
40
41#ifdef CONFIG_USB_ATMEL
42static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq)
43{
44	unsigned i, div = 0, mul = 0, diff = 1 << 30;
45	unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;
46
47	/* PLL output max 240 MHz (or 180 MHz per errata) */
48	if (out_freq > 240000000)
49		goto fail;
50
51	for (i = 1; i < 256; i++) {
52		int diff1;
53		unsigned input, mul1;
54
55		/*
56		 * PLL input between 1MHz and 32MHz per spec, but lower
57		 * frequences seem necessary in some cases so allow 100K.
58		 * Warning: some newer products need 2MHz min.
59		 */
60		input = main_freq / i;
61#if defined(CONFIG_AT91SAM9G20)
62		if (input < 2000000)
63			continue;
64#endif
65		if (input < 100000)
66			continue;
67		if (input > 32000000)
68			continue;
69
70		mul1 = out_freq / input;
71#if defined(CONFIG_AT91SAM9G20)
72		if (mul > 63)
73			continue;
74#endif
75		if (mul1 > 2048)
76			continue;
77		if (mul1 < 2)
78			goto fail;
79
80		diff1 = out_freq - input * mul1;
81		if (diff1 < 0)
82			diff1 = -diff1;
83		if (diff > diff1) {
84			diff = diff1;
85			div = i;
86			mul = mul1;
87			if (diff == 0)
88				break;
89		}
90	}
91	if (i == 256 && diff > (out_freq >> 5))
92		goto fail;
93	return ret | ((mul - 1) << 16) | div;
94fail:
95	return 0;
96}
97#endif
98
99static u32 at91_pll_rate(u32 freq, u32 reg)
100{
101	unsigned mul, div;
102
103	div = reg & 0xff;
104	mul = (reg >> 16) & 0x7ff;
105	if (div && mul) {
106		freq /= div;
107		freq *= mul + 1;
108	} else
109		freq = 0;
110
111	return freq;
112}
113
114int at91_clock_init(unsigned long main_clock)
115{
116	unsigned freq, mckr;
117	at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC;
118#ifndef CFG_SYS_AT91_MAIN_CLOCK
119	unsigned tmp;
120	/*
121	 * When the bootloader initialized the main oscillator correctly,
122	 * there's no problem using the cycle counter.  But if it didn't,
123	 * or when using oscillator bypass mode, we must be told the speed
124	 * of the main clock.
125	 */
126	if (!main_clock) {
127		do {
128			tmp = readl(&pmc->mcfr);
129		} while (!(tmp & AT91_PMC_MCFR_MAINRDY));
130		tmp &= AT91_PMC_MCFR_MAINF_MASK;
131		main_clock = tmp * (CFG_SYS_AT91_SLOW_CLOCK / 16);
132	}
133#endif
134	gd->arch.main_clk_rate_hz = main_clock;
135
136	/* report if PLLA is more than mildly overclocked */
137	gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
138
139#ifdef CONFIG_USB_ATMEL
140	/*
141	 * USB clock init:  choose 48 MHz PLLB value,
142	 * disable 48MHz clock during usb peripheral suspend.
143	 *
144	 * REVISIT:  assumes MCK doesn't derive from PLLB!
145	 */
146	gd->arch.at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) |
147			     AT91_PMC_PLLBR_USBDIV_2;
148	gd->arch.pllb_rate_hz = at91_pll_rate(main_clock,
149					      gd->arch.at91_pllb_usb_init);
150#endif
151
152	/*
153	 * MCK and CPU derive from one of those primary clocks.
154	 * For now, assume this parentage won't change.
155	 */
156	mckr = readl(&pmc->mckr);
157#if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \
158		|| defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5)
159	/* plla divisor by 2 */
160	gd->arch.plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12));
161#endif
162	gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
163	freq = gd->arch.mck_rate_hz;
164
165#if defined(CONFIG_AT91SAM9X5)
166	/* different in prescale on at91sam9x5 */
167	freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 4));
168#else
169	freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2));	/* prescale */
170#endif
171
172#if defined(CONFIG_AT91SAM9G20)
173	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
174	gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ?
175		freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq;
176	if (mckr & AT91_PMC_MCKR_MDIV_MASK)
177		freq /= 2;			/* processor clock division */
178#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \
179		|| defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5)
180	/* mdiv <==> divisor
181	 *  0   <==>   1
182	 *  1   <==>   2
183	 *  2   <==>   4
184	 *  3   <==>   3
185	 */
186	gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ==
187		(AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4)
188		? freq / 3
189		: freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
190#else
191	gd->arch.mck_rate_hz = freq /
192			(1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8));
193#endif
194	gd->arch.cpu_clk_rate_hz = freq;
195
196	return 0;
197}
198
199#if !defined(AT91_PLL_LOCK_TIMEOUT)
200#define AT91_PLL_LOCK_TIMEOUT	1000000
201#endif
202
203void at91_plla_init(u32 pllar)
204{
205	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
206
207	writel(pllar, &pmc->pllar);
208	while (!(readl(&pmc->sr) & AT91_PMC_LOCKA))
209		;
210}
211void at91_pllb_init(u32 pllbr)
212{
213	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
214
215	writel(pllbr, &pmc->pllbr);
216	while (!(readl(&pmc->sr) & AT91_PMC_LOCKB))
217		;
218}
219
220void at91_mck_init(u32 mckr)
221{
222	struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
223	u32 tmp;
224
225	tmp = readl(&pmc->mckr);
226	tmp &= ~AT91_PMC_MCKR_PRES_MASK;
227	tmp |= mckr & AT91_PMC_MCKR_PRES_MASK;
228	writel(tmp, &pmc->mckr);
229	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
230		;
231
232	tmp = readl(&pmc->mckr);
233	tmp &= ~AT91_PMC_MCKR_MDIV_MASK;
234	tmp |= mckr & AT91_PMC_MCKR_MDIV_MASK;
235	writel(tmp, &pmc->mckr);
236	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
237		;
238
239	tmp = readl(&pmc->mckr);
240	tmp &= ~AT91_PMC_MCKR_PLLADIV_MASK;
241	tmp |= mckr & AT91_PMC_MCKR_PLLADIV_MASK;
242	writel(tmp, &pmc->mckr);
243	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
244		;
245
246	tmp = readl(&pmc->mckr);
247	tmp &= ~AT91_PMC_MCKR_CSS_MASK;
248	tmp |= mckr & AT91_PMC_MCKR_CSS_MASK;
249	writel(tmp, &pmc->mckr);
250	while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
251		;
252}
253
254int at91_pllb_clk_enable(u32 pllbr)
255{
256	struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
257	ulong start_time, tmp_time;
258
259	start_time = get_timer(0);
260	writel(pllbr, &pmc->pllbr);
261	while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != AT91_PMC_LOCKB) {
262		tmp_time = get_timer(0);
263		if ((tmp_time - start_time) > EN_PLLB_TIMEOUT) {
264			printf("ERROR: failed to enable PLLB\n");
265			return -1;
266		}
267	}
268
269	return 0;
270}
271
272int at91_pllb_clk_disable(void)
273{
274	struct at91_pmc *pmc = (at91_pmc_t *)ATMEL_BASE_PMC;
275	ulong start_time, tmp_time;
276
277	start_time = get_timer(0);
278	writel(0, &pmc->pllbr);
279	while ((readl(&pmc->sr) & AT91_PMC_LOCKB) != 0) {
280		tmp_time = get_timer(0);
281		if ((tmp_time - start_time) > EN_PLLB_TIMEOUT) {
282			printf("ERROR: failed to disable PLLB\n");
283			return -1;
284		}
285	}
286
287	return 0;
288}
289