s3c2443-clock.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. /* linux/arch/arm/plat-s3c24xx/s3c2443-clock.c
  2. *
  3. * Copyright (c) 2007, 2010 Simtec Electronics
  4. * Ben Dooks <ben@simtec.co.uk>
  5. *
  6. * S3C2443 Clock control suport - common code
  7. */
  8. #include <linux/init.h>
  9. #include <linux/clk.h>
  10. #include <linux/io.h>
  11. #include <mach/regs-s3c2443-clock.h>
  12. #include <plat/s3c2443.h>
  13. #include <plat/clock.h>
  14. #include <plat/clock-clksrc.h>
  15. #include <plat/cpu.h>
  16. #include <plat/cpu-freq.h>
  17. static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
  18. {
  19. u32 ctrlbit = clk->ctrlbit;
  20. u32 con = __raw_readl(reg);
  21. if (enable)
  22. con |= ctrlbit;
  23. else
  24. con &= ~ctrlbit;
  25. __raw_writel(con, reg);
  26. return 0;
  27. }
  28. int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
  29. {
  30. return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
  31. }
  32. int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
  33. {
  34. return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
  35. }
  36. int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
  37. {
  38. return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
  39. }
  40. /* mpllref is a direct descendant of clk_xtal by default, but it is not
  41. * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
  42. * such directly equating the two source clocks is impossible.
  43. */
  44. struct clk clk_mpllref = {
  45. .name = "mpllref",
  46. .parent = &clk_xtal,
  47. .id = -1,
  48. };
  49. static struct clk *clk_epllref_sources[] = {
  50. [0] = &clk_mpllref,
  51. [1] = &clk_mpllref,
  52. [2] = &clk_xtal,
  53. [3] = &clk_ext,
  54. };
  55. struct clksrc_clk clk_epllref = {
  56. .clk = {
  57. .name = "epllref",
  58. .id = -1,
  59. },
  60. .sources = &(struct clksrc_sources) {
  61. .sources = clk_epllref_sources,
  62. .nr_sources = ARRAY_SIZE(clk_epllref_sources),
  63. },
  64. .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
  65. };
  66. /* esysclk
  67. *
  68. * this is sourced from either the EPLL or the EPLLref clock
  69. */
  70. static struct clk *clk_sysclk_sources[] = {
  71. [0] = &clk_epllref.clk,
  72. [1] = &clk_epll,
  73. };
  74. struct clksrc_clk clk_esysclk = {
  75. .clk = {
  76. .name = "esysclk",
  77. .parent = &clk_epll,
  78. .id = -1,
  79. },
  80. .sources = &(struct clksrc_sources) {
  81. .sources = clk_sysclk_sources,
  82. .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
  83. },
  84. .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
  85. };
  86. static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
  87. {
  88. unsigned long parent_rate = clk_get_rate(clk->parent);
  89. unsigned long div = __raw_readl(S3C2443_CLKDIV0);
  90. div &= S3C2443_CLKDIV0_EXTDIV_MASK;
  91. div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
  92. return parent_rate / (div + 1);
  93. }
  94. static struct clk clk_mdivclk = {
  95. .name = "mdivclk",
  96. .parent = &clk_mpllref,
  97. .id = -1,
  98. .ops = &(struct clk_ops) {
  99. .get_rate = s3c2443_getrate_mdivclk,
  100. },
  101. };
  102. static struct clk *clk_msysclk_sources[] = {
  103. [0] = &clk_mpllref,
  104. [1] = &clk_mpll,
  105. [2] = &clk_mdivclk,
  106. [3] = &clk_mpllref,
  107. };
  108. struct clksrc_clk clk_msysclk = {
  109. .clk = {
  110. .name = "msysclk",
  111. .parent = &clk_xtal,
  112. .id = -1,
  113. },
  114. .sources = &(struct clksrc_sources) {
  115. .sources = clk_msysclk_sources,
  116. .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
  117. },
  118. .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
  119. };
  120. /* prediv
  121. *
  122. * this divides the msysclk down to pass to h/p/etc.
  123. */
  124. static unsigned long s3c2443_prediv_getrate(struct clk *clk)
  125. {
  126. unsigned long rate = clk_get_rate(clk->parent);
  127. unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
  128. clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
  129. clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
  130. return rate / (clkdiv0 + 1);
  131. }
  132. static struct clk clk_prediv = {
  133. .name = "prediv",
  134. .id = -1,
  135. .parent = &clk_msysclk.clk,
  136. .ops = &(struct clk_ops) {
  137. .get_rate = s3c2443_prediv_getrate,
  138. },
  139. };
  140. /* usbhost
  141. *
  142. * usb host bus-clock, usually 48MHz to provide USB bus clock timing
  143. */
  144. static struct clksrc_clk clk_usb_bus_host = {
  145. .clk = {
  146. .name = "usb-bus-host-parent",
  147. .id = -1,
  148. .parent = &clk_esysclk.clk,
  149. .ctrlbit = S3C2443_SCLKCON_USBHOST,
  150. .enable = s3c2443_clkcon_enable_s,
  151. },
  152. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
  153. };
  154. /* common clksrc clocks */
  155. static struct clksrc_clk clksrc_clks[] = {
  156. {
  157. /* ART baud-rate clock sourced from esysclk via a divisor */
  158. .clk = {
  159. .name = "uartclk",
  160. .id = -1,
  161. .parent = &clk_esysclk.clk,
  162. },
  163. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
  164. }, {
  165. /* camera interface bus-clock, divided down from esysclk */
  166. .clk = {
  167. .name = "camif-upll", /* same as 2440 name */
  168. .id = -1,
  169. .parent = &clk_esysclk.clk,
  170. .ctrlbit = S3C2443_SCLKCON_CAMCLK,
  171. .enable = s3c2443_clkcon_enable_s,
  172. },
  173. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
  174. }, {
  175. .clk = {
  176. .name = "display-if",
  177. .id = -1,
  178. .parent = &clk_esysclk.clk,
  179. .ctrlbit = S3C2443_SCLKCON_DISPCLK,
  180. .enable = s3c2443_clkcon_enable_s,
  181. },
  182. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
  183. },
  184. };
  185. static struct clk init_clocks_off[] = {
  186. {
  187. .name = "adc",
  188. .id = -1,
  189. .parent = &clk_p,
  190. .enable = s3c2443_clkcon_enable_p,
  191. .ctrlbit = S3C2443_PCLKCON_ADC,
  192. }, {
  193. .name = "i2c",
  194. .id = -1,
  195. .parent = &clk_p,
  196. .enable = s3c2443_clkcon_enable_p,
  197. .ctrlbit = S3C2443_PCLKCON_IIC,
  198. }
  199. };
  200. static struct clk init_clocks[] = {
  201. {
  202. .name = "dma",
  203. .id = 0,
  204. .parent = &clk_h,
  205. .enable = s3c2443_clkcon_enable_h,
  206. .ctrlbit = S3C2443_HCLKCON_DMA0,
  207. }, {
  208. .name = "dma",
  209. .id = 1,
  210. .parent = &clk_h,
  211. .enable = s3c2443_clkcon_enable_h,
  212. .ctrlbit = S3C2443_HCLKCON_DMA1,
  213. }, {
  214. .name = "dma",
  215. .id = 2,
  216. .parent = &clk_h,
  217. .enable = s3c2443_clkcon_enable_h,
  218. .ctrlbit = S3C2443_HCLKCON_DMA2,
  219. }, {
  220. .name = "dma",
  221. .id = 3,
  222. .parent = &clk_h,
  223. .enable = s3c2443_clkcon_enable_h,
  224. .ctrlbit = S3C2443_HCLKCON_DMA3,
  225. }, {
  226. .name = "dma",
  227. .id = 4,
  228. .parent = &clk_h,
  229. .enable = s3c2443_clkcon_enable_h,
  230. .ctrlbit = S3C2443_HCLKCON_DMA4,
  231. }, {
  232. .name = "dma",
  233. .id = 5,
  234. .parent = &clk_h,
  235. .enable = s3c2443_clkcon_enable_h,
  236. .ctrlbit = S3C2443_HCLKCON_DMA5,
  237. }, {
  238. .name = "hsmmc",
  239. .id = 1,
  240. .parent = &clk_h,
  241. .enable = s3c2443_clkcon_enable_h,
  242. .ctrlbit = S3C2443_HCLKCON_HSMMC,
  243. }, {
  244. .name = "gpio",
  245. .id = -1,
  246. .parent = &clk_p,
  247. .enable = s3c2443_clkcon_enable_p,
  248. .ctrlbit = S3C2443_PCLKCON_GPIO,
  249. }, {
  250. .name = "usb-host",
  251. .id = -1,
  252. .parent = &clk_h,
  253. .enable = s3c2443_clkcon_enable_h,
  254. .ctrlbit = S3C2443_HCLKCON_USBH,
  255. }, {
  256. .name = "usb-device",
  257. .id = -1,
  258. .parent = &clk_h,
  259. .enable = s3c2443_clkcon_enable_h,
  260. .ctrlbit = S3C2443_HCLKCON_USBD,
  261. }, {
  262. .name = "lcd",
  263. .id = -1,
  264. .parent = &clk_h,
  265. .enable = s3c2443_clkcon_enable_h,
  266. .ctrlbit = S3C2443_HCLKCON_LCDC,
  267. }, {
  268. .name = "timers",
  269. .id = -1,
  270. .parent = &clk_p,
  271. .enable = s3c2443_clkcon_enable_p,
  272. .ctrlbit = S3C2443_PCLKCON_PWMT,
  273. }, {
  274. .name = "cfc",
  275. .id = -1,
  276. .parent = &clk_h,
  277. .enable = s3c2443_clkcon_enable_h,
  278. .ctrlbit = S3C2443_HCLKCON_CFC,
  279. }, {
  280. .name = "ssmc",
  281. .id = -1,
  282. .parent = &clk_h,
  283. .enable = s3c2443_clkcon_enable_h,
  284. .ctrlbit = S3C2443_HCLKCON_SSMC,
  285. }, {
  286. .name = "uart",
  287. .id = 0,
  288. .parent = &clk_p,
  289. .enable = s3c2443_clkcon_enable_p,
  290. .ctrlbit = S3C2443_PCLKCON_UART0,
  291. }, {
  292. .name = "uart",
  293. .id = 1,
  294. .parent = &clk_p,
  295. .enable = s3c2443_clkcon_enable_p,
  296. .ctrlbit = S3C2443_PCLKCON_UART1,
  297. }, {
  298. .name = "uart",
  299. .id = 2,
  300. .parent = &clk_p,
  301. .enable = s3c2443_clkcon_enable_p,
  302. .ctrlbit = S3C2443_PCLKCON_UART2,
  303. }, {
  304. .name = "uart",
  305. .id = 3,
  306. .parent = &clk_p,
  307. .enable = s3c2443_clkcon_enable_p,
  308. .ctrlbit = S3C2443_PCLKCON_UART3,
  309. }, {
  310. .name = "rtc",
  311. .id = -1,
  312. .parent = &clk_p,
  313. .enable = s3c2443_clkcon_enable_p,
  314. .ctrlbit = S3C2443_PCLKCON_RTC,
  315. }, {
  316. .name = "watchdog",
  317. .id = -1,
  318. .parent = &clk_p,
  319. .ctrlbit = S3C2443_PCLKCON_WDT,
  320. }, {
  321. .name = "ac97",
  322. .id = -1,
  323. .parent = &clk_p,
  324. .ctrlbit = S3C2443_PCLKCON_AC97,
  325. }, {
  326. .name = "nand",
  327. .id = -1,
  328. .parent = &clk_h,
  329. }, {
  330. .name = "usb-bus-host",
  331. .id = -1,
  332. .parent = &clk_usb_bus_host.clk,
  333. }
  334. };
  335. static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
  336. {
  337. clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
  338. return clkcon0 + 1;
  339. }
  340. /* EPLLCON compatible enough to get on/off information */
  341. void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll,
  342. fdiv_fn get_fdiv)
  343. {
  344. unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
  345. unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
  346. unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
  347. struct clk *xtal_clk;
  348. unsigned long xtal;
  349. unsigned long pll;
  350. unsigned long fclk;
  351. unsigned long hclk;
  352. unsigned long pclk;
  353. int ptr;
  354. xtal_clk = clk_get(NULL, "xtal");
  355. xtal = clk_get_rate(xtal_clk);
  356. clk_put(xtal_clk);
  357. pll = get_mpll(mpllcon, xtal);
  358. clk_msysclk.clk.rate = pll;
  359. fclk = pll / get_fdiv(clkdiv0);
  360. hclk = s3c2443_prediv_getrate(&clk_prediv);
  361. hclk /= s3c2443_get_hdiv(clkdiv0);
  362. pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
  363. s3c24xx_setup_clocks(fclk, hclk, pclk);
  364. printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
  365. (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  366. print_mhz(pll), print_mhz(fclk),
  367. print_mhz(hclk), print_mhz(pclk));
  368. for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
  369. s3c_set_clksrc(&clksrc_clks[ptr], true);
  370. /* ensure usb bus clock is within correct rate of 48MHz */
  371. if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
  372. printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
  373. clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
  374. }
  375. printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
  376. (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  377. print_mhz(clk_get_rate(&clk_epll)),
  378. print_mhz(clk_get_rate(&clk_usb_bus)));
  379. }
  380. static struct clk *clks[] __initdata = {
  381. &clk_prediv,
  382. &clk_mpllref,
  383. &clk_mdivclk,
  384. &clk_ext,
  385. &clk_epll,
  386. &clk_usb_bus,
  387. };
  388. static struct clksrc_clk *clksrcs[] __initdata = {
  389. &clk_usb_bus_host,
  390. &clk_epllref,
  391. &clk_esysclk,
  392. &clk_msysclk,
  393. };
  394. void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
  395. fdiv_fn get_fdiv)
  396. {
  397. int ptr;
  398. /* s3c2443 parents h and p clocks from prediv */
  399. clk_h.parent = &clk_prediv;
  400. clk_p.parent = &clk_prediv;
  401. clk_usb_bus.parent = &clk_usb_bus_host.clk;
  402. clk_epll.parent = &clk_epllref.clk;
  403. s3c24xx_register_baseclocks(xtal);
  404. s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
  405. for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
  406. s3c_register_clksrc(clksrcs[ptr], 1);
  407. s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
  408. s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
  409. /* See s3c2443/etc notes on disabling clocks at init time */
  410. s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  411. s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  412. s3c2443_common_setup_clocks(get_mpll, get_fdiv);
  413. }