clk_set.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include <linux/module.h>
  2. #include <linux/delay.h>
  3. #include <mach/am_regs.h>
  4. #include <mach/clk_set.h>
  5. struct pll_reg_table {
  6. unsigned long xtal_clk;
  7. unsigned long out_clk;
  8. unsigned long settings;
  9. };
  10. unsigned long get_xtal_clock(void)
  11. {
  12. unsigned long clk;
  13. clk = READ_CBUS_REG_BITS(PREG_CTLREG0_ADDR, 4, 5);
  14. clk = clk * 1000 * 1000;
  15. return clk;
  16. }
  17. /*
  18. Get two number's max common divisor;
  19. */
  20. static int get_max_common_divisor(int a, int b)
  21. {
  22. while (b) {
  23. int temp = b;
  24. b = a % b;
  25. a = temp;
  26. }
  27. return a;
  28. }
  29. /*
  30. select clk:
  31. 5,6,7 sata
  32. 4-extern pad
  33. 3-other_pll_clk
  34. 2-ddr_pll_clk
  35. 1-APLL_CLK_OUT_400M
  36. 0----sys_pll_div3 (333~400Mhz)
  37. clk_freq:50M=50000000
  38. output_clk:50000000;
  39. aways,maybe changed for others?
  40. */
  41. int eth_clk_set(int selectclk, unsigned long clk_freq, unsigned long out_clk)
  42. {
  43. int n = 1;
  44. int clk = READ_CBUS_REG(HHI_ETH_CLK_CNTL);
  45. printk("select eth clk-%d,source=%ld,out=%ld,reg=%x\n", selectclk,
  46. clk_freq, out_clk, clk);
  47. if (out_clk == 0) {
  48. WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, clk & (~(1 << 8)) //disable clk
  49. );
  50. } else {
  51. if (((clk_freq) % out_clk) != 0) {
  52. printk(KERN_ERR
  53. "ERROR:source clk must n times of out_clk=%ld ,source clk=%ld\n",
  54. out_clk, clk_freq);
  55. return -1;
  56. } else {
  57. n = (int)((clk_freq) / out_clk);
  58. }
  59. WRITE_CBUS_REG(HHI_ETH_CLK_CNTL, (n - 1) << 0 | selectclk << 9 | 1 << 8 //enable clk
  60. );
  61. }
  62. //writel(0x70b,(0xc1100000+0x1076*4)); // enable Ethernet clocks for other clock 600/12
  63. //writel(0x107,(0xc1100000+0x1076*4)); // enable Ethernet clocks for sys clock 1200/3/8
  64. udelay(100);
  65. clk = READ_CBUS_REG_BITS(HHI_ETH_CLK_CNTL, 0, 32);
  66. printk("after clk set : reg=%x\n", clk);
  67. return 0;
  68. }
  69. int auto_select_eth_clk(void)
  70. {
  71. return -1;
  72. }
  73. /*
  74. out_freq=crystal_req*m/n
  75. out_freq=crystal_req*m/n-->
  76. n=crystal_req*m/out_freq
  77. m=out_freq*n/crystal_req
  78. */
  79. int demod_apll_setting(unsigned crystal_req, unsigned out_freq)
  80. {
  81. int n, m;
  82. unsigned long crys_M, out_M, middle_freq;
  83. if (!crystal_req)
  84. crystal_req = get_xtal_clock();
  85. crys_M = crystal_req / 1000000;
  86. out_M = out_freq / 1000000;
  87. middle_freq = get_max_common_divisor(crys_M, out_M);
  88. n = crys_M / middle_freq;
  89. m = out_M / (middle_freq);
  90. if (n > (1 << 5) - 1) {
  91. printk(KERN_ERR
  92. "demod_apll_setting setting error, n is too bigger n=%d,crys_M=%ldM,out_M=%ldM\n",
  93. n, crys_M, out_M);
  94. return -1;
  95. }
  96. if (m > (1 << 9) - 1) {
  97. printk(KERN_ERR
  98. "demod_apll_setting setting error, m is too bigger m=%d,crys_M=%ldM,out_M=%ldM\n",
  99. m, crys_M, out_M);
  100. return -2;
  101. }
  102. printk("demod_apll_setting crystal_req=%ld,out_freq=%ld,n=%d,m=%dM\n",
  103. crys_M, out_M, n, m);
  104. /*==========Set Demod PLL, should be in system setting===========*/
  105. //Set 1.2G PLL
  106. CLEAR_CBUS_REG_MASK(HHI_DEMOD_PLL_CNTL, 0xFFFFFFFF);
  107. SET_CBUS_REG_MASK(HHI_DEMOD_PLL_CNTL, n << 9 | m << 0); //
  108. //Set 400M PLL
  109. CLEAR_CBUS_REG_MASK(HHI_DEMOD_PLL_CNTL3, 0xFFFF0000);
  110. SET_CBUS_REG_MASK(HHI_DEMOD_PLL_CNTL3, 0x0C850000); //400M 300M 240M enable
  111. return 0;
  112. }
  113. static unsigned pll_setting[17] = {
  114. 0x211,
  115. 0x215,
  116. 0x219,
  117. 0x21d,
  118. 0x221,
  119. 0x225,
  120. 0x229,
  121. 0x22d,
  122. 0x231,
  123. 0x235,
  124. 0x239,
  125. 0x23d,
  126. 0x242,
  127. 0x243,
  128. 0x244,
  129. 0x245,
  130. 0x246
  131. };
  132. int sys_clkpll_setting(unsigned crystal_freq, unsigned out_freq)
  133. {
  134. unsigned long crys_M, out_M, flags;
  135. if (!crystal_freq)
  136. crystal_freq = get_xtal_clock();
  137. crys_M = crystal_freq / 1000000;
  138. out_M = out_freq / 2000000;
  139. if (READ_MPEG_REG(HHI_SYS_PLL_CNTL) != pll_setting[(out_M - 200) / 50]) {
  140. local_irq_save(flags);
  141. WRITE_MPEG_REG(HHI_SYS_PLL_CNTL, pll_setting[(out_M - 200) / 50]); // system PLL
  142. WRITE_MPEG_REG(HHI_A9_CLK_CNTL, // A9 clk set to system clock/2
  143. (0 << 10) | // 0 - sys_pll_clk, 1 - audio_pll_clk
  144. (1 << 0) | // 1 - sys/audio pll clk, 0 - XTAL
  145. (1 << 4) | // APB_CLK_ENABLE
  146. (1 << 5) | // AT_CLK_ENABLE
  147. (0 << 2) | // div1
  148. (1 << 7)); // Connect A9 to the PLL divider output
  149. udelay(10);
  150. local_irq_restore(flags);
  151. //printk(KERN_INFO "a9_clk = %ldMHz\n", out_M);
  152. }
  153. return 0;
  154. }
  155. int other_pll_setting(unsigned crystal_freq, unsigned out_freq)
  156. {
  157. int n, m, od;
  158. unsigned long crys_M, out_M, middle_freq;
  159. if (!crystal_freq)
  160. crystal_freq = get_xtal_clock();
  161. crys_M = crystal_freq / 1000000;
  162. out_M = out_freq / 1000000;
  163. if (out_M < 400) { /*if <400M, Od=1 */
  164. od = 1; /*out=pll_out/(1<<od)
  165. */
  166. out_M = out_M << 1;
  167. } else {
  168. od = 0;
  169. }
  170. middle_freq = get_max_common_divisor(crys_M, out_M);
  171. n = crys_M / middle_freq;
  172. m = out_M / (middle_freq);
  173. if (n > (1 << 5) - 1) {
  174. printk(KERN_ERR
  175. "other_pll_setting error, n is too bigger n=%d,crys_M=%ldM,out=%ldM\n",
  176. n, crys_M, out_M);
  177. return -1;
  178. }
  179. if (m > (1 << 9) - 1) {
  180. printk(KERN_ERR
  181. "other_pll_setting error, m is too bigger m=%d,crys_M=%ldM,out=%ldM\n",
  182. m, crys_M, out_M);
  183. return -2;
  184. }
  185. WRITE_MPEG_REG(HHI_OTHER_PLL_CNTL, m | n << 9 | (od & 1) << 16); // other PLL
  186. printk(KERN_INFO
  187. "other pll setting to crystal_req=%ld,out_freq=%ld,n=%d,m=%d,od=%d\n",
  188. crys_M, out_M / (od + 1), n, m, od);
  189. return 0;
  190. }
  191. int audio_pll_setting(unsigned crystal_freq, unsigned out_freq)
  192. {
  193. int n, m, od;
  194. unsigned long crys_M, out_M, middle_freq;
  195. /*
  196. FIXME:If we need can't exact setting this clock,Can used a pll table?
  197. */
  198. if (!crystal_freq)
  199. crystal_freq = get_xtal_clock();
  200. crys_M = crystal_freq / 1000000;
  201. out_M = out_freq / 1000000;
  202. if (out_M < 400) { /*if <400M, Od=1 */
  203. od = 1; /*out=pll_out/(1<<od)
  204. */
  205. out_M = out_M << 1;
  206. } else {
  207. od = 0;
  208. }
  209. middle_freq = get_max_common_divisor(crys_M, out_M);
  210. n = crys_M / middle_freq;
  211. m = out_M / (middle_freq);
  212. if (n > (1 << 5) - 1) {
  213. printk(KERN_ERR
  214. "audio_pll_setting error, n is too bigger n=%d,crys_M=%ldM,out=%ldM\n",
  215. n, crys_M, out_M);
  216. return -1;
  217. }
  218. if (m > (1 << 9) - 1) {
  219. printk(KERN_ERR
  220. "audio_pll_setting error, m is too bigger m=%d,crys_M=%ldM,out=%ldM\n",
  221. m, crys_M, out_M);
  222. return -2;
  223. }
  224. WRITE_MPEG_REG(HHI_AUD_PLL_CNTL, m | n << 9 | (od & 1) << 14); // other PLL
  225. printk(KERN_INFO
  226. "audio_pll_setting to crystal_req=%ld,out_freq=%ld,n=%d,m=%d,od=%d\n",
  227. crys_M, out_M / (od + 1), n, m, od);
  228. return 0;
  229. }
  230. int video_pll_setting(unsigned crystal_freq, unsigned out_freq, int powerdown,
  231. int flags)
  232. {
  233. int n, m, od;
  234. unsigned long crys_M, out_M, middle_freq;
  235. int ret = 0;
  236. /*
  237. flags can used for od1/xd settings
  238. FIXME:If we need can't exact setting this clock,Can used a pll table?
  239. */
  240. if (!crystal_freq)
  241. crystal_freq = get_xtal_clock();
  242. crys_M = crystal_freq / 1000000;
  243. out_M = out_freq / 1000000;
  244. if (out_M < 400) { /*if <400M, Od=1 */
  245. od = 1; /*out=pll_out/(1<<od)
  246. */
  247. out_M = out_M << 1;
  248. } else {
  249. od = 0;
  250. }
  251. middle_freq = get_max_common_divisor(crys_M, out_M);
  252. n = crys_M / middle_freq;
  253. m = out_M / (middle_freq);
  254. if (n > (1 << 5) - 1) {
  255. printk(KERN_ERR
  256. "video_pll_setting error, n is too bigger n=%d,crys_M=%ldM,out=%ldM\n",
  257. n, crys_M, out_M);
  258. ret = -1;
  259. }
  260. if (m > (1 << 9) - 1) {
  261. printk(KERN_ERR
  262. "video_pll_setting error, m is too bigger m=%d,crys_M=%ldM,out=%ldM\n",
  263. m, crys_M, out_M);
  264. ret = -2;
  265. }
  266. if (ret)
  267. return ret;
  268. WRITE_MPEG_REG(HHI_VID_PLL_CNTL, m | n << 9 | (od & 1) << 16 | (!!powerdown) << 15 /*is power down mode? */
  269. ); // other PLL
  270. printk(KERN_INFO
  271. "video_pll_setting to crystal_req=%ld,out_freq=%ld,n=%d,m=%d,od=%d\n",
  272. crys_M, out_M / (od + 1), n, m, od);
  273. return 0;
  274. }