1 /* 2 * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> 3 * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #include <linux/kernel.h> 21 #include <linux/init.h> 22 #include <linux/types.h> 23 #include <linux/module.h> 24 #include <linux/delay.h> 25 #include <linux/gcd.h> 26 #include <linux/io.h> 27 28 #include <asm/addrspace.h> 29 #include <asm/mach-ar7/ar7.h> 30 31 #define BOOT_PLL_SOURCE_MASK 0x3 32 #define CPU_PLL_SOURCE_SHIFT 16 33 #define BUS_PLL_SOURCE_SHIFT 14 34 #define USB_PLL_SOURCE_SHIFT 18 35 #define DSP_PLL_SOURCE_SHIFT 22 36 #define BOOT_PLL_SOURCE_AFE 0 37 #define BOOT_PLL_SOURCE_BUS 0 38 #define BOOT_PLL_SOURCE_REF 1 39 #define BOOT_PLL_SOURCE_XTAL 2 40 #define BOOT_PLL_SOURCE_CPU 3 41 #define BOOT_PLL_BYPASS 0x00000020 42 #define BOOT_PLL_ASYNC_MODE 0x02000000 43 #define BOOT_PLL_2TO1_MODE 0x00008000 44 45 #define TNETD7200_CLOCK_ID_CPU 0 46 #define TNETD7200_CLOCK_ID_DSP 1 47 #define TNETD7200_CLOCK_ID_USB 2 48 49 #define TNETD7200_DEF_CPU_CLK 211000000 50 #define TNETD7200_DEF_DSP_CLK 125000000 51 #define TNETD7200_DEF_USB_CLK 48000000 52 53 struct tnetd7300_clock { 54 u32 ctrl; 55 #define PREDIV_MASK 0x001f0000 56 #define PREDIV_SHIFT 16 57 #define POSTDIV_MASK 0x0000001f 58 u32 unused1[3]; 59 u32 pll; 60 #define MUL_MASK 0x0000f000 61 #define MUL_SHIFT 12 62 #define PLL_MODE_MASK 0x00000001 63 #define PLL_NDIV 0x00000800 64 #define PLL_DIV 0x00000002 65 #define PLL_STATUS 0x00000001 66 u32 unused2[3]; 67 }; 68 69 struct tnetd7300_clocks { 70 struct tnetd7300_clock bus; 71 struct tnetd7300_clock cpu; 72 struct tnetd7300_clock usb; 73 struct tnetd7300_clock dsp; 74 }; 75 76 struct tnetd7200_clock { 77 u32 ctrl; 78 u32 unused1[3]; 79 #define DIVISOR_ENABLE_MASK 0x00008000 80 u32 mul; 81 u32 prediv; 82 u32 postdiv; 83 u32 postdiv2; 84 u32 unused2[6]; 85 u32 cmd; 86 u32 status; 87 u32 cmden; 88 u32 padding[15]; 89 }; 90 91 struct tnetd7200_clocks { 92 struct tnetd7200_clock cpu; 93 struct tnetd7200_clock dsp; 94 struct tnetd7200_clock usb; 95 }; 96 97 int ar7_cpu_clock = 150000000; 98 EXPORT_SYMBOL(ar7_cpu_clock); 99 int ar7_bus_clock = 125000000; 100 EXPORT_SYMBOL(ar7_bus_clock); 101 int ar7_dsp_clock; 102 EXPORT_SYMBOL(ar7_dsp_clock); 103 104 static void approximate(int base, int target, int *prediv, 105 int *postdiv, int *mul) 106 { 107 int i, j, k, freq, res = target; 108 for (i = 1; i <= 16; i++) 109 for (j = 1; j <= 32; j++) 110 for (k = 1; k <= 32; k++) { 111 freq = abs(base / j * i / k - target); 112 if (freq < res) { 113 res = freq; 114 *mul = i; 115 *prediv = j; 116 *postdiv = k; 117 } 118 } 119 } 120 121 static void calculate(int base, int target, int *prediv, int *postdiv, 122 int *mul) 123 { 124 int tmp_gcd, tmp_base, tmp_freq; 125 126 for (*prediv = 1; *prediv <= 32; (*prediv)++) { 127 tmp_base = base / *prediv; 128 tmp_gcd = gcd(target, tmp_base); 129 *mul = target / tmp_gcd; 130 *postdiv = tmp_base / tmp_gcd; 131 if ((*mul < 1) || (*mul >= 16)) 132 continue; 133 if ((*postdiv > 0) & (*postdiv <= 32)) 134 break; 135 } 136 137 if (base / *prediv * *mul / *postdiv != target) { 138 approximate(base, target, prediv, postdiv, mul); 139 tmp_freq = base / *prediv * *mul / *postdiv; 140 printk(KERN_WARNING 141 "Adjusted requested frequency %d to %d\n", 142 target, tmp_freq); 143 } 144 145 printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n", 146 *prediv, *postdiv, *mul); 147 } 148 149 static int tnetd7300_dsp_clock(void) 150 { 151 u32 didr1, didr2; 152 u8 rev = ar7_chip_rev(); 153 didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18)); 154 didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c)); 155 if (didr2 & (1 << 23)) 156 return 0; 157 if ((rev >= 0x23) && (rev != 0x57)) 158 return 250000000; 159 if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22)) 160 > 4208000) 161 return 250000000; 162 return 0; 163 } 164 165 static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock, 166 u32 *bootcr, u32 bus_clock) 167 { 168 int product; 169 int base_clock = AR7_REF_CLOCK; 170 u32 ctrl = readl(&clock->ctrl); 171 u32 pll = readl(&clock->pll); 172 int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1; 173 int postdiv = (ctrl & POSTDIV_MASK) + 1; 174 int divisor = prediv * postdiv; 175 int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1; 176 177 switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { 178 case BOOT_PLL_SOURCE_BUS: 179 base_clock = bus_clock; 180 break; 181 case BOOT_PLL_SOURCE_REF: 182 base_clock = AR7_REF_CLOCK; 183 break; 184 case BOOT_PLL_SOURCE_XTAL: 185 base_clock = AR7_XTAL_CLOCK; 186 break; 187 case BOOT_PLL_SOURCE_CPU: 188 base_clock = ar7_cpu_clock; 189 break; 190 } 191 192 if (*bootcr & BOOT_PLL_BYPASS) 193 return base_clock / divisor; 194 195 if ((pll & PLL_MODE_MASK) == 0) 196 return (base_clock >> (mul / 16 + 1)) / divisor; 197 198 if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) { 199 product = (mul & 1) ? 200 (base_clock * mul) >> 1 : 201 (base_clock * (mul - 1)) >> 2; 202 return product / divisor; 203 } 204 205 if (mul == 16) 206 return base_clock / divisor; 207 208 return base_clock * mul / divisor; 209 } 210 211 static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock, 212 u32 *bootcr, u32 frequency) 213 { 214 int prediv, postdiv, mul; 215 int base_clock = ar7_bus_clock; 216 217 switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) { 218 case BOOT_PLL_SOURCE_BUS: 219 base_clock = ar7_bus_clock; 220 break; 221 case BOOT_PLL_SOURCE_REF: 222 base_clock = AR7_REF_CLOCK; 223 break; 224 case BOOT_PLL_SOURCE_XTAL: 225 base_clock = AR7_XTAL_CLOCK; 226 break; 227 case BOOT_PLL_SOURCE_CPU: 228 base_clock = ar7_cpu_clock; 229 break; 230 } 231 232 calculate(base_clock, frequency, &prediv, &postdiv, &mul); 233 234 writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl); 235 msleep(1); 236 writel(4, &clock->pll); 237 while (readl(&clock->pll) & PLL_STATUS) 238 ; 239 writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll); 240 msleep(75); 241 } 242 243 static void __init tnetd7300_init_clocks(void) 244 { 245 u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4); 246 struct tnetd7300_clocks *clocks = 247 ioremap_nocache(UR8_REGS_CLOCKS, 248 sizeof(struct tnetd7300_clocks)); 249 250 ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT, 251 &clocks->bus, bootcr, AR7_AFE_CLOCK); 252 253 if (*bootcr & BOOT_PLL_ASYNC_MODE) 254 ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT, 255 &clocks->cpu, bootcr, AR7_AFE_CLOCK); 256 else 257 ar7_cpu_clock = ar7_bus_clock; 258 259 if (ar7_dsp_clock == 250000000) 260 tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp, 261 bootcr, ar7_dsp_clock); 262 263 iounmap(clocks); 264 iounmap(bootcr); 265 } 266 267 static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock, 268 int prediv, int postdiv, int postdiv2, int mul, u32 frequency) 269 { 270 printk(KERN_INFO 271 "Clocks: base = %d, frequency = %u, prediv = %d, " 272 "postdiv = %d, postdiv2 = %d, mul = %d\n", 273 base, frequency, prediv, postdiv, postdiv2, mul); 274 275 writel(0, &clock->ctrl); 276 writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv); 277 writel((mul - 1) & 0xF, &clock->mul); 278 279 while (readl(&clock->status) & 0x1) 280 ; /* nop */ 281 282 writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv); 283 284 writel(readl(&clock->cmden) | 1, &clock->cmden); 285 writel(readl(&clock->cmd) | 1, &clock->cmd); 286 287 while (readl(&clock->status) & 0x1) 288 ; /* nop */ 289 290 writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2); 291 292 writel(readl(&clock->cmden) | 1, &clock->cmden); 293 writel(readl(&clock->cmd) | 1, &clock->cmd); 294 295 while (readl(&clock->status) & 0x1) 296 ; /* nop */ 297 298 writel(readl(&clock->ctrl) | 1, &clock->ctrl); 299 } 300 301 static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr) 302 { 303 if (*bootcr & BOOT_PLL_ASYNC_MODE) 304 /* Async */ 305 switch (clock_id) { 306 case TNETD7200_CLOCK_ID_DSP: 307 return AR7_REF_CLOCK; 308 default: 309 return AR7_AFE_CLOCK; 310 } 311 else 312 /* Sync */ 313 if (*bootcr & BOOT_PLL_2TO1_MODE) 314 /* 2:1 */ 315 switch (clock_id) { 316 case TNETD7200_CLOCK_ID_DSP: 317 return AR7_REF_CLOCK; 318 default: 319 return AR7_AFE_CLOCK; 320 } 321 else 322 /* 1:1 */ 323 return AR7_REF_CLOCK; 324 } 325 326 327 static void __init tnetd7200_init_clocks(void) 328 { 329 u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4); 330 struct tnetd7200_clocks *clocks = 331 ioremap_nocache(AR7_REGS_CLOCKS, 332 sizeof(struct tnetd7200_clocks)); 333 int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv; 334 int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv; 335 int usb_base, usb_mul, usb_prediv, usb_postdiv; 336 337 cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr); 338 dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr); 339 340 if (*bootcr & BOOT_PLL_ASYNC_MODE) { 341 printk(KERN_INFO "Clocks: Async mode\n"); 342 343 printk(KERN_INFO "Clocks: Setting DSP clock\n"); 344 calculate(dsp_base, TNETD7200_DEF_DSP_CLK, 345 &dsp_prediv, &dsp_postdiv, &dsp_mul); 346 ar7_bus_clock = 347 ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv; 348 tnetd7200_set_clock(dsp_base, &clocks->dsp, 349 dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2, 350 ar7_bus_clock); 351 352 printk(KERN_INFO "Clocks: Setting CPU clock\n"); 353 calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, 354 &cpu_postdiv, &cpu_mul); 355 ar7_cpu_clock = 356 ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv; 357 tnetd7200_set_clock(cpu_base, &clocks->cpu, 358 cpu_prediv, cpu_postdiv, -1, cpu_mul, 359 ar7_cpu_clock); 360 361 } else 362 if (*bootcr & BOOT_PLL_2TO1_MODE) { 363 printk(KERN_INFO "Clocks: Sync 2:1 mode\n"); 364 365 printk(KERN_INFO "Clocks: Setting CPU clock\n"); 366 calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv, 367 &cpu_postdiv, &cpu_mul); 368 ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul) 369 / cpu_postdiv; 370 tnetd7200_set_clock(cpu_base, &clocks->cpu, 371 cpu_prediv, cpu_postdiv, -1, cpu_mul, 372 ar7_cpu_clock); 373 374 printk(KERN_INFO "Clocks: Setting DSP clock\n"); 375 calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, 376 &dsp_postdiv, &dsp_mul); 377 ar7_bus_clock = ar7_cpu_clock / 2; 378 tnetd7200_set_clock(dsp_base, &clocks->dsp, 379 dsp_prediv, dsp_postdiv * 2, dsp_postdiv, 380 dsp_mul * 2, ar7_bus_clock); 381 } else { 382 printk(KERN_INFO "Clocks: Sync 1:1 mode\n"); 383 384 printk(KERN_INFO "Clocks: Setting DSP clock\n"); 385 calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv, 386 &dsp_postdiv, &dsp_mul); 387 ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul) 388 / dsp_postdiv; 389 tnetd7200_set_clock(dsp_base, &clocks->dsp, 390 dsp_prediv, dsp_postdiv * 2, dsp_postdiv, 391 dsp_mul * 2, ar7_bus_clock); 392 393 ar7_cpu_clock = ar7_bus_clock; 394 } 395 396 printk(KERN_INFO "Clocks: Setting USB clock\n"); 397 usb_base = ar7_bus_clock; 398 calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv, 399 &usb_postdiv, &usb_mul); 400 tnetd7200_set_clock(usb_base, &clocks->usb, 401 usb_prediv, usb_postdiv, -1, usb_mul, 402 TNETD7200_DEF_USB_CLK); 403 404 ar7_dsp_clock = ar7_cpu_clock; 405 406 iounmap(clocks); 407 iounmap(bootcr); 408 } 409 410 int __init ar7_init_clocks(void) 411 { 412 switch (ar7_chip_id()) { 413 case AR7_CHIP_7100: 414 case AR7_CHIP_7200: 415 tnetd7200_init_clocks(); 416 break; 417 case AR7_CHIP_7300: 418 ar7_dsp_clock = tnetd7300_dsp_clock(); 419 tnetd7300_init_clocks(); 420 break; 421 default: 422 break; 423 } 424 425 return 0; 426 } 427 arch_initcall(ar7_init_clocks); 428