s3c6400-clock.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761
  1. /* linux/arch/arm/plat-s3c64xx/s3c6400-clock.c
  2. *
  3. * Copyright 2008 Openmoko, Inc.
  4. * Copyright 2008 Simtec Electronics
  5. * Ben Dooks <ben@simtec.co.uk>
  6. * http://armlinux.simtec.co.uk/
  7. *
  8. * S3C6400 based common clock support
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #include <linux/init.h>
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/list.h>
  18. #include <linux/errno.h>
  19. #include <linux/err.h>
  20. #include <linux/clk.h>
  21. #include <linux/sysdev.h>
  22. #include <linux/io.h>
  23. #include <mach/hardware.h>
  24. #include <mach/map.h>
  25. #include <plat/cpu-freq.h>
  26. #include <plat/regs-clock.h>
  27. #include <plat/clock.h>
  28. #include <plat/cpu.h>
  29. #include <plat/pll.h>
  30. /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
  31. * ext_xtal_mux for want of an actual name from the manual.
  32. */
  33. static struct clk clk_ext_xtal_mux = {
  34. .name = "ext_xtal",
  35. .id = -1,
  36. };
  37. #define clk_fin_apll clk_ext_xtal_mux
  38. #define clk_fin_mpll clk_ext_xtal_mux
  39. #define clk_fin_epll clk_ext_xtal_mux
  40. #define clk_fout_mpll clk_mpll
  41. struct clk_sources {
  42. unsigned int nr_sources;
  43. struct clk **sources;
  44. };
  45. struct clksrc_clk {
  46. struct clk clk;
  47. unsigned int mask;
  48. unsigned int shift;
  49. struct clk_sources *sources;
  50. unsigned int divider_shift;
  51. void __iomem *reg_divider;
  52. };
  53. static struct clk clk_fout_apll = {
  54. .name = "fout_apll",
  55. .id = -1,
  56. };
  57. static struct clk *clk_src_apll_list[] = {
  58. [0] = &clk_fin_apll,
  59. [1] = &clk_fout_apll,
  60. };
  61. static struct clk_sources clk_src_apll = {
  62. .sources = clk_src_apll_list,
  63. .nr_sources = ARRAY_SIZE(clk_src_apll_list),
  64. };
  65. static struct clksrc_clk clk_mout_apll = {
  66. .clk = {
  67. .name = "mout_apll",
  68. .id = -1,
  69. },
  70. .shift = S3C6400_CLKSRC_APLL_MOUT_SHIFT,
  71. .mask = S3C6400_CLKSRC_APLL_MOUT,
  72. .sources = &clk_src_apll,
  73. };
  74. static struct clk clk_fout_epll = {
  75. .name = "fout_epll",
  76. .id = -1,
  77. };
  78. static struct clk *clk_src_epll_list[] = {
  79. [0] = &clk_fin_epll,
  80. [1] = &clk_fout_epll,
  81. };
  82. static struct clk_sources clk_src_epll = {
  83. .sources = clk_src_epll_list,
  84. .nr_sources = ARRAY_SIZE(clk_src_epll_list),
  85. };
  86. static struct clksrc_clk clk_mout_epll = {
  87. .clk = {
  88. .name = "mout_epll",
  89. .id = -1,
  90. },
  91. .shift = S3C6400_CLKSRC_EPLL_MOUT_SHIFT,
  92. .mask = S3C6400_CLKSRC_EPLL_MOUT,
  93. .sources = &clk_src_epll,
  94. };
  95. static struct clk *clk_src_mpll_list[] = {
  96. [0] = &clk_fin_mpll,
  97. [1] = &clk_fout_mpll,
  98. };
  99. static struct clk_sources clk_src_mpll = {
  100. .sources = clk_src_mpll_list,
  101. .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
  102. };
  103. static struct clksrc_clk clk_mout_mpll = {
  104. .clk = {
  105. .name = "mout_mpll",
  106. .id = -1,
  107. },
  108. .shift = S3C6400_CLKSRC_MPLL_MOUT_SHIFT,
  109. .mask = S3C6400_CLKSRC_MPLL_MOUT,
  110. .sources = &clk_src_mpll,
  111. };
  112. static unsigned int armclk_mask;
  113. static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
  114. {
  115. unsigned long rate = clk_get_rate(clk->parent);
  116. u32 clkdiv;
  117. /* divisor mask starts at bit0, so no need to shift */
  118. clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask;
  119. return rate / (clkdiv + 1);
  120. }
  121. static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
  122. unsigned long rate)
  123. {
  124. unsigned long parent = clk_get_rate(clk->parent);
  125. u32 div;
  126. if (parent < rate)
  127. return rate;
  128. div = (parent / rate) - 1;
  129. if (div > armclk_mask)
  130. div = armclk_mask;
  131. return parent / (div + 1);
  132. }
  133. static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
  134. {
  135. unsigned long parent = clk_get_rate(clk->parent);
  136. u32 div;
  137. u32 val;
  138. if (rate < parent / (armclk_mask + 1))
  139. return -EINVAL;
  140. rate = clk_round_rate(clk, rate);
  141. div = clk_get_rate(clk->parent) / rate;
  142. val = __raw_readl(S3C_CLK_DIV0);
  143. val &= armclk_mask;
  144. val |= (div - 1);
  145. __raw_writel(val, S3C_CLK_DIV0);
  146. return 0;
  147. }
  148. static struct clk clk_arm = {
  149. .name = "armclk",
  150. .id = -1,
  151. .parent = &clk_mout_apll.clk,
  152. .get_rate = s3c64xx_clk_arm_get_rate,
  153. .set_rate = s3c64xx_clk_arm_set_rate,
  154. .round_rate = s3c64xx_clk_arm_round_rate,
  155. };
  156. static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
  157. {
  158. unsigned long rate = clk_get_rate(clk->parent);
  159. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  160. if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
  161. rate /= 2;
  162. return rate;
  163. }
  164. static struct clk clk_dout_mpll = {
  165. .name = "dout_mpll",
  166. .id = -1,
  167. .parent = &clk_mout_mpll.clk,
  168. .get_rate = s3c64xx_clk_doutmpll_get_rate,
  169. };
  170. static struct clk *clkset_spi_mmc_list[] = {
  171. &clk_mout_epll.clk,
  172. &clk_dout_mpll,
  173. &clk_fin_epll,
  174. &clk_27m,
  175. };
  176. static struct clk_sources clkset_spi_mmc = {
  177. .sources = clkset_spi_mmc_list,
  178. .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
  179. };
  180. static struct clk *clkset_irda_list[] = {
  181. &clk_mout_epll.clk,
  182. &clk_dout_mpll,
  183. NULL,
  184. &clk_27m,
  185. };
  186. static struct clk_sources clkset_irda = {
  187. .sources = clkset_irda_list,
  188. .nr_sources = ARRAY_SIZE(clkset_irda_list),
  189. };
  190. static struct clk *clkset_uart_list[] = {
  191. &clk_mout_epll.clk,
  192. &clk_dout_mpll,
  193. NULL,
  194. NULL
  195. };
  196. static struct clk_sources clkset_uart = {
  197. .sources = clkset_uart_list,
  198. .nr_sources = ARRAY_SIZE(clkset_uart_list),
  199. };
  200. static struct clk *clkset_uhost_list[] = {
  201. &clk_48m,
  202. &clk_mout_epll.clk,
  203. &clk_dout_mpll,
  204. &clk_fin_epll,
  205. };
  206. static struct clk_sources clkset_uhost = {
  207. .sources = clkset_uhost_list,
  208. .nr_sources = ARRAY_SIZE(clkset_uhost_list),
  209. };
  210. /* The peripheral clocks are all controlled via clocksource followed
  211. * by an optional divider and gate stage. We currently roll this into
  212. * one clock which hides the intermediate clock from the mux.
  213. *
  214. * Note, the JPEG clock can only be an even divider...
  215. *
  216. * The scaler and LCD clocks depend on the S3C64XX version, and also
  217. * have a common parent divisor so are not included here.
  218. */
  219. static inline struct clksrc_clk *to_clksrc(struct clk *clk)
  220. {
  221. return container_of(clk, struct clksrc_clk, clk);
  222. }
  223. static unsigned long s3c64xx_getrate_clksrc(struct clk *clk)
  224. {
  225. struct clksrc_clk *sclk = to_clksrc(clk);
  226. unsigned long rate = clk_get_rate(clk->parent);
  227. u32 clkdiv = __raw_readl(sclk->reg_divider);
  228. clkdiv >>= sclk->divider_shift;
  229. clkdiv &= 0xf;
  230. clkdiv++;
  231. rate /= clkdiv;
  232. return rate;
  233. }
  234. static int s3c64xx_setrate_clksrc(struct clk *clk, unsigned long rate)
  235. {
  236. struct clksrc_clk *sclk = to_clksrc(clk);
  237. void __iomem *reg = sclk->reg_divider;
  238. unsigned int div;
  239. u32 val;
  240. rate = clk_round_rate(clk, rate);
  241. div = clk_get_rate(clk->parent) / rate;
  242. if (div > 16)
  243. return -EINVAL;
  244. val = __raw_readl(reg);
  245. val &= ~(0xf << sclk->shift);
  246. val |= (div - 1) << sclk->shift;
  247. __raw_writel(val, reg);
  248. return 0;
  249. }
  250. static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent)
  251. {
  252. struct clksrc_clk *sclk = to_clksrc(clk);
  253. struct clk_sources *srcs = sclk->sources;
  254. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  255. int src_nr = -1;
  256. int ptr;
  257. for (ptr = 0; ptr < srcs->nr_sources; ptr++)
  258. if (srcs->sources[ptr] == parent) {
  259. src_nr = ptr;
  260. break;
  261. }
  262. if (src_nr >= 0) {
  263. clksrc &= ~sclk->mask;
  264. clksrc |= src_nr << sclk->shift;
  265. __raw_writel(clksrc, S3C_CLK_SRC);
  266. return 0;
  267. }
  268. return -EINVAL;
  269. }
  270. static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk,
  271. unsigned long rate)
  272. {
  273. unsigned long parent_rate = clk_get_rate(clk->parent);
  274. int div;
  275. if (rate > parent_rate)
  276. rate = parent_rate;
  277. else {
  278. div = rate / parent_rate;
  279. if (div == 0)
  280. div = 1;
  281. if (div > 16)
  282. div = 16;
  283. rate = parent_rate / div;
  284. }
  285. return rate;
  286. }
  287. static struct clksrc_clk clk_mmc0 = {
  288. .clk = {
  289. .name = "mmc_bus",
  290. .id = 0,
  291. .ctrlbit = S3C_CLKCON_SCLK_MMC0,
  292. .enable = s3c64xx_sclk_ctrl,
  293. .set_parent = s3c64xx_setparent_clksrc,
  294. .get_rate = s3c64xx_getrate_clksrc,
  295. .set_rate = s3c64xx_setrate_clksrc,
  296. .round_rate = s3c64xx_roundrate_clksrc,
  297. },
  298. .shift = S3C6400_CLKSRC_MMC0_SHIFT,
  299. .mask = S3C6400_CLKSRC_MMC0_MASK,
  300. .sources = &clkset_spi_mmc,
  301. .divider_shift = S3C6400_CLKDIV1_MMC0_SHIFT,
  302. .reg_divider = S3C_CLK_DIV1,
  303. };
  304. static struct clksrc_clk clk_mmc1 = {
  305. .clk = {
  306. .name = "mmc_bus",
  307. .id = 1,
  308. .ctrlbit = S3C_CLKCON_SCLK_MMC1,
  309. .enable = s3c64xx_sclk_ctrl,
  310. .get_rate = s3c64xx_getrate_clksrc,
  311. .set_rate = s3c64xx_setrate_clksrc,
  312. .set_parent = s3c64xx_setparent_clksrc,
  313. .round_rate = s3c64xx_roundrate_clksrc,
  314. },
  315. .shift = S3C6400_CLKSRC_MMC1_SHIFT,
  316. .mask = S3C6400_CLKSRC_MMC1_MASK,
  317. .sources = &clkset_spi_mmc,
  318. .divider_shift = S3C6400_CLKDIV1_MMC1_SHIFT,
  319. .reg_divider = S3C_CLK_DIV1,
  320. };
  321. static struct clksrc_clk clk_mmc2 = {
  322. .clk = {
  323. .name = "mmc_bus",
  324. .id = 2,
  325. .ctrlbit = S3C_CLKCON_SCLK_MMC2,
  326. .enable = s3c64xx_sclk_ctrl,
  327. .get_rate = s3c64xx_getrate_clksrc,
  328. .set_rate = s3c64xx_setrate_clksrc,
  329. .set_parent = s3c64xx_setparent_clksrc,
  330. .round_rate = s3c64xx_roundrate_clksrc,
  331. },
  332. .shift = S3C6400_CLKSRC_MMC2_SHIFT,
  333. .mask = S3C6400_CLKSRC_MMC2_MASK,
  334. .sources = &clkset_spi_mmc,
  335. .divider_shift = S3C6400_CLKDIV1_MMC2_SHIFT,
  336. .reg_divider = S3C_CLK_DIV1,
  337. };
  338. static struct clksrc_clk clk_usbhost = {
  339. .clk = {
  340. .name = "usb-bus-host",
  341. .id = -1,
  342. .ctrlbit = S3C_CLKCON_SCLK_UHOST,
  343. .enable = s3c64xx_sclk_ctrl,
  344. .set_parent = s3c64xx_setparent_clksrc,
  345. .get_rate = s3c64xx_getrate_clksrc,
  346. .set_rate = s3c64xx_setrate_clksrc,
  347. .round_rate = s3c64xx_roundrate_clksrc,
  348. },
  349. .shift = S3C6400_CLKSRC_UHOST_SHIFT,
  350. .mask = S3C6400_CLKSRC_UHOST_MASK,
  351. .sources = &clkset_uhost,
  352. .divider_shift = S3C6400_CLKDIV1_UHOST_SHIFT,
  353. .reg_divider = S3C_CLK_DIV1,
  354. };
  355. static struct clksrc_clk clk_uart_uclk1 = {
  356. .clk = {
  357. .name = "uclk1",
  358. .id = -1,
  359. .ctrlbit = S3C_CLKCON_SCLK_UART,
  360. .enable = s3c64xx_sclk_ctrl,
  361. .set_parent = s3c64xx_setparent_clksrc,
  362. .get_rate = s3c64xx_getrate_clksrc,
  363. .set_rate = s3c64xx_setrate_clksrc,
  364. .round_rate = s3c64xx_roundrate_clksrc,
  365. },
  366. .shift = S3C6400_CLKSRC_UART_SHIFT,
  367. .mask = S3C6400_CLKSRC_UART_MASK,
  368. .sources = &clkset_uart,
  369. .divider_shift = S3C6400_CLKDIV2_UART_SHIFT,
  370. .reg_divider = S3C_CLK_DIV2,
  371. };
  372. /* Where does UCLK0 come from? */
  373. static struct clksrc_clk clk_spi0 = {
  374. .clk = {
  375. .name = "spi-bus",
  376. .id = 0,
  377. .ctrlbit = S3C_CLKCON_SCLK_SPI0,
  378. .enable = s3c64xx_sclk_ctrl,
  379. .set_parent = s3c64xx_setparent_clksrc,
  380. .get_rate = s3c64xx_getrate_clksrc,
  381. .set_rate = s3c64xx_setrate_clksrc,
  382. .round_rate = s3c64xx_roundrate_clksrc,
  383. },
  384. .shift = S3C6400_CLKSRC_SPI0_SHIFT,
  385. .mask = S3C6400_CLKSRC_SPI0_MASK,
  386. .sources = &clkset_spi_mmc,
  387. .divider_shift = S3C6400_CLKDIV2_SPI0_SHIFT,
  388. .reg_divider = S3C_CLK_DIV2,
  389. };
  390. static struct clksrc_clk clk_spi1 = {
  391. .clk = {
  392. .name = "spi-bus",
  393. .id = 1,
  394. .ctrlbit = S3C_CLKCON_SCLK_SPI1,
  395. .enable = s3c64xx_sclk_ctrl,
  396. .set_parent = s3c64xx_setparent_clksrc,
  397. .get_rate = s3c64xx_getrate_clksrc,
  398. .set_rate = s3c64xx_setrate_clksrc,
  399. .round_rate = s3c64xx_roundrate_clksrc,
  400. },
  401. .shift = S3C6400_CLKSRC_SPI1_SHIFT,
  402. .mask = S3C6400_CLKSRC_SPI1_MASK,
  403. .sources = &clkset_spi_mmc,
  404. .divider_shift = S3C6400_CLKDIV2_SPI1_SHIFT,
  405. .reg_divider = S3C_CLK_DIV2,
  406. };
  407. static struct clk clk_iis_cd0 = {
  408. .name = "iis_cdclk0",
  409. .id = -1,
  410. };
  411. static struct clk clk_iis_cd1 = {
  412. .name = "iis_cdclk1",
  413. .id = -1,
  414. };
  415. static struct clk clk_pcm_cd = {
  416. .name = "pcm_cdclk",
  417. .id = -1,
  418. };
  419. static struct clk *clkset_audio0_list[] = {
  420. [0] = &clk_mout_epll.clk,
  421. [1] = &clk_dout_mpll,
  422. [2] = &clk_fin_epll,
  423. [3] = &clk_iis_cd0,
  424. [4] = &clk_pcm_cd,
  425. };
  426. static struct clk_sources clkset_audio0 = {
  427. .sources = clkset_audio0_list,
  428. .nr_sources = ARRAY_SIZE(clkset_audio0_list),
  429. };
  430. static struct clksrc_clk clk_audio0 = {
  431. .clk = {
  432. .name = "audio-bus",
  433. .id = 0,
  434. .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
  435. .enable = s3c64xx_sclk_ctrl,
  436. .set_parent = s3c64xx_setparent_clksrc,
  437. .get_rate = s3c64xx_getrate_clksrc,
  438. .set_rate = s3c64xx_setrate_clksrc,
  439. .round_rate = s3c64xx_roundrate_clksrc,
  440. },
  441. .shift = S3C6400_CLKSRC_AUDIO0_SHIFT,
  442. .mask = S3C6400_CLKSRC_AUDIO0_MASK,
  443. .sources = &clkset_audio0,
  444. .divider_shift = S3C6400_CLKDIV2_AUDIO0_SHIFT,
  445. .reg_divider = S3C_CLK_DIV2,
  446. };
  447. static struct clk *clkset_audio1_list[] = {
  448. [0] = &clk_mout_epll.clk,
  449. [1] = &clk_dout_mpll,
  450. [2] = &clk_fin_epll,
  451. [3] = &clk_iis_cd1,
  452. [4] = &clk_pcm_cd,
  453. };
  454. static struct clk_sources clkset_audio1 = {
  455. .sources = clkset_audio1_list,
  456. .nr_sources = ARRAY_SIZE(clkset_audio1_list),
  457. };
  458. static struct clksrc_clk clk_audio1 = {
  459. .clk = {
  460. .name = "audio-bus",
  461. .id = 1,
  462. .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
  463. .enable = s3c64xx_sclk_ctrl,
  464. .set_parent = s3c64xx_setparent_clksrc,
  465. .get_rate = s3c64xx_getrate_clksrc,
  466. .set_rate = s3c64xx_setrate_clksrc,
  467. .round_rate = s3c64xx_roundrate_clksrc,
  468. },
  469. .shift = S3C6400_CLKSRC_AUDIO1_SHIFT,
  470. .mask = S3C6400_CLKSRC_AUDIO1_MASK,
  471. .sources = &clkset_audio1,
  472. .divider_shift = S3C6400_CLKDIV2_AUDIO1_SHIFT,
  473. .reg_divider = S3C_CLK_DIV2,
  474. };
  475. static struct clksrc_clk clk_irda = {
  476. .clk = {
  477. .name = "irda-bus",
  478. .id = 0,
  479. .ctrlbit = S3C_CLKCON_SCLK_IRDA,
  480. .enable = s3c64xx_sclk_ctrl,
  481. .set_parent = s3c64xx_setparent_clksrc,
  482. .get_rate = s3c64xx_getrate_clksrc,
  483. .set_rate = s3c64xx_setrate_clksrc,
  484. .round_rate = s3c64xx_roundrate_clksrc,
  485. },
  486. .shift = S3C6400_CLKSRC_IRDA_SHIFT,
  487. .mask = S3C6400_CLKSRC_IRDA_MASK,
  488. .sources = &clkset_irda,
  489. .divider_shift = S3C6400_CLKDIV2_IRDA_SHIFT,
  490. .reg_divider = S3C_CLK_DIV2,
  491. };
  492. static struct clk *clkset_camif_list[] = {
  493. &clk_h2,
  494. };
  495. static struct clk_sources clkset_camif = {
  496. .sources = clkset_camif_list,
  497. .nr_sources = ARRAY_SIZE(clkset_camif_list),
  498. };
  499. static struct clksrc_clk clk_camif = {
  500. .clk = {
  501. .name = "camera",
  502. .id = -1,
  503. .ctrlbit = S3C_CLKCON_SCLK_CAM,
  504. .enable = s3c64xx_sclk_ctrl,
  505. .set_parent = s3c64xx_setparent_clksrc,
  506. .get_rate = s3c64xx_getrate_clksrc,
  507. .set_rate = s3c64xx_setrate_clksrc,
  508. .round_rate = s3c64xx_roundrate_clksrc,
  509. },
  510. .shift = 0,
  511. .mask = 0,
  512. .sources = &clkset_camif,
  513. .divider_shift = S3C6400_CLKDIV0_CAM_SHIFT,
  514. .reg_divider = S3C_CLK_DIV0,
  515. };
  516. /* Clock initialisation code */
  517. static struct clksrc_clk *init_parents[] = {
  518. &clk_mout_apll,
  519. &clk_mout_epll,
  520. &clk_mout_mpll,
  521. &clk_mmc0,
  522. &clk_mmc1,
  523. &clk_mmc2,
  524. &clk_usbhost,
  525. &clk_uart_uclk1,
  526. &clk_spi0,
  527. &clk_spi1,
  528. &clk_audio0,
  529. &clk_audio1,
  530. &clk_irda,
  531. &clk_camif,
  532. };
  533. static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
  534. {
  535. struct clk_sources *srcs = clk->sources;
  536. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  537. clksrc &= clk->mask;
  538. clksrc >>= clk->shift;
  539. if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
  540. printk(KERN_ERR "%s: bad source %d\n",
  541. clk->clk.name, clksrc);
  542. return;
  543. }
  544. clk->clk.parent = srcs->sources[clksrc];
  545. printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
  546. clk->clk.name, clk->clk.parent->name, clksrc,
  547. clk_get_rate(&clk->clk));
  548. }
  549. #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
  550. void __init_or_cpufreq s3c6400_setup_clocks(void)
  551. {
  552. struct clk *xtal_clk;
  553. unsigned long xtal;
  554. unsigned long fclk;
  555. unsigned long hclk;
  556. unsigned long hclk2;
  557. unsigned long pclk;
  558. unsigned long epll;
  559. unsigned long apll;
  560. unsigned long mpll;
  561. unsigned int ptr;
  562. u32 clkdiv0;
  563. printk(KERN_DEBUG "%s: registering clocks\n", __func__);
  564. clkdiv0 = __raw_readl(S3C_CLK_DIV0);
  565. printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
  566. xtal_clk = clk_get(NULL, "xtal");
  567. BUG_ON(IS_ERR(xtal_clk));
  568. xtal = clk_get_rate(xtal_clk);
  569. clk_put(xtal_clk);
  570. printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
  571. epll = s3c6400_get_epll(xtal);
  572. mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
  573. apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
  574. fclk = mpll;
  575. printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
  576. apll, mpll, epll);
  577. hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
  578. hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
  579. pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
  580. printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
  581. hclk2, hclk, pclk);
  582. clk_fout_mpll.rate = mpll;
  583. clk_fout_epll.rate = epll;
  584. clk_fout_apll.rate = apll;
  585. clk_h2.rate = hclk2;
  586. clk_h.rate = hclk;
  587. clk_p.rate = pclk;
  588. clk_f.rate = fclk;
  589. for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
  590. s3c6400_set_clksrc(init_parents[ptr]);
  591. }
  592. static struct clk *clks[] __initdata = {
  593. &clk_ext_xtal_mux,
  594. &clk_iis_cd0,
  595. &clk_iis_cd1,
  596. &clk_pcm_cd,
  597. &clk_mout_epll.clk,
  598. &clk_fout_epll,
  599. &clk_mout_mpll.clk,
  600. &clk_dout_mpll,
  601. &clk_mmc0.clk,
  602. &clk_mmc1.clk,
  603. &clk_mmc2.clk,
  604. &clk_usbhost.clk,
  605. &clk_uart_uclk1.clk,
  606. &clk_spi0.clk,
  607. &clk_spi1.clk,
  608. &clk_audio0.clk,
  609. &clk_audio1.clk,
  610. &clk_irda.clk,
  611. &clk_camif.clk,
  612. &clk_arm,
  613. };
  614. /**
  615. * s3c6400_register_clocks - register clocks for s3c6400 and above
  616. * @armclk_divlimit: Divisor mask for ARMCLK
  617. *
  618. * Register the clocks for the S3C6400 and above SoC range, such
  619. * as ARMCLK and the clocks which have divider chains attached.
  620. *
  621. * This call does not setup the clocks, which is left to the
  622. * s3c6400_setup_clocks() call which may be needed by the cpufreq
  623. * or resume code to re-set the clocks if the bootloader has changed
  624. * them.
  625. */
  626. void __init s3c6400_register_clocks(unsigned armclk_divlimit)
  627. {
  628. struct clk *clkp;
  629. int ret;
  630. int ptr;
  631. armclk_mask = armclk_divlimit;
  632. for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
  633. clkp = clks[ptr];
  634. ret = s3c24xx_register_clock(clkp);
  635. if (ret < 0) {
  636. printk(KERN_ERR "Failed to register clock %s (%d)\n",
  637. clkp->name, ret);
  638. }
  639. }
  640. clk_mpll.parent = &clk_mout_mpll.clk;
  641. clk_epll.parent = &clk_mout_epll.clk;
  642. }