1 /* 2 * Atheros AR71XX/AR724X/AR913X common routines 3 * 4 * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com> 5 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 6 * 7 * Parts of this file are based on Atheros' 2.6.15/2.6.31 BSP 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License version 2 as published 11 * by the Free Software Foundation. 12 */ 13 14 #include <linux/kernel.h> 15 #include <linux/module.h> 16 #include <linux/init.h> 17 #include <linux/err.h> 18 #include <linux/clk.h> 19 20 #include <asm/mach-ath79/ath79.h> 21 #include <asm/mach-ath79/ar71xx_regs.h> 22 #include "common.h" 23 24 #define AR71XX_BASE_FREQ 40000000 25 #define AR724X_BASE_FREQ 5000000 26 #define AR913X_BASE_FREQ 5000000 27 28 struct clk { 29 unsigned long rate; 30 }; 31 32 static struct clk ath79_ref_clk; 33 static struct clk ath79_cpu_clk; 34 static struct clk ath79_ddr_clk; 35 static struct clk ath79_ahb_clk; 36 static struct clk ath79_wdt_clk; 37 static struct clk ath79_uart_clk; 38 39 static void __init ar71xx_clocks_init(void) 40 { 41 u32 pll; 42 u32 freq; 43 u32 div; 44 45 ath79_ref_clk.rate = AR71XX_BASE_FREQ; 46 47 pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); 48 49 div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; 50 freq = div * ath79_ref_clk.rate; 51 52 div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; 53 ath79_cpu_clk.rate = freq / div; 54 55 div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; 56 ath79_ddr_clk.rate = freq / div; 57 58 div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; 59 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 60 61 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 62 ath79_uart_clk.rate = ath79_ahb_clk.rate; 63 } 64 65 static void __init ar724x_clocks_init(void) 66 { 67 u32 pll; 68 u32 freq; 69 u32 div; 70 71 ath79_ref_clk.rate = AR724X_BASE_FREQ; 72 pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); 73 74 div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); 75 freq = div * ath79_ref_clk.rate; 76 77 div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); 78 freq *= div; 79 80 ath79_cpu_clk.rate = freq; 81 82 div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; 83 ath79_ddr_clk.rate = freq / div; 84 85 div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; 86 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 87 88 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 89 ath79_uart_clk.rate = ath79_ahb_clk.rate; 90 } 91 92 static void __init ar913x_clocks_init(void) 93 { 94 u32 pll; 95 u32 freq; 96 u32 div; 97 98 ath79_ref_clk.rate = AR913X_BASE_FREQ; 99 pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); 100 101 div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); 102 freq = div * ath79_ref_clk.rate; 103 104 ath79_cpu_clk.rate = freq; 105 106 div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; 107 ath79_ddr_clk.rate = freq / div; 108 109 div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; 110 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 111 112 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 113 ath79_uart_clk.rate = ath79_ahb_clk.rate; 114 } 115 116 static void __init ar933x_clocks_init(void) 117 { 118 u32 clock_ctrl; 119 u32 cpu_config; 120 u32 freq; 121 u32 t; 122 123 t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); 124 if (t & AR933X_BOOTSTRAP_REF_CLK_40) 125 ath79_ref_clk.rate = (40 * 1000 * 1000); 126 else 127 ath79_ref_clk.rate = (25 * 1000 * 1000); 128 129 clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); 130 if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { 131 ath79_cpu_clk.rate = ath79_ref_clk.rate; 132 ath79_ahb_clk.rate = ath79_ref_clk.rate; 133 ath79_ddr_clk.rate = ath79_ref_clk.rate; 134 } else { 135 cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); 136 137 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 138 AR933X_PLL_CPU_CONFIG_REFDIV_MASK; 139 freq = ath79_ref_clk.rate / t; 140 141 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & 142 AR933X_PLL_CPU_CONFIG_NINT_MASK; 143 freq *= t; 144 145 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 146 AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; 147 if (t == 0) 148 t = 1; 149 150 freq >>= t; 151 152 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & 153 AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; 154 ath79_cpu_clk.rate = freq / t; 155 156 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & 157 AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; 158 ath79_ddr_clk.rate = freq / t; 159 160 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & 161 AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; 162 ath79_ahb_clk.rate = freq / t; 163 } 164 165 ath79_wdt_clk.rate = ath79_ref_clk.rate; 166 ath79_uart_clk.rate = ath79_ref_clk.rate; 167 } 168 169 static void __init ar934x_clocks_init(void) 170 { 171 u32 pll, out_div, ref_div, nint, frac, clk_ctrl, postdiv; 172 u32 cpu_pll, ddr_pll; 173 u32 bootstrap; 174 175 bootstrap = ath79_reset_rr(AR934X_RESET_REG_BOOTSTRAP); 176 if (bootstrap & AR934X_BOOTSTRAP_REF_CLK_40) 177 ath79_ref_clk.rate = 40 * 1000 * 1000; 178 else 179 ath79_ref_clk.rate = 25 * 1000 * 1000; 180 181 pll = ath79_pll_rr(AR934X_PLL_CPU_CONFIG_REG); 182 out_div = (pll >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 183 AR934X_PLL_CPU_CONFIG_OUTDIV_MASK; 184 ref_div = (pll >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 185 AR934X_PLL_CPU_CONFIG_REFDIV_MASK; 186 nint = (pll >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) & 187 AR934X_PLL_CPU_CONFIG_NINT_MASK; 188 frac = (pll >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) & 189 AR934X_PLL_CPU_CONFIG_NFRAC_MASK; 190 191 cpu_pll = nint * ath79_ref_clk.rate / ref_div; 192 cpu_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 6)); 193 cpu_pll /= (1 << out_div); 194 195 pll = ath79_pll_rr(AR934X_PLL_DDR_CONFIG_REG); 196 out_div = (pll >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) & 197 AR934X_PLL_DDR_CONFIG_OUTDIV_MASK; 198 ref_div = (pll >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) & 199 AR934X_PLL_DDR_CONFIG_REFDIV_MASK; 200 nint = (pll >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) & 201 AR934X_PLL_DDR_CONFIG_NINT_MASK; 202 frac = (pll >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) & 203 AR934X_PLL_DDR_CONFIG_NFRAC_MASK; 204 205 ddr_pll = nint * ath79_ref_clk.rate / ref_div; 206 ddr_pll += frac * ath79_ref_clk.rate / (ref_div * (2 << 10)); 207 ddr_pll /= (1 << out_div); 208 209 clk_ctrl = ath79_pll_rr(AR934X_PLL_CPU_DDR_CLK_CTRL_REG); 210 211 postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_SHIFT) & 212 AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_POST_DIV_MASK; 213 214 if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPU_PLL_BYPASS) 215 ath79_cpu_clk.rate = ath79_ref_clk.rate; 216 else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_CPUCLK_FROM_CPUPLL) 217 ath79_cpu_clk.rate = cpu_pll / (postdiv + 1); 218 else 219 ath79_cpu_clk.rate = ddr_pll / (postdiv + 1); 220 221 postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_SHIFT) & 222 AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_POST_DIV_MASK; 223 224 if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDR_PLL_BYPASS) 225 ath79_ddr_clk.rate = ath79_ref_clk.rate; 226 else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_DDRCLK_FROM_DDRPLL) 227 ath79_ddr_clk.rate = ddr_pll / (postdiv + 1); 228 else 229 ath79_ddr_clk.rate = cpu_pll / (postdiv + 1); 230 231 postdiv = (clk_ctrl >> AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_SHIFT) & 232 AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_POST_DIV_MASK; 233 234 if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHB_PLL_BYPASS) 235 ath79_ahb_clk.rate = ath79_ref_clk.rate; 236 else if (clk_ctrl & AR934X_PLL_CPU_DDR_CLK_CTRL_AHBCLK_FROM_DDRPLL) 237 ath79_ahb_clk.rate = ddr_pll / (postdiv + 1); 238 else 239 ath79_ahb_clk.rate = cpu_pll / (postdiv + 1); 240 241 ath79_wdt_clk.rate = ath79_ref_clk.rate; 242 ath79_uart_clk.rate = ath79_ref_clk.rate; 243 } 244 245 void __init ath79_clocks_init(void) 246 { 247 if (soc_is_ar71xx()) 248 ar71xx_clocks_init(); 249 else if (soc_is_ar724x()) 250 ar724x_clocks_init(); 251 else if (soc_is_ar913x()) 252 ar913x_clocks_init(); 253 else if (soc_is_ar933x()) 254 ar933x_clocks_init(); 255 else if (soc_is_ar934x()) 256 ar934x_clocks_init(); 257 else 258 BUG(); 259 260 pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " 261 "Ref:%lu.%03luMHz", 262 ath79_cpu_clk.rate / 1000000, 263 (ath79_cpu_clk.rate / 1000) % 1000, 264 ath79_ddr_clk.rate / 1000000, 265 (ath79_ddr_clk.rate / 1000) % 1000, 266 ath79_ahb_clk.rate / 1000000, 267 (ath79_ahb_clk.rate / 1000) % 1000, 268 ath79_ref_clk.rate / 1000000, 269 (ath79_ref_clk.rate / 1000) % 1000); 270 } 271 272 /* 273 * Linux clock API 274 */ 275 struct clk *clk_get(struct device *dev, const char *id) 276 { 277 if (!strcmp(id, "ref")) 278 return &ath79_ref_clk; 279 280 if (!strcmp(id, "cpu")) 281 return &ath79_cpu_clk; 282 283 if (!strcmp(id, "ddr")) 284 return &ath79_ddr_clk; 285 286 if (!strcmp(id, "ahb")) 287 return &ath79_ahb_clk; 288 289 if (!strcmp(id, "wdt")) 290 return &ath79_wdt_clk; 291 292 if (!strcmp(id, "uart")) 293 return &ath79_uart_clk; 294 295 return ERR_PTR(-ENOENT); 296 } 297 EXPORT_SYMBOL(clk_get); 298 299 int clk_enable(struct clk *clk) 300 { 301 return 0; 302 } 303 EXPORT_SYMBOL(clk_enable); 304 305 void clk_disable(struct clk *clk) 306 { 307 } 308 EXPORT_SYMBOL(clk_disable); 309 310 unsigned long clk_get_rate(struct clk *clk) 311 { 312 return clk->rate; 313 } 314 EXPORT_SYMBOL(clk_get_rate); 315 316 void clk_put(struct clk *clk) 317 { 318 } 319 EXPORT_SYMBOL(clk_put); 320