]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - arch/arm/cpu/armv7/at91/clock.c
Merge branch 'u-boot-samsung/master' into 'u-boot-arm/master'
[karo-tx-uboot.git] / arch / arm / cpu / armv7 / at91 / clock.c
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  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  */
14
15 #include <common.h>
16 #include <asm/io.h>
17 #include <asm/arch/hardware.h>
18 #include <asm/arch/at91_pmc.h>
19 #include <asm/arch/clk.h>
20
21 #if !defined(CONFIG_AT91FAMILY)
22 # error You need to define CONFIG_AT91FAMILY in your board config!
23 #endif
24
25 DECLARE_GLOBAL_DATA_PTR;
26
27 static unsigned long at91_css_to_rate(unsigned long css)
28 {
29         switch (css) {
30         case AT91_PMC_MCKR_CSS_SLOW:
31                 return CONFIG_SYS_AT91_SLOW_CLOCK;
32         case AT91_PMC_MCKR_CSS_MAIN:
33                 return gd->arch.main_clk_rate_hz;
34         case AT91_PMC_MCKR_CSS_PLLA:
35                 return gd->arch.plla_rate_hz;
36         }
37
38         return 0;
39 }
40
41 static u32 at91_pll_rate(u32 freq, u32 reg)
42 {
43         unsigned mul, div;
44
45         div = reg & 0xff;
46         mul = (reg >> 18) & 0x7f;
47         if (div && mul) {
48                 freq /= div;
49                 freq *= mul + 1;
50         } else {
51                 freq = 0;
52         }
53
54         return freq;
55 }
56
57 int at91_clock_init(unsigned long main_clock)
58 {
59         unsigned freq, mckr;
60         struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
61 #ifndef CONFIG_SYS_AT91_MAIN_CLOCK
62         unsigned tmp;
63         /*
64          * When the bootloader initialized the main oscillator correctly,
65          * there's no problem using the cycle counter.  But if it didn't,
66          * or when using oscillator bypass mode, we must be told the speed
67          * of the main clock.
68          */
69         if (!main_clock) {
70                 do {
71                         tmp = readl(&pmc->mcfr);
72                 } while (!(tmp & AT91_PMC_MCFR_MAINRDY));
73                 tmp &= AT91_PMC_MCFR_MAINF_MASK;
74                 main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
75         }
76 #endif
77         gd->arch.main_clk_rate_hz = main_clock;
78
79         /* report if PLLA is more than mildly overclocked */
80         gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
81
82         /*
83          * MCK and CPU derive from one of those primary clocks.
84          * For now, assume this parentage won't change.
85          */
86         mckr = readl(&pmc->mckr);
87
88         /* plla divisor by 2 */
89         if (mckr & (1 << 12))
90                 gd->arch.plla_rate_hz >>= 1;
91
92         gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
93         freq = gd->arch.mck_rate_hz;
94
95         /* prescale */
96         freq >>= mckr & AT91_PMC_MCKR_PRES_MASK;
97
98         switch (mckr & AT91_PMC_MCKR_MDIV_MASK) {
99         case AT91_PMC_MCKR_MDIV_2:
100                 gd->arch.mck_rate_hz = freq / 2;
101                 break;
102         case AT91_PMC_MCKR_MDIV_3:
103                 gd->arch.mck_rate_hz = freq / 3;
104                 break;
105         case AT91_PMC_MCKR_MDIV_4:
106                 gd->arch.mck_rate_hz = freq / 4;
107                 break;
108         default:
109                 break;
110         }
111
112         gd->arch.cpu_clk_rate_hz = freq;
113
114         return 0;
115 }
116
117 void at91_periph_clk_enable(int id)
118 {
119         struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
120
121         if (id > 31)
122                 writel(1 << (id - 32), &pmc->pcer1);
123         else
124                 writel(1 << id, &pmc->pcer);
125 }