s3c2443-clock.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  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 clk_i2s_ext = {
  176. .name = "i2s-ext",
  177. };
  178. /* i2s_eplldiv
  179. *
  180. * This clock is the output from the I2S divisor of ESYSCLK, and is separate
  181. * from the mux that comes after it (cannot merge into one single clock)
  182. */
  183. static struct clksrc_clk clk_i2s_eplldiv = {
  184. .clk = {
  185. .name = "i2s-eplldiv",
  186. .parent = &clk_esysclk.clk,
  187. },
  188. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
  189. };
  190. /* i2s-ref
  191. *
  192. * i2s bus reference clock, selectable from external, esysclk or epllref
  193. *
  194. * Note, this used to be two clocks, but was compressed into one.
  195. */
  196. static struct clk *clk_i2s_srclist[] = {
  197. [0] = &clk_i2s_eplldiv.clk,
  198. [1] = &clk_i2s_ext,
  199. [2] = &clk_epllref.clk,
  200. [3] = &clk_epllref.clk,
  201. };
  202. static struct clksrc_clk clk_i2s = {
  203. .clk = {
  204. .name = "i2s-if",
  205. .ctrlbit = S3C2443_SCLKCON_I2SCLK,
  206. .enable = s3c2443_clkcon_enable_s,
  207. },
  208. .sources = &(struct clksrc_sources) {
  209. .sources = clk_i2s_srclist,
  210. .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
  211. },
  212. .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
  213. };
  214. static struct clk init_clocks_off[] = {
  215. {
  216. .name = "iis",
  217. .parent = &clk_p,
  218. .enable = s3c2443_clkcon_enable_p,
  219. .ctrlbit = S3C2443_PCLKCON_IIS,
  220. }, {
  221. .name = "hsspi",
  222. .parent = &clk_p,
  223. .enable = s3c2443_clkcon_enable_p,
  224. .ctrlbit = S3C2443_PCLKCON_HSSPI,
  225. }, {
  226. .name = "adc",
  227. .parent = &clk_p,
  228. .enable = s3c2443_clkcon_enable_p,
  229. .ctrlbit = S3C2443_PCLKCON_ADC,
  230. }, {
  231. .name = "i2c",
  232. .parent = &clk_p,
  233. .enable = s3c2443_clkcon_enable_p,
  234. .ctrlbit = S3C2443_PCLKCON_IIC,
  235. }
  236. };
  237. static struct clk init_clocks[] = {
  238. {
  239. .name = "dma",
  240. .parent = &clk_h,
  241. .enable = s3c2443_clkcon_enable_h,
  242. .ctrlbit = S3C2443_HCLKCON_DMA0,
  243. }, {
  244. .name = "dma",
  245. .parent = &clk_h,
  246. .enable = s3c2443_clkcon_enable_h,
  247. .ctrlbit = S3C2443_HCLKCON_DMA1,
  248. }, {
  249. .name = "dma",
  250. .parent = &clk_h,
  251. .enable = s3c2443_clkcon_enable_h,
  252. .ctrlbit = S3C2443_HCLKCON_DMA2,
  253. }, {
  254. .name = "dma",
  255. .parent = &clk_h,
  256. .enable = s3c2443_clkcon_enable_h,
  257. .ctrlbit = S3C2443_HCLKCON_DMA3,
  258. }, {
  259. .name = "dma",
  260. .parent = &clk_h,
  261. .enable = s3c2443_clkcon_enable_h,
  262. .ctrlbit = S3C2443_HCLKCON_DMA4,
  263. }, {
  264. .name = "dma",
  265. .parent = &clk_h,
  266. .enable = s3c2443_clkcon_enable_h,
  267. .ctrlbit = S3C2443_HCLKCON_DMA5,
  268. }, {
  269. .name = "hsmmc",
  270. .parent = &clk_h,
  271. .enable = s3c2443_clkcon_enable_h,
  272. .ctrlbit = S3C2443_HCLKCON_HSMMC,
  273. }, {
  274. .name = "gpio",
  275. .parent = &clk_p,
  276. .enable = s3c2443_clkcon_enable_p,
  277. .ctrlbit = S3C2443_PCLKCON_GPIO,
  278. }, {
  279. .name = "usb-host",
  280. .parent = &clk_h,
  281. .enable = s3c2443_clkcon_enable_h,
  282. .ctrlbit = S3C2443_HCLKCON_USBH,
  283. }, {
  284. .name = "usb-device",
  285. .parent = &clk_h,
  286. .enable = s3c2443_clkcon_enable_h,
  287. .ctrlbit = S3C2443_HCLKCON_USBD,
  288. }, {
  289. .name = "lcd",
  290. .parent = &clk_h,
  291. .enable = s3c2443_clkcon_enable_h,
  292. .ctrlbit = S3C2443_HCLKCON_LCDC,
  293. }, {
  294. .name = "timers",
  295. .parent = &clk_p,
  296. .enable = s3c2443_clkcon_enable_p,
  297. .ctrlbit = S3C2443_PCLKCON_PWMT,
  298. }, {
  299. .name = "cfc",
  300. .parent = &clk_h,
  301. .enable = s3c2443_clkcon_enable_h,
  302. .ctrlbit = S3C2443_HCLKCON_CFC,
  303. }, {
  304. .name = "ssmc",
  305. .parent = &clk_h,
  306. .enable = s3c2443_clkcon_enable_h,
  307. .ctrlbit = S3C2443_HCLKCON_SSMC,
  308. }, {
  309. .name = "uart",
  310. .devname = "s3c2440-uart.0",
  311. .parent = &clk_p,
  312. .enable = s3c2443_clkcon_enable_p,
  313. .ctrlbit = S3C2443_PCLKCON_UART0,
  314. }, {
  315. .name = "uart",
  316. .devname = "s3c2440-uart.1",
  317. .parent = &clk_p,
  318. .enable = s3c2443_clkcon_enable_p,
  319. .ctrlbit = S3C2443_PCLKCON_UART1,
  320. }, {
  321. .name = "uart",
  322. .devname = "s3c2440-uart.2",
  323. .parent = &clk_p,
  324. .enable = s3c2443_clkcon_enable_p,
  325. .ctrlbit = S3C2443_PCLKCON_UART2,
  326. }, {
  327. .name = "uart",
  328. .devname = "s3c2440-uart.3",
  329. .parent = &clk_p,
  330. .enable = s3c2443_clkcon_enable_p,
  331. .ctrlbit = S3C2443_PCLKCON_UART3,
  332. }, {
  333. .name = "rtc",
  334. .parent = &clk_p,
  335. .enable = s3c2443_clkcon_enable_p,
  336. .ctrlbit = S3C2443_PCLKCON_RTC,
  337. }, {
  338. .name = "watchdog",
  339. .parent = &clk_p,
  340. .ctrlbit = S3C2443_PCLKCON_WDT,
  341. }, {
  342. .name = "ac97",
  343. .parent = &clk_p,
  344. .ctrlbit = S3C2443_PCLKCON_AC97,
  345. }, {
  346. .name = "nand",
  347. .parent = &clk_h,
  348. }, {
  349. .name = "usb-bus-host",
  350. .parent = &clk_usb_bus_host.clk,
  351. }
  352. };
  353. static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
  354. {
  355. clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
  356. return clkcon0 + 1;
  357. }
  358. /* EPLLCON compatible enough to get on/off information */
  359. void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll,
  360. fdiv_fn get_fdiv)
  361. {
  362. unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
  363. unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
  364. unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
  365. struct clk *xtal_clk;
  366. unsigned long xtal;
  367. unsigned long pll;
  368. unsigned long fclk;
  369. unsigned long hclk;
  370. unsigned long pclk;
  371. int ptr;
  372. xtal_clk = clk_get(NULL, "xtal");
  373. xtal = clk_get_rate(xtal_clk);
  374. clk_put(xtal_clk);
  375. pll = get_mpll(mpllcon, xtal);
  376. clk_msysclk.clk.rate = pll;
  377. fclk = pll / get_fdiv(clkdiv0);
  378. hclk = s3c2443_prediv_getrate(&clk_prediv);
  379. hclk /= s3c2443_get_hdiv(clkdiv0);
  380. pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
  381. s3c24xx_setup_clocks(fclk, hclk, pclk);
  382. printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
  383. (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  384. print_mhz(pll), print_mhz(fclk),
  385. print_mhz(hclk), print_mhz(pclk));
  386. for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
  387. s3c_set_clksrc(&clksrc_clks[ptr], true);
  388. /* ensure usb bus clock is within correct rate of 48MHz */
  389. if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
  390. printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
  391. clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
  392. }
  393. printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
  394. (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  395. print_mhz(clk_get_rate(&clk_epll)),
  396. print_mhz(clk_get_rate(&clk_usb_bus)));
  397. }
  398. static struct clk *clks[] __initdata = {
  399. &clk_prediv,
  400. &clk_mpllref,
  401. &clk_mdivclk,
  402. &clk_ext,
  403. &clk_epll,
  404. &clk_usb_bus,
  405. };
  406. static struct clksrc_clk *clksrcs[] __initdata = {
  407. &clk_i2s_eplldiv,
  408. &clk_i2s,
  409. &clk_usb_bus_host,
  410. &clk_epllref,
  411. &clk_esysclk,
  412. &clk_msysclk,
  413. };
  414. void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
  415. fdiv_fn get_fdiv)
  416. {
  417. int ptr;
  418. /* s3c2443 parents h and p clocks from prediv */
  419. clk_h.parent = &clk_prediv;
  420. clk_p.parent = &clk_prediv;
  421. clk_usb_bus.parent = &clk_usb_bus_host.clk;
  422. clk_epll.parent = &clk_epllref.clk;
  423. s3c24xx_register_baseclocks(xtal);
  424. s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
  425. for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
  426. s3c_register_clksrc(clksrcs[ptr], 1);
  427. s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
  428. s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
  429. /* See s3c2443/etc notes on disabling clocks at init time */
  430. s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  431. s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  432. s3c2443_common_setup_clocks(get_mpll, get_fdiv);
  433. }