clock.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /* linux/arch/arm/mach-s5pv310/clock.c
  2. *
  3. * Copyright (c) 2010 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com/
  5. *
  6. * S5PV310 - Clock support
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/err.h>
  14. #include <linux/io.h>
  15. #include <plat/cpu-freq.h>
  16. #include <plat/clock.h>
  17. #include <plat/cpu.h>
  18. #include <plat/pll.h>
  19. #include <plat/s5p-clock.h>
  20. #include <plat/clock-clksrc.h>
  21. #include <mach/map.h>
  22. #include <mach/regs-clock.h>
  23. static struct clk clk_sclk_hdmi27m = {
  24. .name = "sclk_hdmi27m",
  25. .id = -1,
  26. .rate = 27000000,
  27. };
  28. static struct clk clk_sclk_hdmiphy = {
  29. .name = "sclk_hdmiphy",
  30. .id = -1,
  31. };
  32. static struct clk clk_sclk_usbphy0 = {
  33. .name = "sclk_usbphy0",
  34. .id = -1,
  35. .rate = 27000000,
  36. };
  37. static struct clk clk_sclk_usbphy1 = {
  38. .name = "sclk_usbphy1",
  39. .id = -1,
  40. };
  41. static int s5pv310_clksrc_mask_peril0_ctrl(struct clk *clk, int enable)
  42. {
  43. return s5p_gatectrl(S5P_CLKSRC_MASK_PERIL0, clk, enable);
  44. }
  45. static int s5pv310_clk_ip_peril_ctrl(struct clk *clk, int enable)
  46. {
  47. return s5p_gatectrl(S5P_CLKGATE_IP_PERIL, clk, enable);
  48. }
  49. /* Core list of CMU_CPU side */
  50. static struct clksrc_clk clk_mout_apll = {
  51. .clk = {
  52. .name = "mout_apll",
  53. .id = -1,
  54. },
  55. .sources = &clk_src_apll,
  56. .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 0, .size = 1 },
  57. };
  58. static struct clksrc_clk clk_sclk_apll = {
  59. .clk = {
  60. .name = "sclk_apll",
  61. .id = -1,
  62. .parent = &clk_mout_apll.clk,
  63. },
  64. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 24, .size = 3 },
  65. };
  66. static struct clksrc_clk clk_mout_epll = {
  67. .clk = {
  68. .name = "mout_epll",
  69. .id = -1,
  70. },
  71. .sources = &clk_src_epll,
  72. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 4, .size = 1 },
  73. };
  74. static struct clksrc_clk clk_mout_mpll = {
  75. .clk = {
  76. .name = "mout_mpll",
  77. .id = -1,
  78. },
  79. .sources = &clk_src_mpll,
  80. .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 8, .size = 1 },
  81. };
  82. static struct clk *clkset_moutcore_list[] = {
  83. [0] = &clk_sclk_apll.clk,
  84. [1] = &clk_mout_mpll.clk,
  85. };
  86. static struct clksrc_sources clkset_moutcore = {
  87. .sources = clkset_moutcore_list,
  88. .nr_sources = ARRAY_SIZE(clkset_moutcore_list),
  89. };
  90. static struct clksrc_clk clk_moutcore = {
  91. .clk = {
  92. .name = "moutcore",
  93. .id = -1,
  94. },
  95. .sources = &clkset_moutcore,
  96. .reg_src = { .reg = S5P_CLKSRC_CPU, .shift = 16, .size = 1 },
  97. };
  98. static struct clksrc_clk clk_coreclk = {
  99. .clk = {
  100. .name = "core_clk",
  101. .id = -1,
  102. .parent = &clk_moutcore.clk,
  103. },
  104. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 0, .size = 3 },
  105. };
  106. static struct clksrc_clk clk_armclk = {
  107. .clk = {
  108. .name = "armclk",
  109. .id = -1,
  110. .parent = &clk_coreclk.clk,
  111. },
  112. };
  113. static struct clksrc_clk clk_aclk_corem0 = {
  114. .clk = {
  115. .name = "aclk_corem0",
  116. .id = -1,
  117. .parent = &clk_coreclk.clk,
  118. },
  119. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
  120. };
  121. static struct clksrc_clk clk_aclk_cores = {
  122. .clk = {
  123. .name = "aclk_cores",
  124. .id = -1,
  125. .parent = &clk_coreclk.clk,
  126. },
  127. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 4, .size = 3 },
  128. };
  129. static struct clksrc_clk clk_aclk_corem1 = {
  130. .clk = {
  131. .name = "aclk_corem1",
  132. .id = -1,
  133. .parent = &clk_coreclk.clk,
  134. },
  135. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 8, .size = 3 },
  136. };
  137. static struct clksrc_clk clk_periphclk = {
  138. .clk = {
  139. .name = "periphclk",
  140. .id = -1,
  141. .parent = &clk_coreclk.clk,
  142. },
  143. .reg_div = { .reg = S5P_CLKDIV_CPU, .shift = 12, .size = 3 },
  144. };
  145. /* Core list of CMU_CORE side */
  146. static struct clk *clkset_corebus_list[] = {
  147. [0] = &clk_mout_mpll.clk,
  148. [1] = &clk_sclk_apll.clk,
  149. };
  150. static struct clksrc_sources clkset_mout_corebus = {
  151. .sources = clkset_corebus_list,
  152. .nr_sources = ARRAY_SIZE(clkset_corebus_list),
  153. };
  154. static struct clksrc_clk clk_mout_corebus = {
  155. .clk = {
  156. .name = "mout_corebus",
  157. .id = -1,
  158. },
  159. .sources = &clkset_mout_corebus,
  160. .reg_src = { .reg = S5P_CLKSRC_CORE, .shift = 4, .size = 1 },
  161. };
  162. static struct clksrc_clk clk_sclk_dmc = {
  163. .clk = {
  164. .name = "sclk_dmc",
  165. .id = -1,
  166. .parent = &clk_mout_corebus.clk,
  167. },
  168. .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 12, .size = 3 },
  169. };
  170. static struct clksrc_clk clk_aclk_cored = {
  171. .clk = {
  172. .name = "aclk_cored",
  173. .id = -1,
  174. .parent = &clk_sclk_dmc.clk,
  175. },
  176. .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 16, .size = 3 },
  177. };
  178. static struct clksrc_clk clk_aclk_corep = {
  179. .clk = {
  180. .name = "aclk_corep",
  181. .id = -1,
  182. .parent = &clk_aclk_cored.clk,
  183. },
  184. .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 20, .size = 3 },
  185. };
  186. static struct clksrc_clk clk_aclk_acp = {
  187. .clk = {
  188. .name = "aclk_acp",
  189. .id = -1,
  190. .parent = &clk_mout_corebus.clk,
  191. },
  192. .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 0, .size = 3 },
  193. };
  194. static struct clksrc_clk clk_pclk_acp = {
  195. .clk = {
  196. .name = "pclk_acp",
  197. .id = -1,
  198. .parent = &clk_aclk_acp.clk,
  199. },
  200. .reg_div = { .reg = S5P_CLKDIV_CORE0, .shift = 4, .size = 3 },
  201. };
  202. /* Core list of CMU_TOP side */
  203. static struct clk *clkset_aclk_top_list[] = {
  204. [0] = &clk_mout_mpll.clk,
  205. [1] = &clk_sclk_apll.clk,
  206. };
  207. static struct clksrc_sources clkset_aclk = {
  208. .sources = clkset_aclk_top_list,
  209. .nr_sources = ARRAY_SIZE(clkset_aclk_top_list),
  210. };
  211. static struct clksrc_clk clk_aclk_200 = {
  212. .clk = {
  213. .name = "aclk_200",
  214. .id = -1,
  215. },
  216. .sources = &clkset_aclk,
  217. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 12, .size = 1 },
  218. .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 0, .size = 3 },
  219. };
  220. static struct clksrc_clk clk_aclk_100 = {
  221. .clk = {
  222. .name = "aclk_100",
  223. .id = -1,
  224. },
  225. .sources = &clkset_aclk,
  226. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 16, .size = 1 },
  227. .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 4, .size = 4 },
  228. };
  229. static struct clksrc_clk clk_aclk_160 = {
  230. .clk = {
  231. .name = "aclk_160",
  232. .id = -1,
  233. },
  234. .sources = &clkset_aclk,
  235. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 20, .size = 1 },
  236. .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 8, .size = 3 },
  237. };
  238. static struct clksrc_clk clk_aclk_133 = {
  239. .clk = {
  240. .name = "aclk_133",
  241. .id = -1,
  242. },
  243. .sources = &clkset_aclk,
  244. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 24, .size = 1 },
  245. .reg_div = { .reg = S5P_CLKDIV_TOP, .shift = 12, .size = 3 },
  246. };
  247. static struct clk *clkset_vpllsrc_list[] = {
  248. [0] = &clk_fin_vpll,
  249. [1] = &clk_sclk_hdmi27m,
  250. };
  251. static struct clksrc_sources clkset_vpllsrc = {
  252. .sources = clkset_vpllsrc_list,
  253. .nr_sources = ARRAY_SIZE(clkset_vpllsrc_list),
  254. };
  255. static struct clksrc_clk clk_vpllsrc = {
  256. .clk = {
  257. .name = "vpll_src",
  258. .id = -1,
  259. },
  260. .sources = &clkset_vpllsrc,
  261. .reg_src = { .reg = S5P_CLKSRC_TOP1, .shift = 0, .size = 1 },
  262. };
  263. static struct clk *clkset_sclk_vpll_list[] = {
  264. [0] = &clk_vpllsrc.clk,
  265. [1] = &clk_fout_vpll,
  266. };
  267. static struct clksrc_sources clkset_sclk_vpll = {
  268. .sources = clkset_sclk_vpll_list,
  269. .nr_sources = ARRAY_SIZE(clkset_sclk_vpll_list),
  270. };
  271. static struct clksrc_clk clk_sclk_vpll = {
  272. .clk = {
  273. .name = "sclk_vpll",
  274. .id = -1,
  275. },
  276. .sources = &clkset_sclk_vpll,
  277. .reg_src = { .reg = S5P_CLKSRC_TOP0, .shift = 8, .size = 1 },
  278. };
  279. static struct clk init_clocks_disable[] = {
  280. {
  281. .name = "timers",
  282. .id = -1,
  283. .parent = &clk_aclk_100.clk,
  284. .enable = s5pv310_clk_ip_peril_ctrl,
  285. .ctrlbit = (1<<24),
  286. }
  287. };
  288. static struct clk init_clocks[] = {
  289. {
  290. .name = "uart",
  291. .id = 0,
  292. .enable = s5pv310_clk_ip_peril_ctrl,
  293. .ctrlbit = (1 << 0),
  294. }, {
  295. .name = "uart",
  296. .id = 1,
  297. .enable = s5pv310_clk_ip_peril_ctrl,
  298. .ctrlbit = (1 << 1),
  299. }, {
  300. .name = "uart",
  301. .id = 2,
  302. .enable = s5pv310_clk_ip_peril_ctrl,
  303. .ctrlbit = (1 << 2),
  304. }, {
  305. .name = "uart",
  306. .id = 3,
  307. .enable = s5pv310_clk_ip_peril_ctrl,
  308. .ctrlbit = (1 << 3),
  309. }, {
  310. .name = "uart",
  311. .id = 4,
  312. .enable = s5pv310_clk_ip_peril_ctrl,
  313. .ctrlbit = (1 << 4),
  314. }, {
  315. .name = "uart",
  316. .id = 5,
  317. .enable = s5pv310_clk_ip_peril_ctrl,
  318. .ctrlbit = (1 << 5),
  319. }
  320. };
  321. static struct clk *clkset_group_list[] = {
  322. [0] = &clk_ext_xtal_mux,
  323. [1] = &clk_xusbxti,
  324. [2] = &clk_sclk_hdmi27m,
  325. [3] = &clk_sclk_usbphy0,
  326. [4] = &clk_sclk_usbphy1,
  327. [5] = &clk_sclk_hdmiphy,
  328. [6] = &clk_mout_mpll.clk,
  329. [7] = &clk_mout_epll.clk,
  330. [8] = &clk_sclk_vpll.clk,
  331. };
  332. static struct clksrc_sources clkset_group = {
  333. .sources = clkset_group_list,
  334. .nr_sources = ARRAY_SIZE(clkset_group_list),
  335. };
  336. static struct clksrc_clk clksrcs[] = {
  337. {
  338. .clk = {
  339. .name = "uclk1",
  340. .id = 0,
  341. .enable = s5pv310_clksrc_mask_peril0_ctrl,
  342. .ctrlbit = (1 << 0),
  343. },
  344. .sources = &clkset_group,
  345. .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 0, .size = 4 },
  346. .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 0, .size = 4 },
  347. }, {
  348. .clk = {
  349. .name = "uclk1",
  350. .id = 1,
  351. .enable = s5pv310_clksrc_mask_peril0_ctrl,
  352. .ctrlbit = (1 << 4),
  353. },
  354. .sources = &clkset_group,
  355. .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 4, .size = 4 },
  356. .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 4, .size = 4 },
  357. }, {
  358. .clk = {
  359. .name = "uclk1",
  360. .id = 2,
  361. .enable = s5pv310_clksrc_mask_peril0_ctrl,
  362. .ctrlbit = (1 << 8),
  363. },
  364. .sources = &clkset_group,
  365. .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 8, .size = 4 },
  366. .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 8, .size = 4 },
  367. }, {
  368. .clk = {
  369. .name = "uclk1",
  370. .id = 3,
  371. .enable = s5pv310_clksrc_mask_peril0_ctrl,
  372. .ctrlbit = (1 << 12),
  373. },
  374. .sources = &clkset_group,
  375. .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 12, .size = 4 },
  376. .reg_div = { .reg = S5P_CLKDIV_PERIL0, .shift = 12, .size = 4 },
  377. }, {
  378. .clk = {
  379. .name = "sclk_pwm",
  380. .id = -1,
  381. .enable = s5pv310_clksrc_mask_peril0_ctrl,
  382. .ctrlbit = (1 << 24),
  383. },
  384. .sources = &clkset_group,
  385. .reg_src = { .reg = S5P_CLKSRC_PERIL0, .shift = 24, .size = 4 },
  386. .reg_div = { .reg = S5P_CLKDIV_PERIL3, .shift = 0, .size = 4 },
  387. },
  388. };
  389. /* Clock initialization code */
  390. static struct clksrc_clk *sysclks[] = {
  391. &clk_mout_apll,
  392. &clk_sclk_apll,
  393. &clk_mout_epll,
  394. &clk_mout_mpll,
  395. &clk_moutcore,
  396. &clk_coreclk,
  397. &clk_armclk,
  398. &clk_aclk_corem0,
  399. &clk_aclk_cores,
  400. &clk_aclk_corem1,
  401. &clk_periphclk,
  402. &clk_mout_corebus,
  403. &clk_sclk_dmc,
  404. &clk_aclk_cored,
  405. &clk_aclk_corep,
  406. &clk_aclk_acp,
  407. &clk_pclk_acp,
  408. &clk_vpllsrc,
  409. &clk_sclk_vpll,
  410. &clk_aclk_200,
  411. &clk_aclk_100,
  412. &clk_aclk_160,
  413. &clk_aclk_133,
  414. };
  415. void __init_or_cpufreq s5pv310_setup_clocks(void)
  416. {
  417. struct clk *xtal_clk;
  418. unsigned long apll;
  419. unsigned long mpll;
  420. unsigned long epll;
  421. unsigned long vpll;
  422. unsigned long vpllsrc;
  423. unsigned long xtal;
  424. unsigned long armclk;
  425. unsigned long sclk_dmc;
  426. unsigned int ptr;
  427. printk(KERN_DEBUG "%s: registering clocks\n", __func__);
  428. xtal_clk = clk_get(NULL, "xtal");
  429. BUG_ON(IS_ERR(xtal_clk));
  430. xtal = clk_get_rate(xtal_clk);
  431. clk_put(xtal_clk);
  432. printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
  433. apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON0), pll_4508);
  434. mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON0), pll_4508);
  435. epll = s5p_get_pll46xx(xtal, __raw_readl(S5P_EPLL_CON0),
  436. __raw_readl(S5P_EPLL_CON1), pll_4600);
  437. vpllsrc = clk_get_rate(&clk_vpllsrc.clk);
  438. vpll = s5p_get_pll46xx(vpllsrc, __raw_readl(S5P_VPLL_CON0),
  439. __raw_readl(S5P_VPLL_CON1), pll_4650);
  440. clk_fout_apll.rate = apll;
  441. clk_fout_mpll.rate = mpll;
  442. clk_fout_epll.rate = epll;
  443. clk_fout_vpll.rate = vpll;
  444. printk(KERN_INFO "S5PV310: PLL settings, A=%ld, M=%ld, E=%ld V=%ld",
  445. apll, mpll, epll, vpll);
  446. armclk = clk_get_rate(&clk_armclk.clk);
  447. sclk_dmc = clk_get_rate(&clk_sclk_dmc.clk);
  448. printk(KERN_INFO "S5PV310: ARMCLK=%ld, DMC=%ld\n", armclk, sclk_dmc);
  449. clk_f.rate = armclk;
  450. clk_h.rate = sclk_dmc;
  451. for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
  452. s3c_set_clksrc(&clksrcs[ptr], true);
  453. }
  454. static struct clk *clks[] __initdata = {
  455. /* Nothing here yet */
  456. };
  457. void __init s5pv310_register_clocks(void)
  458. {
  459. struct clk *clkp;
  460. int ret;
  461. int ptr;
  462. ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
  463. if (ret > 0)
  464. printk(KERN_ERR "Failed to register %u clocks\n", ret);
  465. for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++)
  466. s3c_register_clksrc(sysclks[ptr], 1);
  467. s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
  468. s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
  469. clkp = init_clocks_disable;
  470. for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
  471. ret = s3c24xx_register_clock(clkp);
  472. if (ret < 0) {
  473. printk(KERN_ERR "Failed to register clock %s (%d)\n",
  474. clkp->name, ret);
  475. }
  476. (clkp->enable)(clkp, 0);
  477. }
  478. s3c_pwmclk_init();
  479. }