clock.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * (C) Copyright 2015, Freescale Semiconductor, Inc.
  3. *
  4. * SPDX-License-Identifier: GPL-2.0+
  5. */
  6. #include <asm/io.h>
  7. #include <asm/arch/imx-regs.h>
  8. #include <asm/arch/mc_cgm_regs.h>
  9. #include <asm/arch/mc_me_regs.h>
  10. #include <asm/arch/clock.h>
  11. /*
  12. * Select the clock reference for required pll.
  13. * pll - ARM_PLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_PLL.
  14. * refclk_freq - input referece clock frequency (FXOSC - 40 MHZ, FIRC - 48 MHZ)
  15. */
  16. static int select_pll_source_clk(enum pll_type pll, u32 refclk_freq)
  17. {
  18. u32 clk_src;
  19. u32 pll_idx;
  20. volatile struct src *src = (struct src *)SRC_SOC_BASE_ADDR;
  21. /* select the pll clock source */
  22. switch (refclk_freq) {
  23. case FIRC_CLK_FREQ:
  24. clk_src = SRC_GPR1_FIRC_CLK_SOURCE;
  25. break;
  26. case XOSC_CLK_FREQ:
  27. clk_src = SRC_GPR1_XOSC_CLK_SOURCE;
  28. break;
  29. default:
  30. /* The clock frequency for the source clock is unknown */
  31. return -1;
  32. }
  33. /*
  34. * The hardware definition is not uniform, it has to calculate again
  35. * the recurrence formula.
  36. */
  37. switch (pll) {
  38. case PERIPH_PLL:
  39. pll_idx = 3;
  40. break;
  41. case ENET_PLL:
  42. pll_idx = 1;
  43. break;
  44. case DDR_PLL:
  45. pll_idx = 2;
  46. break;
  47. default:
  48. pll_idx = pll;
  49. }
  50. writel(readl(&src->gpr1) | SRC_GPR1_PLL_SOURCE(pll_idx, clk_src),
  51. &src->gpr1);
  52. return 0;
  53. }
  54. static void entry_to_target_mode(u32 mode)
  55. {
  56. writel(mode | MC_ME_MCTL_KEY, MC_ME_MCTL);
  57. writel(mode | MC_ME_MCTL_INVERTEDKEY, MC_ME_MCTL);
  58. while ((readl(MC_ME_GS) & MC_ME_GS_S_MTRANS) != 0x00000000) ;
  59. }
  60. /*
  61. * Program the pll according to the input parameters.
  62. * pll - ARM_PLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_PLL.
  63. * refclk_freq - input reference clock frequency (FXOSC - 40 MHZ, FIRC - 48 MHZ)
  64. * freq - expected output frequency for PHY0
  65. * freq1 - expected output frequency for PHY1
  66. * dfs_nr - number of DFS modules for current PLL
  67. * dfs - array with the activation dfs field, mfn and mfi
  68. * plldv_prediv - divider of clkfreq_ref
  69. * plldv_mfd - loop multiplication factor divider
  70. * pllfd_mfn - numerator loop multiplication factor divider
  71. * Please consult the PLLDIG chapter of platform manual
  72. * before to use this function.
  73. *)
  74. */
  75. static int program_pll(enum pll_type pll, u32 refclk_freq, u32 freq0, u32 freq1,
  76. u32 dfs_nr, u32 dfs[][DFS_PARAMS_Nr], u32 plldv_prediv,
  77. u32 plldv_mfd, u32 pllfd_mfn)
  78. {
  79. u32 i, rfdphi1, rfdphi, dfs_on = 0, fvco;
  80. /*
  81. * This formula is from platform reference manual (Rev. 1, 6/2015), PLLDIG chapter.
  82. */
  83. fvco =
  84. (refclk_freq / plldv_prediv) * (plldv_mfd +
  85. pllfd_mfn / (float)20480);
  86. /*
  87. * VCO should have value in [ PLL_MIN_FREQ, PLL_MAX_FREQ ]. Please consult
  88. * the platform DataSheet in order to determine the allowed values.
  89. */
  90. if (fvco < PLL_MIN_FREQ || fvco > PLL_MAX_FREQ) {
  91. return -1;
  92. }
  93. if (select_pll_source_clk(pll, refclk_freq) < 0) {
  94. return -1;
  95. }
  96. rfdphi = fvco / freq0;
  97. rfdphi1 = (freq1 == 0) ? 0 : fvco / freq1;
  98. writel(PLLDIG_PLLDV_RFDPHI1_SET(rfdphi1) |
  99. PLLDIG_PLLDV_RFDPHI_SET(rfdphi) |
  100. PLLDIG_PLLDV_PREDIV_SET(plldv_prediv) |
  101. PLLDIG_PLLDV_MFD(plldv_mfd), PLLDIG_PLLDV(pll));
  102. writel(readl(PLLDIG_PLLFD(pll)) | PLLDIG_PLLFD_MFN_SET(pllfd_mfn) |
  103. PLLDIG_PLLFD_SMDEN, PLLDIG_PLLFD(pll));
  104. /* switch on the pll in current mode */
  105. writel(readl(MC_ME_RUNn_MC(0)) | MC_ME_RUNMODE_MC_PLL(pll),
  106. MC_ME_RUNn_MC(0));
  107. entry_to_target_mode(MC_ME_MCTL_RUN0);
  108. /* Only ARM_PLL, ENET_PLL and DDR_PLL */
  109. if ((pll == ARM_PLL) || (pll == ENET_PLL) || (pll == DDR_PLL)) {
  110. /* DFS clk enable programming */
  111. writel(DFS_CTRL_DLL_RESET, DFS_CTRL(pll));
  112. writel(DFS_DLLPRG1_CPICTRL_SET(0x5) |
  113. DFS_DLLPRG1_VSETTLCTRL_SET(0x1) |
  114. DFS_DLLPRG1_CALBYPEN_SET(0x0) |
  115. DFS_DLLPRG1_DACIN_SET(0x1) | DFS_DLLPRG1_LCKWT_SET(0x0) |
  116. DFS_DLLPRG1_V2IGC_SET(0x5), DFS_DLLPRG1(pll));
  117. for (i = 0; i < dfs_nr; i++) {
  118. if (dfs[i][0]) {
  119. writel(DFS_DVPORTn_MFI_SET(dfs[i][2]) |
  120. DFS_DVPORTn_MFN_SET(dfs[i][1]),
  121. DFS_DVPORTn(pll, i));
  122. dfs_on |= (dfs[i][0] << i);
  123. }
  124. }
  125. writel(readl(DFS_CTRL(pll)) & ~DFS_CTRL_DLL_RESET,
  126. DFS_CTRL(pll));
  127. writel(readl(DFS_PORTRESET(pll)) &
  128. ~DFS_PORTRESET_PORTRESET_SET(dfs_on),
  129. DFS_PORTRESET(pll));
  130. while ((readl(DFS_PORTSR(pll)) & dfs_on) != dfs_on) ;
  131. }
  132. entry_to_target_mode(MC_ME_MCTL_RUN0);
  133. return 0;
  134. }
  135. static void aux_source_clk_config(uintptr_t cgm_addr, u8 ac, u32 source)
  136. {
  137. /* select the clock source */
  138. writel(MC_CGM_ACn_SEL_SET(source), CGM_ACn_SC(cgm_addr, ac));
  139. }
  140. static void aux_div_clk_config(uintptr_t cgm_addr, u8 ac, u8 dc, u32 divider)
  141. {
  142. /* set the divider */
  143. writel(MC_CGM_ACn_DCm_DE | MC_CGM_ACn_DCm_PREDIV(divider),
  144. CGM_ACn_DCm(cgm_addr, ac, dc));
  145. }
  146. static void setup_sys_clocks(void)
  147. {
  148. /* set ARM PLL DFS 1 as SYSCLK */
  149. writel((readl(MC_ME_RUNn_MC(0)) & ~MC_ME_RUNMODE_MC_SYSCLK_MASK) |
  150. MC_ME_RUNMODE_MC_SYSCLK(0x2), MC_ME_RUNn_MC(0));
  151. entry_to_target_mode(MC_ME_MCTL_RUN0);
  152. /* select sysclks ARMPLL, ARMPLLDFS2, ARMPLLDFS3 */
  153. writel(MC_ME_RUNMODE_SEC_CC_I_SYSCLK
  154. (0x2,
  155. MC_ME_RUNMODE_SEC_CC_I_SYSCLK1_OFFSET) |
  156. MC_ME_RUNMODE_SEC_CC_I_SYSCLK(0x2,
  157. MC_ME_RUNMODE_SEC_CC_I_SYSCLK2_OFFSET)
  158. | MC_ME_RUNMODE_SEC_CC_I_SYSCLK(0x2,
  159. MC_ME_RUNMODE_SEC_CC_I_SYSCLK3_OFFSET),
  160. MC_ME_RUNn_SEC_CC_I(0));
  161. /* setup the sys clock divider for CORE_CLK (1000MHz) */
  162. writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x0),
  163. CGM_SC_DCn(MC_CGM1_BASE_ADDR, 0));
  164. /* setup the sys clock divider for CORE2_CLK (500MHz) */
  165. writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x1),
  166. CGM_SC_DCn(MC_CGM1_BASE_ADDR, 1));
  167. /* setup the sys clock divider for SYS3_CLK (266 MHz) */
  168. writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x0),
  169. CGM_SC_DCn(MC_CGM0_BASE_ADDR, 0));
  170. /* setup the sys clock divider for SYS6_CLK (133 Mhz) */
  171. writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x1),
  172. CGM_SC_DCn(MC_CGM0_BASE_ADDR, 1));
  173. entry_to_target_mode(MC_ME_MCTL_RUN0);
  174. }
  175. static void setup_aux_clocks(void)
  176. {
  177. /*
  178. * setup the aux clock divider for PERI_CLK
  179. * (source: PERIPH_PLL_PHI_0/5, PERI_CLK - 80 MHz)
  180. */
  181. aux_source_clk_config(MC_CGM0_BASE_ADDR, 5, MC_CGM_ACn_SEL_PERPLLDIVX);
  182. aux_div_clk_config(MC_CGM0_BASE_ADDR, 5, 0, 4);
  183. /* setup the aux clock divider for LIN_CLK (40MHz) */
  184. aux_source_clk_config(MC_CGM0_BASE_ADDR, 3, MC_CGM_ACn_SEL_PERPLLDIVX);
  185. aux_div_clk_config(MC_CGM0_BASE_ADDR, 3, 0, 1);
  186. /* setup the aux clock divider for ENET_TIME_CLK (50MHz) */
  187. aux_source_clk_config(MC_CGM0_BASE_ADDR, 7, MC_CGM_ACn_SEL_ENETPLL);
  188. aux_div_clk_config(MC_CGM0_BASE_ADDR, 7, 1, 9);
  189. /* setup the aux clock divider for ENET_CLK (50MHz) */
  190. aux_source_clk_config(MC_CGM2_BASE_ADDR, 2, MC_CGM_ACn_SEL_ENETPLL);
  191. aux_div_clk_config(MC_CGM2_BASE_ADDR, 2, 0, 9);
  192. /* setup the aux clock divider for SDHC_CLK (50 MHz). */
  193. aux_source_clk_config(MC_CGM0_BASE_ADDR, 15, MC_CGM_ACn_SEL_ENETPLL);
  194. aux_div_clk_config(MC_CGM0_BASE_ADDR, 15, 0, 9);
  195. /* setup the aux clock divider for DDR_CLK (533MHz) and APEX_SYS_CLK (266MHz) */
  196. aux_source_clk_config(MC_CGM0_BASE_ADDR, 8, MC_CGM_ACn_SEL_DDRPLL);
  197. aux_div_clk_config(MC_CGM0_BASE_ADDR, 8, 0, 0);
  198. /* setup the aux clock divider for DDR4_CLK (133,25MHz) */
  199. aux_div_clk_config(MC_CGM0_BASE_ADDR, 8, 1, 3);
  200. entry_to_target_mode(MC_ME_MCTL_RUN0);
  201. }
  202. static void enable_modules_clock(void)
  203. {
  204. /* PIT0 */
  205. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL58);
  206. /* PIT1 */
  207. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL170);
  208. /* LINFLEX0 */
  209. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL83);
  210. /* LINFLEX1 */
  211. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL188);
  212. /* ENET */
  213. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL50);
  214. /* SDHC */
  215. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL93);
  216. /* IIC0 */
  217. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL81);
  218. /* IIC1 */
  219. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL184);
  220. /* IIC2 */
  221. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL186);
  222. /* MMDC0 */
  223. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL54);
  224. /* MMDC1 */
  225. writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL162);
  226. entry_to_target_mode(MC_ME_MCTL_RUN0);
  227. }
  228. void clock_init(void)
  229. {
  230. unsigned int arm_dfs[ARM_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
  231. {ARM_PLL_PHI1_DFS1_EN, ARM_PLL_PHI1_DFS1_MFN,
  232. ARM_PLL_PHI1_DFS1_MFI},
  233. {ARM_PLL_PHI1_DFS2_EN, ARM_PLL_PHI1_DFS2_MFN,
  234. ARM_PLL_PHI1_DFS2_MFI},
  235. {ARM_PLL_PHI1_DFS3_EN, ARM_PLL_PHI1_DFS3_MFN,
  236. ARM_PLL_PHI1_DFS3_MFI}
  237. };
  238. unsigned int enet_dfs[ENET_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
  239. {ENET_PLL_PHI1_DFS1_EN, ENET_PLL_PHI1_DFS1_MFN,
  240. ENET_PLL_PHI1_DFS1_MFI},
  241. {ENET_PLL_PHI1_DFS2_EN, ENET_PLL_PHI1_DFS2_MFN,
  242. ENET_PLL_PHI1_DFS2_MFI},
  243. {ENET_PLL_PHI1_DFS3_EN, ENET_PLL_PHI1_DFS3_MFN,
  244. ENET_PLL_PHI1_DFS3_MFI},
  245. {ENET_PLL_PHI1_DFS4_EN, ENET_PLL_PHI1_DFS4_MFN,
  246. ENET_PLL_PHI1_DFS4_MFI}
  247. };
  248. unsigned int ddr_dfs[DDR_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
  249. {DDR_PLL_PHI1_DFS1_EN, DDR_PLL_PHI1_DFS1_MFN,
  250. DDR_PLL_PHI1_DFS1_MFI},
  251. {DDR_PLL_PHI1_DFS2_EN, DDR_PLL_PHI1_DFS2_MFN,
  252. DDR_PLL_PHI1_DFS2_MFI},
  253. {DDR_PLL_PHI1_DFS3_EN, DDR_PLL_PHI1_DFS3_MFN,
  254. DDR_PLL_PHI1_DFS3_MFI}
  255. };
  256. writel(MC_ME_RUN_PCn_DRUN | MC_ME_RUN_PCn_RUN0 | MC_ME_RUN_PCn_RUN1 |
  257. MC_ME_RUN_PCn_RUN2 | MC_ME_RUN_PCn_RUN3, MC_ME_RUN_PCn(0));
  258. /* turn on FXOSC */
  259. writel(MC_ME_RUNMODE_MC_MVRON | MC_ME_RUNMODE_MC_XOSCON |
  260. MC_ME_RUNMODE_MC_FIRCON | MC_ME_RUNMODE_MC_SYSCLK(0x1),
  261. MC_ME_RUNn_MC(0));
  262. entry_to_target_mode(MC_ME_MCTL_RUN0);
  263. program_pll(ARM_PLL, XOSC_CLK_FREQ, ARM_PLL_PHI0_FREQ,
  264. ARM_PLL_PHI1_FREQ, ARM_PLL_PHI1_DFS_Nr, arm_dfs,
  265. ARM_PLL_PLLDV_PREDIV, ARM_PLL_PLLDV_MFD, ARM_PLL_PLLDV_MFN);
  266. setup_sys_clocks();
  267. program_pll(PERIPH_PLL, XOSC_CLK_FREQ, PERIPH_PLL_PHI0_FREQ,
  268. PERIPH_PLL_PHI1_FREQ, PERIPH_PLL_PHI1_DFS_Nr, NULL,
  269. PERIPH_PLL_PLLDV_PREDIV, PERIPH_PLL_PLLDV_MFD,
  270. PERIPH_PLL_PLLDV_MFN);
  271. program_pll(ENET_PLL, XOSC_CLK_FREQ, ENET_PLL_PHI0_FREQ,
  272. ENET_PLL_PHI1_FREQ, ENET_PLL_PHI1_DFS_Nr, enet_dfs,
  273. ENET_PLL_PLLDV_PREDIV, ENET_PLL_PLLDV_MFD,
  274. ENET_PLL_PLLDV_MFN);
  275. program_pll(DDR_PLL, XOSC_CLK_FREQ, DDR_PLL_PHI0_FREQ,
  276. DDR_PLL_PHI1_FREQ, DDR_PLL_PHI1_DFS_Nr, ddr_dfs,
  277. DDR_PLL_PLLDV_PREDIV, DDR_PLL_PLLDV_MFD, DDR_PLL_PLLDV_MFN);
  278. program_pll(VIDEO_PLL, XOSC_CLK_FREQ, VIDEO_PLL_PHI0_FREQ,
  279. VIDEO_PLL_PHI1_FREQ, VIDEO_PLL_PHI1_DFS_Nr, NULL,
  280. VIDEO_PLL_PLLDV_PREDIV, VIDEO_PLL_PLLDV_MFD,
  281. VIDEO_PLL_PLLDV_MFN);
  282. setup_aux_clocks();
  283. enable_modules_clock();
  284. }