s3c2443-clock.c 10 KB

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