]>
Commit | Line | Data |
---|---|---|
3225f34e BS |
1 | /* |
2 | * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c] | |
3 | * | |
4 | * Copyright (C) 2005 David Brownell | |
5 | * Copyright (C) 2005 Ivan Kokshaysky | |
6 | * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> | |
7 | * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com> | |
8 | * | |
1a459660 | 9 | * SPDX-License-Identifier: GPL-2.0+ |
3225f34e BS |
10 | */ |
11 | ||
12 | #include <common.h> | |
13 | #include <asm/io.h> | |
14 | #include <asm/arch/hardware.h> | |
15 | #include <asm/arch/at91_pmc.h> | |
16 | #include <asm/arch/clk.h> | |
17 | ||
18 | #if !defined(CONFIG_AT91FAMILY) | |
19 | # error You need to define CONFIG_AT91FAMILY in your board config! | |
20 | #endif | |
21 | ||
22 | DECLARE_GLOBAL_DATA_PTR; | |
23 | ||
24 | static unsigned long at91_css_to_rate(unsigned long css) | |
25 | { | |
26 | switch (css) { | |
27 | case AT91_PMC_MCKR_CSS_SLOW: | |
28 | return CONFIG_SYS_AT91_SLOW_CLOCK; | |
29 | case AT91_PMC_MCKR_CSS_MAIN: | |
30 | return gd->arch.main_clk_rate_hz; | |
31 | case AT91_PMC_MCKR_CSS_PLLA: | |
32 | return gd->arch.plla_rate_hz; | |
33 | } | |
34 | ||
35 | return 0; | |
36 | } | |
37 | ||
38 | static u32 at91_pll_rate(u32 freq, u32 reg) | |
39 | { | |
40 | unsigned mul, div; | |
41 | ||
42 | div = reg & 0xff; | |
43 | mul = (reg >> 18) & 0x7f; | |
44 | if (div && mul) { | |
45 | freq /= div; | |
46 | freq *= mul + 1; | |
47 | } else { | |
48 | freq = 0; | |
49 | } | |
50 | ||
51 | return freq; | |
52 | } | |
53 | ||
54 | int at91_clock_init(unsigned long main_clock) | |
55 | { | |
56 | unsigned freq, mckr; | |
57 | struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; | |
58 | #ifndef CONFIG_SYS_AT91_MAIN_CLOCK | |
59 | unsigned tmp; | |
60 | /* | |
61 | * When the bootloader initialized the main oscillator correctly, | |
62 | * there's no problem using the cycle counter. But if it didn't, | |
63 | * or when using oscillator bypass mode, we must be told the speed | |
64 | * of the main clock. | |
65 | */ | |
66 | if (!main_clock) { | |
67 | do { | |
68 | tmp = readl(&pmc->mcfr); | |
69 | } while (!(tmp & AT91_PMC_MCFR_MAINRDY)); | |
70 | tmp &= AT91_PMC_MCFR_MAINF_MASK; | |
71 | main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16); | |
72 | } | |
73 | #endif | |
74 | gd->arch.main_clk_rate_hz = main_clock; | |
75 | ||
76 | /* report if PLLA is more than mildly overclocked */ | |
77 | gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar)); | |
78 | ||
79 | /* | |
80 | * MCK and CPU derive from one of those primary clocks. | |
81 | * For now, assume this parentage won't change. | |
82 | */ | |
83 | mckr = readl(&pmc->mckr); | |
84 | ||
85 | /* plla divisor by 2 */ | |
86 | if (mckr & (1 << 12)) | |
87 | gd->arch.plla_rate_hz >>= 1; | |
88 | ||
89 | gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK); | |
90 | freq = gd->arch.mck_rate_hz; | |
91 | ||
92 | /* prescale */ | |
93 | freq >>= mckr & AT91_PMC_MCKR_PRES_MASK; | |
94 | ||
95 | switch (mckr & AT91_PMC_MCKR_MDIV_MASK) { | |
96 | case AT91_PMC_MCKR_MDIV_2: | |
97 | gd->arch.mck_rate_hz = freq / 2; | |
98 | break; | |
99 | case AT91_PMC_MCKR_MDIV_3: | |
100 | gd->arch.mck_rate_hz = freq / 3; | |
101 | break; | |
102 | case AT91_PMC_MCKR_MDIV_4: | |
103 | gd->arch.mck_rate_hz = freq / 4; | |
104 | break; | |
105 | default: | |
106 | break; | |
107 | } | |
108 | ||
109 | gd->arch.cpu_clk_rate_hz = freq; | |
110 | ||
111 | return 0; | |
112 | } | |
113 | ||
114 | void at91_periph_clk_enable(int id) | |
115 | { | |
116 | struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; | |
117 | ||
118 | if (id > 31) | |
119 | writel(1 << (id - 32), &pmc->pcer1); | |
120 | else | |
121 | writel(1 << id, &pmc->pcer); | |
122 | } |