clock.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  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. #include <linux/kernel.h>
  20. #include <linux/init.h>
  21. #include <linux/types.h>
  22. #include <linux/module.h>
  23. #include <linux/delay.h>
  24. #include <linux/gcd.h>
  25. #include <linux/io.h>
  26. #include <asm/addrspace.h>
  27. #include <asm/mach-ar7/ar7.h>
  28. #define BOOT_PLL_SOURCE_MASK 0x3
  29. #define CPU_PLL_SOURCE_SHIFT 16
  30. #define BUS_PLL_SOURCE_SHIFT 14
  31. #define USB_PLL_SOURCE_SHIFT 18
  32. #define DSP_PLL_SOURCE_SHIFT 22
  33. #define BOOT_PLL_SOURCE_AFE 0
  34. #define BOOT_PLL_SOURCE_BUS 0
  35. #define BOOT_PLL_SOURCE_REF 1
  36. #define BOOT_PLL_SOURCE_XTAL 2
  37. #define BOOT_PLL_SOURCE_CPU 3
  38. #define BOOT_PLL_BYPASS 0x00000020
  39. #define BOOT_PLL_ASYNC_MODE 0x02000000
  40. #define BOOT_PLL_2TO1_MODE 0x00008000
  41. #define TNETD7200_CLOCK_ID_CPU 0
  42. #define TNETD7200_CLOCK_ID_DSP 1
  43. #define TNETD7200_CLOCK_ID_USB 2
  44. #define TNETD7200_DEF_CPU_CLK 211000000
  45. #define TNETD7200_DEF_DSP_CLK 125000000
  46. #define TNETD7200_DEF_USB_CLK 48000000
  47. struct tnetd7300_clock {
  48. u32 ctrl;
  49. #define PREDIV_MASK 0x001f0000
  50. #define PREDIV_SHIFT 16
  51. #define POSTDIV_MASK 0x0000001f
  52. u32 unused1[3];
  53. u32 pll;
  54. #define MUL_MASK 0x0000f000
  55. #define MUL_SHIFT 12
  56. #define PLL_MODE_MASK 0x00000001
  57. #define PLL_NDIV 0x00000800
  58. #define PLL_DIV 0x00000002
  59. #define PLL_STATUS 0x00000001
  60. u32 unused2[3];
  61. };
  62. struct tnetd7300_clocks {
  63. struct tnetd7300_clock bus;
  64. struct tnetd7300_clock cpu;
  65. struct tnetd7300_clock usb;
  66. struct tnetd7300_clock dsp;
  67. };
  68. struct tnetd7200_clock {
  69. u32 ctrl;
  70. u32 unused1[3];
  71. #define DIVISOR_ENABLE_MASK 0x00008000
  72. u32 mul;
  73. u32 prediv;
  74. u32 postdiv;
  75. u32 postdiv2;
  76. u32 unused2[6];
  77. u32 cmd;
  78. u32 status;
  79. u32 cmden;
  80. u32 padding[15];
  81. };
  82. struct tnetd7200_clocks {
  83. struct tnetd7200_clock cpu;
  84. struct tnetd7200_clock dsp;
  85. struct tnetd7200_clock usb;
  86. };
  87. int ar7_cpu_clock = 150000000;
  88. EXPORT_SYMBOL(ar7_cpu_clock);
  89. int ar7_bus_clock = 125000000;
  90. EXPORT_SYMBOL(ar7_bus_clock);
  91. int ar7_dsp_clock;
  92. EXPORT_SYMBOL(ar7_dsp_clock);
  93. static void approximate(int base, int target, int *prediv,
  94. int *postdiv, int *mul)
  95. {
  96. int i, j, k, freq, res = target;
  97. for (i = 1; i <= 16; i++)
  98. for (j = 1; j <= 32; j++)
  99. for (k = 1; k <= 32; k++) {
  100. freq = abs(base / j * i / k - target);
  101. if (freq < res) {
  102. res = freq;
  103. *mul = i;
  104. *prediv = j;
  105. *postdiv = k;
  106. }
  107. }
  108. }
  109. static void calculate(int base, int target, int *prediv, int *postdiv,
  110. int *mul)
  111. {
  112. int tmp_gcd, tmp_base, tmp_freq;
  113. for (*prediv = 1; *prediv <= 32; (*prediv)++) {
  114. tmp_base = base / *prediv;
  115. tmp_gcd = gcd(target, tmp_base);
  116. *mul = target / tmp_gcd;
  117. *postdiv = tmp_base / tmp_gcd;
  118. if ((*mul < 1) || (*mul >= 16))
  119. continue;
  120. if ((*postdiv > 0) & (*postdiv <= 32))
  121. break;
  122. }
  123. if (base / *prediv * *mul / *postdiv != target) {
  124. approximate(base, target, prediv, postdiv, mul);
  125. tmp_freq = base / *prediv * *mul / *postdiv;
  126. printk(KERN_WARNING
  127. "Adjusted requested frequency %d to %d\n",
  128. target, tmp_freq);
  129. }
  130. printk(KERN_DEBUG "Clocks: prediv: %d, postdiv: %d, mul: %d\n",
  131. *prediv, *postdiv, *mul);
  132. }
  133. static int tnetd7300_dsp_clock(void)
  134. {
  135. u32 didr1, didr2;
  136. u8 rev = ar7_chip_rev();
  137. didr1 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x18));
  138. didr2 = readl((void *)KSEG1ADDR(AR7_REGS_GPIO + 0x1c));
  139. if (didr2 & (1 << 23))
  140. return 0;
  141. if ((rev >= 0x23) && (rev != 0x57))
  142. return 250000000;
  143. if ((((didr2 & 0x1fff) << 10) | ((didr1 & 0xffc00000) >> 22))
  144. > 4208000)
  145. return 250000000;
  146. return 0;
  147. }
  148. static int tnetd7300_get_clock(u32 shift, struct tnetd7300_clock *clock,
  149. u32 *bootcr, u32 bus_clock)
  150. {
  151. int product;
  152. int base_clock = AR7_REF_CLOCK;
  153. u32 ctrl = readl(&clock->ctrl);
  154. u32 pll = readl(&clock->pll);
  155. int prediv = ((ctrl & PREDIV_MASK) >> PREDIV_SHIFT) + 1;
  156. int postdiv = (ctrl & POSTDIV_MASK) + 1;
  157. int divisor = prediv * postdiv;
  158. int mul = ((pll & MUL_MASK) >> MUL_SHIFT) + 1;
  159. switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
  160. case BOOT_PLL_SOURCE_BUS:
  161. base_clock = bus_clock;
  162. break;
  163. case BOOT_PLL_SOURCE_REF:
  164. base_clock = AR7_REF_CLOCK;
  165. break;
  166. case BOOT_PLL_SOURCE_XTAL:
  167. base_clock = AR7_XTAL_CLOCK;
  168. break;
  169. case BOOT_PLL_SOURCE_CPU:
  170. base_clock = ar7_cpu_clock;
  171. break;
  172. }
  173. if (*bootcr & BOOT_PLL_BYPASS)
  174. return base_clock / divisor;
  175. if ((pll & PLL_MODE_MASK) == 0)
  176. return (base_clock >> (mul / 16 + 1)) / divisor;
  177. if ((pll & (PLL_NDIV | PLL_DIV)) == (PLL_NDIV | PLL_DIV)) {
  178. product = (mul & 1) ?
  179. (base_clock * mul) >> 1 :
  180. (base_clock * (mul - 1)) >> 2;
  181. return product / divisor;
  182. }
  183. if (mul == 16)
  184. return base_clock / divisor;
  185. return base_clock * mul / divisor;
  186. }
  187. static void tnetd7300_set_clock(u32 shift, struct tnetd7300_clock *clock,
  188. u32 *bootcr, u32 frequency)
  189. {
  190. int prediv, postdiv, mul;
  191. int base_clock = ar7_bus_clock;
  192. switch ((*bootcr & (BOOT_PLL_SOURCE_MASK << shift)) >> shift) {
  193. case BOOT_PLL_SOURCE_BUS:
  194. base_clock = ar7_bus_clock;
  195. break;
  196. case BOOT_PLL_SOURCE_REF:
  197. base_clock = AR7_REF_CLOCK;
  198. break;
  199. case BOOT_PLL_SOURCE_XTAL:
  200. base_clock = AR7_XTAL_CLOCK;
  201. break;
  202. case BOOT_PLL_SOURCE_CPU:
  203. base_clock = ar7_cpu_clock;
  204. break;
  205. }
  206. calculate(base_clock, frequency, &prediv, &postdiv, &mul);
  207. writel(((prediv - 1) << PREDIV_SHIFT) | (postdiv - 1), &clock->ctrl);
  208. msleep(1);
  209. writel(4, &clock->pll);
  210. while (readl(&clock->pll) & PLL_STATUS)
  211. ;
  212. writel(((mul - 1) << MUL_SHIFT) | (0xff << 3) | 0x0e, &clock->pll);
  213. msleep(75);
  214. }
  215. static void __init tnetd7300_init_clocks(void)
  216. {
  217. u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
  218. struct tnetd7300_clocks *clocks =
  219. ioremap_nocache(UR8_REGS_CLOCKS,
  220. sizeof(struct tnetd7300_clocks));
  221. ar7_bus_clock = tnetd7300_get_clock(BUS_PLL_SOURCE_SHIFT,
  222. &clocks->bus, bootcr, AR7_AFE_CLOCK);
  223. if (*bootcr & BOOT_PLL_ASYNC_MODE)
  224. ar7_cpu_clock = tnetd7300_get_clock(CPU_PLL_SOURCE_SHIFT,
  225. &clocks->cpu, bootcr, AR7_AFE_CLOCK);
  226. else
  227. ar7_cpu_clock = ar7_bus_clock;
  228. if (ar7_dsp_clock == 250000000)
  229. tnetd7300_set_clock(DSP_PLL_SOURCE_SHIFT, &clocks->dsp,
  230. bootcr, ar7_dsp_clock);
  231. iounmap(clocks);
  232. iounmap(bootcr);
  233. }
  234. static void tnetd7200_set_clock(int base, struct tnetd7200_clock *clock,
  235. int prediv, int postdiv, int postdiv2, int mul, u32 frequency)
  236. {
  237. printk(KERN_INFO
  238. "Clocks: base = %d, frequency = %u, prediv = %d, "
  239. "postdiv = %d, postdiv2 = %d, mul = %d\n",
  240. base, frequency, prediv, postdiv, postdiv2, mul);
  241. writel(0, &clock->ctrl);
  242. writel(DIVISOR_ENABLE_MASK | ((prediv - 1) & 0x1F), &clock->prediv);
  243. writel((mul - 1) & 0xF, &clock->mul);
  244. while (readl(&clock->status) & 0x1)
  245. ; /* nop */
  246. writel(DIVISOR_ENABLE_MASK | ((postdiv - 1) & 0x1F), &clock->postdiv);
  247. writel(readl(&clock->cmden) | 1, &clock->cmden);
  248. writel(readl(&clock->cmd) | 1, &clock->cmd);
  249. while (readl(&clock->status) & 0x1)
  250. ; /* nop */
  251. writel(DIVISOR_ENABLE_MASK | ((postdiv2 - 1) & 0x1F), &clock->postdiv2);
  252. writel(readl(&clock->cmden) | 1, &clock->cmden);
  253. writel(readl(&clock->cmd) | 1, &clock->cmd);
  254. while (readl(&clock->status) & 0x1)
  255. ; /* nop */
  256. writel(readl(&clock->ctrl) | 1, &clock->ctrl);
  257. }
  258. static int tnetd7200_get_clock_base(int clock_id, u32 *bootcr)
  259. {
  260. if (*bootcr & BOOT_PLL_ASYNC_MODE)
  261. /* Async */
  262. switch (clock_id) {
  263. case TNETD7200_CLOCK_ID_DSP:
  264. return AR7_REF_CLOCK;
  265. default:
  266. return AR7_AFE_CLOCK;
  267. }
  268. else
  269. /* Sync */
  270. if (*bootcr & BOOT_PLL_2TO1_MODE)
  271. /* 2:1 */
  272. switch (clock_id) {
  273. case TNETD7200_CLOCK_ID_DSP:
  274. return AR7_REF_CLOCK;
  275. default:
  276. return AR7_AFE_CLOCK;
  277. }
  278. else
  279. /* 1:1 */
  280. return AR7_REF_CLOCK;
  281. }
  282. static void __init tnetd7200_init_clocks(void)
  283. {
  284. u32 *bootcr = (u32 *)ioremap_nocache(AR7_REGS_DCL, 4);
  285. struct tnetd7200_clocks *clocks =
  286. ioremap_nocache(AR7_REGS_CLOCKS,
  287. sizeof(struct tnetd7200_clocks));
  288. int cpu_base, cpu_mul, cpu_prediv, cpu_postdiv;
  289. int dsp_base, dsp_mul, dsp_prediv, dsp_postdiv;
  290. int usb_base, usb_mul, usb_prediv, usb_postdiv;
  291. cpu_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_CPU, bootcr);
  292. dsp_base = tnetd7200_get_clock_base(TNETD7200_CLOCK_ID_DSP, bootcr);
  293. if (*bootcr & BOOT_PLL_ASYNC_MODE) {
  294. printk(KERN_INFO "Clocks: Async mode\n");
  295. printk(KERN_INFO "Clocks: Setting DSP clock\n");
  296. calculate(dsp_base, TNETD7200_DEF_DSP_CLK,
  297. &dsp_prediv, &dsp_postdiv, &dsp_mul);
  298. ar7_bus_clock =
  299. ((dsp_base / dsp_prediv) * dsp_mul) / dsp_postdiv;
  300. tnetd7200_set_clock(dsp_base, &clocks->dsp,
  301. dsp_prediv, dsp_postdiv * 2, dsp_postdiv, dsp_mul * 2,
  302. ar7_bus_clock);
  303. printk(KERN_INFO "Clocks: Setting CPU clock\n");
  304. calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
  305. &cpu_postdiv, &cpu_mul);
  306. ar7_cpu_clock =
  307. ((cpu_base / cpu_prediv) * cpu_mul) / cpu_postdiv;
  308. tnetd7200_set_clock(cpu_base, &clocks->cpu,
  309. cpu_prediv, cpu_postdiv, -1, cpu_mul,
  310. ar7_cpu_clock);
  311. } else
  312. if (*bootcr & BOOT_PLL_2TO1_MODE) {
  313. printk(KERN_INFO "Clocks: Sync 2:1 mode\n");
  314. printk(KERN_INFO "Clocks: Setting CPU clock\n");
  315. calculate(cpu_base, TNETD7200_DEF_CPU_CLK, &cpu_prediv,
  316. &cpu_postdiv, &cpu_mul);
  317. ar7_cpu_clock = ((cpu_base / cpu_prediv) * cpu_mul)
  318. / cpu_postdiv;
  319. tnetd7200_set_clock(cpu_base, &clocks->cpu,
  320. cpu_prediv, cpu_postdiv, -1, cpu_mul,
  321. ar7_cpu_clock);
  322. printk(KERN_INFO "Clocks: Setting DSP clock\n");
  323. calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
  324. &dsp_postdiv, &dsp_mul);
  325. ar7_bus_clock = ar7_cpu_clock / 2;
  326. tnetd7200_set_clock(dsp_base, &clocks->dsp,
  327. dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
  328. dsp_mul * 2, ar7_bus_clock);
  329. } else {
  330. printk(KERN_INFO "Clocks: Sync 1:1 mode\n");
  331. printk(KERN_INFO "Clocks: Setting DSP clock\n");
  332. calculate(dsp_base, TNETD7200_DEF_DSP_CLK, &dsp_prediv,
  333. &dsp_postdiv, &dsp_mul);
  334. ar7_bus_clock = ((dsp_base / dsp_prediv) * dsp_mul)
  335. / dsp_postdiv;
  336. tnetd7200_set_clock(dsp_base, &clocks->dsp,
  337. dsp_prediv, dsp_postdiv * 2, dsp_postdiv,
  338. dsp_mul * 2, ar7_bus_clock);
  339. ar7_cpu_clock = ar7_bus_clock;
  340. }
  341. printk(KERN_INFO "Clocks: Setting USB clock\n");
  342. usb_base = ar7_bus_clock;
  343. calculate(usb_base, TNETD7200_DEF_USB_CLK, &usb_prediv,
  344. &usb_postdiv, &usb_mul);
  345. tnetd7200_set_clock(usb_base, &clocks->usb,
  346. usb_prediv, usb_postdiv, -1, usb_mul,
  347. TNETD7200_DEF_USB_CLK);
  348. ar7_dsp_clock = ar7_cpu_clock;
  349. iounmap(clocks);
  350. iounmap(bootcr);
  351. }
  352. int __init ar7_init_clocks(void)
  353. {
  354. switch (ar7_chip_id()) {
  355. case AR7_CHIP_7100:
  356. case AR7_CHIP_7200:
  357. tnetd7200_init_clocks();
  358. break;
  359. case AR7_CHIP_7300:
  360. ar7_dsp_clock = tnetd7300_dsp_clock();
  361. tnetd7300_init_clocks();
  362. break;
  363. default:
  364. break;
  365. }
  366. return 0;
  367. }
  368. arch_initcall(ar7_init_clocks);