s3c2443-clock.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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. /* armdiv
  135. *
  136. * this clock is sourced from msysclk and can have a number of
  137. * divider values applied to it to then be fed into armclk.
  138. */
  139. static unsigned int *armdiv;
  140. static int nr_armdiv;
  141. static int armdivmask;
  142. static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
  143. unsigned long rate)
  144. {
  145. unsigned long parent = clk_get_rate(clk->parent);
  146. unsigned long calc;
  147. unsigned best = 256; /* bigger than any value */
  148. unsigned div;
  149. int ptr;
  150. for (ptr = 0; ptr < nr_armdiv; ptr++) {
  151. div = armdiv[ptr];
  152. calc = parent / div;
  153. if (calc <= rate && div < best)
  154. best = div;
  155. }
  156. return parent / best;
  157. }
  158. static unsigned long s3c2443_armclk_getrate(struct clk *clk)
  159. {
  160. unsigned long rate = clk_get_rate(clk->parent);
  161. unsigned long clkcon0;
  162. int val;
  163. clkcon0 = __raw_readl(S3C2443_CLKDIV0);
  164. clkcon0 &= armdivmask;
  165. val = clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT;
  166. return rate / armdiv[val];
  167. }
  168. static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
  169. {
  170. unsigned long parent = clk_get_rate(clk->parent);
  171. unsigned long calc;
  172. unsigned div;
  173. unsigned best = 256; /* bigger than any value */
  174. int ptr;
  175. int val = -1;
  176. for (ptr = 0; ptr < nr_armdiv; ptr++) {
  177. div = armdiv[ptr];
  178. calc = parent / div;
  179. if (calc <= rate && div < best) {
  180. best = div;
  181. val = ptr;
  182. }
  183. }
  184. if (val >= 0) {
  185. unsigned long clkcon0;
  186. clkcon0 = __raw_readl(S3C2443_CLKDIV0);
  187. clkcon0 &= ~armdivmask;
  188. clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
  189. __raw_writel(clkcon0, S3C2443_CLKDIV0);
  190. }
  191. return (val == -1) ? -EINVAL : 0;
  192. }
  193. static struct clk clk_armdiv = {
  194. .name = "armdiv",
  195. .parent = &clk_msysclk.clk,
  196. .ops = &(struct clk_ops) {
  197. .round_rate = s3c2443_armclk_roundrate,
  198. .get_rate = s3c2443_armclk_getrate,
  199. .set_rate = s3c2443_armclk_setrate,
  200. },
  201. };
  202. /* armclk
  203. *
  204. * this is the clock fed into the ARM core itself, from armdiv or from hclk.
  205. */
  206. static struct clk *clk_arm_sources[] = {
  207. [0] = &clk_armdiv,
  208. [1] = &clk_h,
  209. };
  210. static struct clksrc_clk clk_arm = {
  211. .clk = {
  212. .name = "armclk",
  213. },
  214. .sources = &(struct clksrc_sources) {
  215. .sources = clk_arm_sources,
  216. .nr_sources = ARRAY_SIZE(clk_arm_sources),
  217. },
  218. .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
  219. };
  220. /* usbhost
  221. *
  222. * usb host bus-clock, usually 48MHz to provide USB bus clock timing
  223. */
  224. static struct clksrc_clk clk_usb_bus_host = {
  225. .clk = {
  226. .name = "usb-bus-host-parent",
  227. .parent = &clk_esysclk.clk,
  228. .ctrlbit = S3C2443_SCLKCON_USBHOST,
  229. .enable = s3c2443_clkcon_enable_s,
  230. },
  231. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
  232. };
  233. /* common clksrc clocks */
  234. static struct clksrc_clk clksrc_clks[] = {
  235. {
  236. /* ART baud-rate clock sourced from esysclk via a divisor */
  237. .clk = {
  238. .name = "uartclk",
  239. .parent = &clk_esysclk.clk,
  240. },
  241. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
  242. }, {
  243. /* camera interface bus-clock, divided down from esysclk */
  244. .clk = {
  245. .name = "camif-upll", /* same as 2440 name */
  246. .parent = &clk_esysclk.clk,
  247. .ctrlbit = S3C2443_SCLKCON_CAMCLK,
  248. .enable = s3c2443_clkcon_enable_s,
  249. },
  250. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
  251. }, {
  252. .clk = {
  253. .name = "display-if",
  254. .parent = &clk_esysclk.clk,
  255. .ctrlbit = S3C2443_SCLKCON_DISPCLK,
  256. .enable = s3c2443_clkcon_enable_s,
  257. },
  258. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
  259. },
  260. };
  261. static struct clk clk_i2s_ext = {
  262. .name = "i2s-ext",
  263. };
  264. /* i2s_eplldiv
  265. *
  266. * This clock is the output from the I2S divisor of ESYSCLK, and is separate
  267. * from the mux that comes after it (cannot merge into one single clock)
  268. */
  269. static struct clksrc_clk clk_i2s_eplldiv = {
  270. .clk = {
  271. .name = "i2s-eplldiv",
  272. .parent = &clk_esysclk.clk,
  273. },
  274. .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
  275. };
  276. /* i2s-ref
  277. *
  278. * i2s bus reference clock, selectable from external, esysclk or epllref
  279. *
  280. * Note, this used to be two clocks, but was compressed into one.
  281. */
  282. static struct clk *clk_i2s_srclist[] = {
  283. [0] = &clk_i2s_eplldiv.clk,
  284. [1] = &clk_i2s_ext,
  285. [2] = &clk_epllref.clk,
  286. [3] = &clk_epllref.clk,
  287. };
  288. static struct clksrc_clk clk_i2s = {
  289. .clk = {
  290. .name = "i2s-if",
  291. .ctrlbit = S3C2443_SCLKCON_I2SCLK,
  292. .enable = s3c2443_clkcon_enable_s,
  293. },
  294. .sources = &(struct clksrc_sources) {
  295. .sources = clk_i2s_srclist,
  296. .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
  297. },
  298. .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
  299. };
  300. static struct clk init_clocks_off[] = {
  301. {
  302. .name = "iis",
  303. .parent = &clk_p,
  304. .enable = s3c2443_clkcon_enable_p,
  305. .ctrlbit = S3C2443_PCLKCON_IIS,
  306. }, {
  307. .name = "hsspi",
  308. .parent = &clk_p,
  309. .enable = s3c2443_clkcon_enable_p,
  310. .ctrlbit = S3C2443_PCLKCON_HSSPI,
  311. }, {
  312. .name = "adc",
  313. .parent = &clk_p,
  314. .enable = s3c2443_clkcon_enable_p,
  315. .ctrlbit = S3C2443_PCLKCON_ADC,
  316. }, {
  317. .name = "i2c",
  318. .parent = &clk_p,
  319. .enable = s3c2443_clkcon_enable_p,
  320. .ctrlbit = S3C2443_PCLKCON_IIC,
  321. }
  322. };
  323. static struct clk init_clocks[] = {
  324. {
  325. .name = "dma",
  326. .parent = &clk_h,
  327. .enable = s3c2443_clkcon_enable_h,
  328. .ctrlbit = S3C2443_HCLKCON_DMA0,
  329. }, {
  330. .name = "dma",
  331. .parent = &clk_h,
  332. .enable = s3c2443_clkcon_enable_h,
  333. .ctrlbit = S3C2443_HCLKCON_DMA1,
  334. }, {
  335. .name = "dma",
  336. .parent = &clk_h,
  337. .enable = s3c2443_clkcon_enable_h,
  338. .ctrlbit = S3C2443_HCLKCON_DMA2,
  339. }, {
  340. .name = "dma",
  341. .parent = &clk_h,
  342. .enable = s3c2443_clkcon_enable_h,
  343. .ctrlbit = S3C2443_HCLKCON_DMA3,
  344. }, {
  345. .name = "dma",
  346. .parent = &clk_h,
  347. .enable = s3c2443_clkcon_enable_h,
  348. .ctrlbit = S3C2443_HCLKCON_DMA4,
  349. }, {
  350. .name = "dma",
  351. .parent = &clk_h,
  352. .enable = s3c2443_clkcon_enable_h,
  353. .ctrlbit = S3C2443_HCLKCON_DMA5,
  354. }, {
  355. .name = "hsmmc",
  356. .parent = &clk_h,
  357. .enable = s3c2443_clkcon_enable_h,
  358. .ctrlbit = S3C2443_HCLKCON_HSMMC,
  359. }, {
  360. .name = "gpio",
  361. .parent = &clk_p,
  362. .enable = s3c2443_clkcon_enable_p,
  363. .ctrlbit = S3C2443_PCLKCON_GPIO,
  364. }, {
  365. .name = "usb-host",
  366. .parent = &clk_h,
  367. .enable = s3c2443_clkcon_enable_h,
  368. .ctrlbit = S3C2443_HCLKCON_USBH,
  369. }, {
  370. .name = "usb-device",
  371. .parent = &clk_h,
  372. .enable = s3c2443_clkcon_enable_h,
  373. .ctrlbit = S3C2443_HCLKCON_USBD,
  374. }, {
  375. .name = "lcd",
  376. .parent = &clk_h,
  377. .enable = s3c2443_clkcon_enable_h,
  378. .ctrlbit = S3C2443_HCLKCON_LCDC,
  379. }, {
  380. .name = "timers",
  381. .parent = &clk_p,
  382. .enable = s3c2443_clkcon_enable_p,
  383. .ctrlbit = S3C2443_PCLKCON_PWMT,
  384. }, {
  385. .name = "cfc",
  386. .parent = &clk_h,
  387. .enable = s3c2443_clkcon_enable_h,
  388. .ctrlbit = S3C2443_HCLKCON_CFC,
  389. }, {
  390. .name = "ssmc",
  391. .parent = &clk_h,
  392. .enable = s3c2443_clkcon_enable_h,
  393. .ctrlbit = S3C2443_HCLKCON_SSMC,
  394. }, {
  395. .name = "uart",
  396. .devname = "s3c2440-uart.0",
  397. .parent = &clk_p,
  398. .enable = s3c2443_clkcon_enable_p,
  399. .ctrlbit = S3C2443_PCLKCON_UART0,
  400. }, {
  401. .name = "uart",
  402. .devname = "s3c2440-uart.1",
  403. .parent = &clk_p,
  404. .enable = s3c2443_clkcon_enable_p,
  405. .ctrlbit = S3C2443_PCLKCON_UART1,
  406. }, {
  407. .name = "uart",
  408. .devname = "s3c2440-uart.2",
  409. .parent = &clk_p,
  410. .enable = s3c2443_clkcon_enable_p,
  411. .ctrlbit = S3C2443_PCLKCON_UART2,
  412. }, {
  413. .name = "uart",
  414. .devname = "s3c2440-uart.3",
  415. .parent = &clk_p,
  416. .enable = s3c2443_clkcon_enable_p,
  417. .ctrlbit = S3C2443_PCLKCON_UART3,
  418. }, {
  419. .name = "rtc",
  420. .parent = &clk_p,
  421. .enable = s3c2443_clkcon_enable_p,
  422. .ctrlbit = S3C2443_PCLKCON_RTC,
  423. }, {
  424. .name = "watchdog",
  425. .parent = &clk_p,
  426. .ctrlbit = S3C2443_PCLKCON_WDT,
  427. }, {
  428. .name = "ac97",
  429. .parent = &clk_p,
  430. .ctrlbit = S3C2443_PCLKCON_AC97,
  431. }, {
  432. .name = "nand",
  433. .parent = &clk_h,
  434. }, {
  435. .name = "usb-bus-host",
  436. .parent = &clk_usb_bus_host.clk,
  437. }
  438. };
  439. static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
  440. {
  441. clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
  442. return clkcon0 + 1;
  443. }
  444. /* EPLLCON compatible enough to get on/off information */
  445. void __init_or_cpufreq s3c2443_common_setup_clocks(pll_fn get_mpll,
  446. fdiv_fn get_fdiv)
  447. {
  448. unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
  449. unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
  450. unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
  451. struct clk *xtal_clk;
  452. unsigned long xtal;
  453. unsigned long pll;
  454. unsigned long fclk;
  455. unsigned long hclk;
  456. unsigned long pclk;
  457. int ptr;
  458. xtal_clk = clk_get(NULL, "xtal");
  459. xtal = clk_get_rate(xtal_clk);
  460. clk_put(xtal_clk);
  461. pll = get_mpll(mpllcon, xtal);
  462. clk_msysclk.clk.rate = pll;
  463. fclk = pll / get_fdiv(clkdiv0);
  464. hclk = s3c2443_prediv_getrate(&clk_prediv);
  465. hclk /= s3c2443_get_hdiv(clkdiv0);
  466. pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
  467. s3c24xx_setup_clocks(fclk, hclk, pclk);
  468. printk("CPU: MPLL %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
  469. (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  470. print_mhz(pll), print_mhz(fclk),
  471. print_mhz(hclk), print_mhz(pclk));
  472. for (ptr = 0; ptr < ARRAY_SIZE(clksrc_clks); ptr++)
  473. s3c_set_clksrc(&clksrc_clks[ptr], true);
  474. /* ensure usb bus clock is within correct rate of 48MHz */
  475. if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
  476. printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
  477. clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
  478. }
  479. printk("CPU: EPLL %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
  480. (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
  481. print_mhz(clk_get_rate(&clk_epll)),
  482. print_mhz(clk_get_rate(&clk_usb_bus)));
  483. }
  484. static struct clk *clks[] __initdata = {
  485. &clk_prediv,
  486. &clk_mpllref,
  487. &clk_mdivclk,
  488. &clk_ext,
  489. &clk_epll,
  490. &clk_usb_bus,
  491. &clk_armdiv,
  492. };
  493. static struct clksrc_clk *clksrcs[] __initdata = {
  494. &clk_i2s_eplldiv,
  495. &clk_i2s,
  496. &clk_usb_bus_host,
  497. &clk_epllref,
  498. &clk_esysclk,
  499. &clk_msysclk,
  500. &clk_arm,
  501. };
  502. void __init s3c2443_common_init_clocks(int xtal, pll_fn get_mpll,
  503. fdiv_fn get_fdiv,
  504. unsigned int *divs, int nr_divs,
  505. int divmask)
  506. {
  507. int ptr;
  508. armdiv = divs;
  509. nr_armdiv = nr_divs;
  510. armdivmask = divmask;
  511. /* s3c2443 parents h and p clocks from prediv */
  512. clk_h.parent = &clk_prediv;
  513. clk_p.parent = &clk_prediv;
  514. clk_usb_bus.parent = &clk_usb_bus_host.clk;
  515. clk_epll.parent = &clk_epllref.clk;
  516. s3c24xx_register_baseclocks(xtal);
  517. s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
  518. for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
  519. s3c_register_clksrc(clksrcs[ptr], 1);
  520. s3c_register_clksrc(clksrc_clks, ARRAY_SIZE(clksrc_clks));
  521. s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
  522. /* See s3c2443/etc notes on disabling clocks at init time */
  523. s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  524. s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
  525. s3c2443_common_setup_clocks(get_mpll, get_fdiv);
  526. }