clock.c 10 KB

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