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