clock.c 13 KB

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