1 /* 2 * Atheros AR71XX/AR724X/AR913X common routines 3 * 4 * Copyright (C) 2011 Gabor Juhos <juhosg@openwrt.org> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 as published 8 * by the Free Software Foundation. 9 */ 10 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/init.h> 14 #include <linux/err.h> 15 #include <linux/clk.h> 16 17 #include <asm/mach-ath79/ath79.h> 18 #include <asm/mach-ath79/ar71xx_regs.h> 19 #include "common.h" 20 21 #define AR71XX_BASE_FREQ 40000000 22 #define AR724X_BASE_FREQ 5000000 23 #define AR913X_BASE_FREQ 5000000 24 25 struct clk { 26 unsigned long rate; 27 }; 28 29 static struct clk ath79_ref_clk; 30 static struct clk ath79_cpu_clk; 31 static struct clk ath79_ddr_clk; 32 static struct clk ath79_ahb_clk; 33 static struct clk ath79_wdt_clk; 34 static struct clk ath79_uart_clk; 35 36 static void __init ar71xx_clocks_init(void) 37 { 38 u32 pll; 39 u32 freq; 40 u32 div; 41 42 ath79_ref_clk.rate = AR71XX_BASE_FREQ; 43 44 pll = ath79_pll_rr(AR71XX_PLL_REG_CPU_CONFIG); 45 46 div = ((pll >> AR71XX_PLL_DIV_SHIFT) & AR71XX_PLL_DIV_MASK) + 1; 47 freq = div * ath79_ref_clk.rate; 48 49 div = ((pll >> AR71XX_CPU_DIV_SHIFT) & AR71XX_CPU_DIV_MASK) + 1; 50 ath79_cpu_clk.rate = freq / div; 51 52 div = ((pll >> AR71XX_DDR_DIV_SHIFT) & AR71XX_DDR_DIV_MASK) + 1; 53 ath79_ddr_clk.rate = freq / div; 54 55 div = (((pll >> AR71XX_AHB_DIV_SHIFT) & AR71XX_AHB_DIV_MASK) + 1) * 2; 56 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 57 58 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 59 ath79_uart_clk.rate = ath79_ahb_clk.rate; 60 } 61 62 static void __init ar724x_clocks_init(void) 63 { 64 u32 pll; 65 u32 freq; 66 u32 div; 67 68 ath79_ref_clk.rate = AR724X_BASE_FREQ; 69 pll = ath79_pll_rr(AR724X_PLL_REG_CPU_CONFIG); 70 71 div = ((pll >> AR724X_PLL_DIV_SHIFT) & AR724X_PLL_DIV_MASK); 72 freq = div * ath79_ref_clk.rate; 73 74 div = ((pll >> AR724X_PLL_REF_DIV_SHIFT) & AR724X_PLL_REF_DIV_MASK); 75 freq *= div; 76 77 ath79_cpu_clk.rate = freq; 78 79 div = ((pll >> AR724X_DDR_DIV_SHIFT) & AR724X_DDR_DIV_MASK) + 1; 80 ath79_ddr_clk.rate = freq / div; 81 82 div = (((pll >> AR724X_AHB_DIV_SHIFT) & AR724X_AHB_DIV_MASK) + 1) * 2; 83 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 84 85 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 86 ath79_uart_clk.rate = ath79_ahb_clk.rate; 87 } 88 89 static void __init ar913x_clocks_init(void) 90 { 91 u32 pll; 92 u32 freq; 93 u32 div; 94 95 ath79_ref_clk.rate = AR913X_BASE_FREQ; 96 pll = ath79_pll_rr(AR913X_PLL_REG_CPU_CONFIG); 97 98 div = ((pll >> AR913X_PLL_DIV_SHIFT) & AR913X_PLL_DIV_MASK); 99 freq = div * ath79_ref_clk.rate; 100 101 ath79_cpu_clk.rate = freq; 102 103 div = ((pll >> AR913X_DDR_DIV_SHIFT) & AR913X_DDR_DIV_MASK) + 1; 104 ath79_ddr_clk.rate = freq / div; 105 106 div = (((pll >> AR913X_AHB_DIV_SHIFT) & AR913X_AHB_DIV_MASK) + 1) * 2; 107 ath79_ahb_clk.rate = ath79_cpu_clk.rate / div; 108 109 ath79_wdt_clk.rate = ath79_ahb_clk.rate; 110 ath79_uart_clk.rate = ath79_ahb_clk.rate; 111 } 112 113 static void __init ar933x_clocks_init(void) 114 { 115 u32 clock_ctrl; 116 u32 cpu_config; 117 u32 freq; 118 u32 t; 119 120 t = ath79_reset_rr(AR933X_RESET_REG_BOOTSTRAP); 121 if (t & AR933X_BOOTSTRAP_REF_CLK_40) 122 ath79_ref_clk.rate = (40 * 1000 * 1000); 123 else 124 ath79_ref_clk.rate = (25 * 1000 * 1000); 125 126 clock_ctrl = ath79_pll_rr(AR933X_PLL_CLOCK_CTRL_REG); 127 if (clock_ctrl & AR933X_PLL_CLOCK_CTRL_BYPASS) { 128 ath79_cpu_clk.rate = ath79_ref_clk.rate; 129 ath79_ahb_clk.rate = ath79_ref_clk.rate; 130 ath79_ddr_clk.rate = ath79_ref_clk.rate; 131 } else { 132 cpu_config = ath79_pll_rr(AR933X_PLL_CPU_CONFIG_REG); 133 134 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT) & 135 AR933X_PLL_CPU_CONFIG_REFDIV_MASK; 136 freq = ath79_ref_clk.rate / t; 137 138 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT) & 139 AR933X_PLL_CPU_CONFIG_NINT_MASK; 140 freq *= t; 141 142 t = (cpu_config >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT) & 143 AR933X_PLL_CPU_CONFIG_OUTDIV_MASK; 144 if (t == 0) 145 t = 1; 146 147 freq >>= t; 148 149 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_CPU_DIV_SHIFT) & 150 AR933X_PLL_CLOCK_CTRL_CPU_DIV_MASK) + 1; 151 ath79_cpu_clk.rate = freq / t; 152 153 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_DDR_DIV_SHIFT) & 154 AR933X_PLL_CLOCK_CTRL_DDR_DIV_MASK) + 1; 155 ath79_ddr_clk.rate = freq / t; 156 157 t = ((clock_ctrl >> AR933X_PLL_CLOCK_CTRL_AHB_DIV_SHIFT) & 158 AR933X_PLL_CLOCK_CTRL_AHB_DIV_MASK) + 1; 159 ath79_ahb_clk.rate = freq / t; 160 } 161 162 ath79_wdt_clk.rate = ath79_ref_clk.rate; 163 ath79_uart_clk.rate = ath79_ref_clk.rate; 164 } 165 166 void __init ath79_clocks_init(void) 167 { 168 if (soc_is_ar71xx()) 169 ar71xx_clocks_init(); 170 else if (soc_is_ar724x()) 171 ar724x_clocks_init(); 172 else if (soc_is_ar913x()) 173 ar913x_clocks_init(); 174 else if (soc_is_ar933x()) 175 ar933x_clocks_init(); 176 else 177 BUG(); 178 179 pr_info("Clocks: CPU:%lu.%03luMHz, DDR:%lu.%03luMHz, AHB:%lu.%03luMHz, " 180 "Ref:%lu.%03luMHz", 181 ath79_cpu_clk.rate / 1000000, 182 (ath79_cpu_clk.rate / 1000) % 1000, 183 ath79_ddr_clk.rate / 1000000, 184 (ath79_ddr_clk.rate / 1000) % 1000, 185 ath79_ahb_clk.rate / 1000000, 186 (ath79_ahb_clk.rate / 1000) % 1000, 187 ath79_ref_clk.rate / 1000000, 188 (ath79_ref_clk.rate / 1000) % 1000); 189 } 190 191 /* 192 * Linux clock API 193 */ 194 struct clk *clk_get(struct device *dev, const char *id) 195 { 196 if (!strcmp(id, "ref")) 197 return &ath79_ref_clk; 198 199 if (!strcmp(id, "cpu")) 200 return &ath79_cpu_clk; 201 202 if (!strcmp(id, "ddr")) 203 return &ath79_ddr_clk; 204 205 if (!strcmp(id, "ahb")) 206 return &ath79_ahb_clk; 207 208 if (!strcmp(id, "wdt")) 209 return &ath79_wdt_clk; 210 211 if (!strcmp(id, "uart")) 212 return &ath79_uart_clk; 213 214 return ERR_PTR(-ENOENT); 215 } 216 EXPORT_SYMBOL(clk_get); 217 218 int clk_enable(struct clk *clk) 219 { 220 return 0; 221 } 222 EXPORT_SYMBOL(clk_enable); 223 224 void clk_disable(struct clk *clk) 225 { 226 } 227 EXPORT_SYMBOL(clk_disable); 228 229 unsigned long clk_get_rate(struct clk *clk) 230 { 231 return clk->rate; 232 } 233 EXPORT_SYMBOL(clk_get_rate); 234 235 void clk_put(struct clk *clk) 236 { 237 } 238 EXPORT_SYMBOL(clk_put); 239