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 * SPDX-License-Identifier: GPL-2.0+ 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_plla_init(u32 pllar) 115 { 116 struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; 117 118 writel(pllar, &pmc->pllar); 119 while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY))) 120 ; 121 } 122 123 void at91_mck_init(u32 mckr) 124 { 125 struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; 126 u32 tmp; 127 128 tmp = readl(&pmc->mckr); 129 tmp &= ~(AT91_PMC_MCKR_CSS_MASK | 130 AT91_PMC_MCKR_PRES_MASK | 131 AT91_PMC_MCKR_MDIV_MASK | 132 AT91_PMC_MCKR_PLLADIV_2); 133 #ifdef CPU_HAS_H32MXDIV 134 tmp &= ~AT91_PMC_MCKR_H32MXDIV; 135 #endif 136 137 tmp |= mckr & (AT91_PMC_MCKR_CSS_MASK | 138 AT91_PMC_MCKR_PRES_MASK | 139 AT91_PMC_MCKR_MDIV_MASK | 140 AT91_PMC_MCKR_PLLADIV_2); 141 #ifdef CPU_HAS_H32MXDIV 142 tmp |= mckr & AT91_PMC_MCKR_H32MXDIV; 143 #endif 144 145 writel(tmp, &pmc->mckr); 146 147 while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY)) 148 ; 149 } 150 151 void at91_periph_clk_enable(int id) 152 { 153 struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; 154 u32 regval; 155 156 if (id > AT91_PMC_PCR_PID_MASK) 157 return; 158 159 regval = AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD_WRITE | id; 160 161 writel(regval, &pmc->pcr); 162 } 163 164 void at91_periph_clk_disable(int id) 165 { 166 struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; 167 u32 regval; 168 169 if (id > AT91_PMC_PCR_PID_MASK) 170 return; 171 172 regval = AT91_PMC_PCR_CMD_WRITE | id; 173 174 writel(regval, &pmc->pcr); 175 } 176