1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2022 NXP
4  *
5  * Peng Fan <peng.fan@nxp.com>
6  */
7 
8 #include <config.h>
9 #include <command.h>
10 #include <asm/arch/ccm_regs.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/imx-regs.h>
13 #include <asm/arch/sys_proto.h>
14 #include <asm/global_data.h>
15 #include <linux/iopoll.h>
16 
17 DECLARE_GLOBAL_DATA_PTR;
18 
19 static struct ccm_reg *ccm_reg = (struct ccm_reg *)CCM_BASE_ADDR;
20 
21 static enum ccm_clk_src clk_root_mux[][4] = {
22 	{ OSC_24M_CLK, SYS_PLL_PFD0, SYS_PLL_PFD1, SYS_PLL_PFD2 }, /* bus */
23 	{ OSC_24M_CLK, SYS_PLL_PFD0_DIV2, SYS_PLL_PFD1_DIV2, SYS_PLL_PFD2_DIV2 }, /* non-IO */
24 	{ OSC_24M_CLK, SYS_PLL_PFD0_DIV2, SYS_PLL_PFD1_DIV2, VIDEO_PLL_CLK }, /* IO*/
25 	{ OSC_24M_CLK, SYS_PLL_PFD0, AUDIO_PLL_CLK, EXT_CLK  }, /* TPM */
26 	{ OSC_24M_CLK, AUDIO_PLL_CLK, VIDEO_PLL_CLK, EXT_CLK }, /* Audio */
27 	{ OSC_24M_CLK, AUDIO_PLL_CLK, VIDEO_PLL_CLK, SYS_PLL_PFD0 }, /* Video */
28 	{ OSC_24M_CLK, SYS_PLL_PFD0, SYS_PLL_PFD1, AUDIO_PLL_CLK }, /* CKO1 */
29 	{ OSC_24M_CLK, SYS_PLL_PFD0, SYS_PLL_PFD1, VIDEO_PLL_CLK }, /* CKO2 */
30 	{ OSC_24M_CLK, AUDIO_PLL_CLK, VIDEO_PLL_CLK, SYS_PLL_PFD2 }, /* CAMSCAN */
31 };
32 
33 static struct clk_root_map clk_root_array[] = {
34 	{ ARM_A55_PERIPH_CLK_ROOT,	0 },
35 	{ ARM_A55_MTR_BUS_CLK_ROOT,	2 },
36 	{ ARM_A55_CLK_ROOT,		0 },
37 	{ M33_CLK_ROOT,			2 },
38 	{ ELE_CLK_ROOT,			2 },
39 	{ BUS_WAKEUP_CLK_ROOT,		2 },
40 	{ BUS_AON_CLK_ROOT,		2 },
41 	{ WAKEUP_AXI_CLK_ROOT,		0 },
42 	{ SWO_TRACE_CLK_ROOT,		2 },
43 	{ M33_SYSTICK_CLK_ROOT,		2 },
44 	{ FLEXIO1_CLK_ROOT,		2 },
45 	{ FLEXIO2_CLK_ROOT,		2 },
46 	{ LPIT1_CLK_ROOT,		2 },
47 	{ LPIT2_CLK_ROOT,		2 },
48 	{ LPTMR1_CLK_ROOT,		2 },
49 	{ LPTMR2_CLK_ROOT,		2 },
50 	{ TPM1_CLK_ROOT,		3 },
51 	{ TPM2_CLK_ROOT,		3 },
52 	{ TPM3_CLK_ROOT,		3 },
53 	{ TPM4_CLK_ROOT,		3 },
54 	{ TPM5_CLK_ROOT,		3 },
55 	{ TPM6_CLK_ROOT,		3 },
56 	{ FLEXSPI1_CLK_ROOT,		0 },
57 	{ CAN1_CLK_ROOT,		2 },
58 	{ CAN2_CLK_ROOT,		2 },
59 	{ LPUART1_CLK_ROOT,		2 },
60 	{ LPUART2_CLK_ROOT,		2 },
61 	{ LPUART3_CLK_ROOT,		2 },
62 	{ LPUART4_CLK_ROOT,		2 },
63 	{ LPUART5_CLK_ROOT,		2 },
64 	{ LPUART6_CLK_ROOT,		2 },
65 	{ LPUART7_CLK_ROOT,		2 },
66 	{ LPUART8_CLK_ROOT,		2 },
67 	{ LPI2C1_CLK_ROOT,		2 },
68 	{ LPI2C2_CLK_ROOT,		2 },
69 	{ LPI2C3_CLK_ROOT,		2 },
70 	{ LPI2C4_CLK_ROOT,		2 },
71 	{ LPI2C5_CLK_ROOT,		2 },
72 	{ LPI2C6_CLK_ROOT,		2 },
73 	{ LPI2C7_CLK_ROOT,		2 },
74 	{ LPI2C8_CLK_ROOT,		2 },
75 	{ LPSPI1_CLK_ROOT,		2 },
76 	{ LPSPI2_CLK_ROOT,		2 },
77 	{ LPSPI3_CLK_ROOT,		2 },
78 	{ LPSPI4_CLK_ROOT,		2 },
79 	{ LPSPI5_CLK_ROOT,		2 },
80 	{ LPSPI6_CLK_ROOT,		2 },
81 	{ LPSPI7_CLK_ROOT,		2 },
82 	{ LPSPI8_CLK_ROOT,		2 },
83 	{ I3C1_CLK_ROOT,		2 },
84 	{ I3C2_CLK_ROOT,		2 },
85 	{ USDHC1_CLK_ROOT,		0 },
86 	{ USDHC2_CLK_ROOT,		0 },
87 	{ USDHC3_CLK_ROOT,		0 },
88 	{ SAI1_CLK_ROOT,		4 },
89 	{ SAI2_CLK_ROOT,		4 },
90 	{ SAI3_CLK_ROOT,		4 },
91 	{ CCM_CKO1_CLK_ROOT,		6 },
92 	{ CCM_CKO2_CLK_ROOT,		7 },
93 	{ CCM_CKO3_CLK_ROOT,		6 },
94 	{ CCM_CKO4_CLK_ROOT,		7 },
95 	{ HSIO_CLK_ROOT,		2 },
96 	{ HSIO_USB_TEST_60M_CLK_ROOT,	2 },
97 	{ HSIO_ACSCAN_80M_CLK_ROOT,	2 },
98 	{ HSIO_ACSCAN_480M_CLK_ROOT,	0 },
99 	{ NIC_CLK_ROOT,			0 },
100 	{ NIC_APB_CLK_ROOT,		2 },
101 	{ ML_APB_CLK_ROOT,		2 },
102 	{ ML_CLK_ROOT,			0 },
103 	{ MEDIA_AXI_CLK_ROOT,		0 },
104 	{ MEDIA_APB_CLK_ROOT,		2 },
105 	{ MEDIA_LDB_CLK_ROOT,		5 },
106 	{ MEDIA_DISP_PIX_CLK_ROOT,	5 },
107 	{ CAM_PIX_CLK_ROOT,		5 },
108 	{ MIPI_TEST_BYTE_CLK_ROOT,	5 },
109 	{ MIPI_PHY_CFG_CLK_ROOT,	5 },
110 	{ DRAM_ALT_CLK_ROOT,		0 },
111 	{ DRAM_APB_CLK_ROOT,		1 },
112 	{ ADC_CLK_ROOT,			2 },
113 	{ PDM_CLK_ROOT,			4 },
114 	{ TSTMR1_CLK_ROOT,		2 },
115 	{ TSTMR2_CLK_ROOT,		2 },
116 	{ MQS1_CLK_ROOT,		4 },
117 	{ MQS2_CLK_ROOT,		4 },
118 	{ AUDIO_XCVR_CLK_ROOT,		1 },
119 	{ SPDIF_CLK_ROOT,		4 },
120 	{ ENET_CLK_ROOT,		1 },
121 	{ ENET_TIMER1_CLK_ROOT,		2 },
122 	{ ENET_TIMER2_CLK_ROOT,		2 },
123 	{ ENET_REF_CLK_ROOT,		1 },
124 	{ ENET_REF_PHY_CLK_ROOT,	2 },
125 	{ I3C1_SLOW_CLK_ROOT,		2 },
126 	{ I3C2_SLOW_CLK_ROOT,		2 },
127 	{ USB_PHY_BURUNIN_CLK_ROOT,	2 },
128 	{ PAL_CAME_SCAN_CLK_ROOT,	8 },
129 };
130 
ccm_clk_src_on(enum ccm_clk_src oscpll,bool enable)131 int ccm_clk_src_on(enum ccm_clk_src oscpll, bool enable)
132 {
133 	u32 authen;
134 
135 	if (oscpll >= OSCPLL_END)
136 		return -EINVAL;
137 
138 	authen = readl(&ccm_reg->clk_oscplls[oscpll].authen);
139 
140 	/* If using cpulpm, need disable it first */
141 	if (authen & CCM_AUTHEN_CPULPM_MODE)
142 		return -EPERM;
143 
144 	if (enable)
145 		writel(1, &ccm_reg->clk_oscplls[oscpll].direct);
146 	else
147 		writel(0, &ccm_reg->clk_oscplls[oscpll].direct);
148 
149 	return 0;
150 }
151 
152 /* auto mode, enable =  DIRECT[ON] | STATUS0[IN_USE] */
ccm_clk_src_auto(enum ccm_clk_src oscpll,bool enable)153 int ccm_clk_src_auto(enum ccm_clk_src oscpll, bool enable)
154 {
155 	u32 authen;
156 
157 	if (oscpll >= OSCPLL_END)
158 		return -EINVAL;
159 
160 	authen = readl(&ccm_reg->clk_oscplls[oscpll].authen);
161 
162 	/* AUTO CTRL and CPULPM are mutual exclusion, need disable CPULPM first */
163 	if (authen & CCM_AUTHEN_CPULPM_MODE)
164 		return -EPERM;
165 
166 	if (enable)
167 		writel(authen | CCM_AUTHEN_AUTO_CTRL, &ccm_reg->clk_oscplls[oscpll].authen);
168 	else
169 		writel((authen & ~CCM_AUTHEN_AUTO_CTRL), &ccm_reg->clk_oscplls[oscpll].authen);
170 
171 	return 0;
172 }
173 
ccm_clk_src_lpm(enum ccm_clk_src oscpll,bool enable)174 int ccm_clk_src_lpm(enum ccm_clk_src oscpll, bool enable)
175 {
176 	u32 authen;
177 
178 	if (oscpll >= OSCPLL_END)
179 		return -EINVAL;
180 
181 	authen = readl(&ccm_reg->clk_oscplls[oscpll].authen);
182 
183 	/* AUTO CTRL and CPULPM are mutual exclusion, need disable AUTO CTRL first */
184 	if (authen & CCM_AUTHEN_AUTO_CTRL)
185 		return -EPERM;
186 
187 	if (enable)
188 		writel(authen | CCM_AUTHEN_CPULPM_MODE, &ccm_reg->clk_oscplls[oscpll].authen);
189 	else
190 		writel((authen & ~CCM_AUTHEN_CPULPM_MODE), &ccm_reg->clk_oscplls[oscpll].authen);
191 
192 	return 0;
193 }
194 
ccm_clk_src_config_lpm(enum ccm_clk_src oscpll,u32 domain,u32 lpm_val)195 int ccm_clk_src_config_lpm(enum ccm_clk_src oscpll, u32 domain, u32 lpm_val)
196 {
197 	u32 lpm, authen;
198 
199 	if (oscpll >= OSCPLL_END || domain >= 16)
200 		return -EINVAL;
201 
202 	authen = readl(&ccm_reg->clk_oscplls[oscpll].authen);
203 	if (!(authen & CCM_AUTHEN_CPULPM_MODE))
204 		return -EPERM;
205 
206 	if (domain > 7) {
207 		lpm = readl(&ccm_reg->clk_oscplls[oscpll].lpm1);
208 		lpm &= ~(0x3 << ((domain - 8) * 4));
209 		lpm |= (lpm_val & 0x3) << ((domain - 8) * 4);
210 		writel(lpm, &ccm_reg->clk_oscplls[oscpll].lpm1);
211 	} else {
212 		lpm = readl(&ccm_reg->clk_oscplls[oscpll].lpm0);
213 		lpm &= ~(0x3 << (domain * 4));
214 		lpm |= (lpm_val & 0x3) << (domain * 4);
215 		writel(lpm, &ccm_reg->clk_oscplls[oscpll].lpm0);
216 	}
217 
218 	return 0;
219 }
220 
ccm_clk_src_is_clk_on(enum ccm_clk_src oscpll)221 bool ccm_clk_src_is_clk_on(enum ccm_clk_src oscpll)
222 {
223 	return !!(readl(&ccm_reg->clk_oscplls[oscpll].status0) & 0x1);
224 }
225 
ccm_clk_src_tz_access(enum ccm_clk_src oscpll,bool non_secure,bool user_mode,bool lock_tz)226 int ccm_clk_src_tz_access(enum ccm_clk_src oscpll, bool non_secure, bool user_mode, bool lock_tz)
227 {
228 	u32 authen;
229 
230 	if (oscpll >= OSCPLL_END)
231 		return -EINVAL;
232 
233 	authen = readl(&ccm_reg->clk_oscplls[oscpll].authen);
234 
235 	authen |= non_secure ? CCM_AUTHEN_TZ_NS : 0;
236 	authen |= user_mode ? CCM_AUTHEN_TZ_USER : 0;
237 	authen |= lock_tz ? CCM_AUTHEN_LOCK_TZ : 0;
238 
239 	writel(authen, &ccm_reg->clk_oscplls[oscpll].authen);
240 
241 	return 0;
242 }
243 
ccm_clk_root_cfg(u32 clk_root_id,enum ccm_clk_src src,u32 div)244 int ccm_clk_root_cfg(u32 clk_root_id, enum ccm_clk_src src, u32 div)
245 {
246 	int i;
247 	int ret;
248 	u32 mux, status;
249 
250 	if (clk_root_id >= CLK_ROOT_NUM || div > 256 || div == 0)
251 		return -EINVAL;
252 
253 	mux = clk_root_array[clk_root_id].mux_type;
254 
255 	for (i = 0; i < 4; i++) {
256 		if (src == clk_root_mux[mux][i])
257 			break;
258 	}
259 
260 	if (i == 4) {
261 		printf("Invalid source [%u] for this clk root\n", src);
262 		return -EINVAL;
263 	}
264 
265 	writel((i << 8) | (div - 1), &ccm_reg->clk_roots[clk_root_id].control);
266 
267 	ret = readl_poll_timeout(&ccm_reg->clk_roots[clk_root_id].status0, status,
268 				 !(status & CLK_ROOT_STATUS_CHANGING), 200000);
269 	if (ret)
270 		printf("%s: failed, status: 0x%x\n", __func__,
271 		       readl(&ccm_reg->clk_roots[clk_root_id].status0));
272 
273 	return ret;
274 };
275 
ccm_clk_root_get_rate(u32 clk_root_id)276 u32 ccm_clk_root_get_rate(u32 clk_root_id)
277 {
278 	u32 mux, status, div, rate;
279 	enum ccm_clk_src src;
280 
281 	if (clk_root_id >= CLK_ROOT_NUM)
282 		return 0;
283 
284 	status = readl(&ccm_reg->clk_roots[clk_root_id].control);
285 
286 	if (status & CLK_ROOT_STATUS_OFF)
287 		return 0; /* clock is off */
288 
289 	mux = (status & CLK_ROOT_MUX_MASK) >> CLK_ROOT_MUX_SHIFT;
290 	div = status & CLK_ROOT_DIV_MASK;
291 	src = clk_root_mux[clk_root_array[clk_root_id].mux_type][mux];
292 
293 	rate = get_clk_src_rate(src) * 1000;
294 
295 	return rate / (div + 1); /* return in hz */
296 }
297 
ccm_clk_root_tz_access(u32 clk_root_id,bool non_secure,bool user_mode,bool lock_tz)298 int ccm_clk_root_tz_access(u32 clk_root_id, bool non_secure, bool user_mode, bool lock_tz)
299 {
300 	u32 authen;
301 
302 	if (clk_root_id >= CLK_ROOT_NUM)
303 		return -EINVAL;
304 
305 	authen = readl(&ccm_reg->clk_roots[clk_root_id].authen);
306 
307 	authen |= non_secure ? CCM_AUTHEN_TZ_NS : 0;
308 	authen |= user_mode ? CCM_AUTHEN_TZ_USER : 0;
309 	authen |= lock_tz ? CCM_AUTHEN_LOCK_TZ : 0;
310 
311 	writel(authen, &ccm_reg->clk_roots[clk_root_id].authen);
312 
313 	return 0;
314 }
315 
ccm_lpcg_on(u32 lpcg,bool enable)316 int ccm_lpcg_on(u32 lpcg, bool enable)
317 {
318 	u32 authen;
319 
320 	if (lpcg >= CCGR_NUM)
321 		return -EINVAL;
322 
323 	authen = readl(&ccm_reg->clk_lpcgs[lpcg].authen);
324 
325 	/* If using cpulpm, need disable it first */
326 	if (authen & CCM_AUTHEN_CPULPM_MODE)
327 		return -EPERM;
328 
329 	if (enable)
330 		writel(1, &ccm_reg->clk_lpcgs[lpcg].direct);
331 	else
332 		writel(0, &ccm_reg->clk_lpcgs[lpcg].direct);
333 
334 	return 0;
335 }
336 
ccm_lpcg_lpm(u32 lpcg,bool enable)337 int ccm_lpcg_lpm(u32 lpcg, bool enable)
338 {
339 	u32 authen;
340 
341 	if (lpcg >= CCGR_NUM)
342 		return -EINVAL;
343 
344 	authen = readl(&ccm_reg->clk_lpcgs[lpcg].authen);
345 
346 	if (enable)
347 		writel(authen | CCM_AUTHEN_CPULPM_MODE, &ccm_reg->clk_lpcgs[lpcg].authen);
348 	else
349 		writel((authen & ~CCM_AUTHEN_CPULPM_MODE), &ccm_reg->clk_lpcgs[lpcg].authen);
350 
351 	return 0;
352 }
353 
ccm_lpcg_config_lpm(u32 lpcg,u32 domain,u32 lpm_val)354 int ccm_lpcg_config_lpm(u32 lpcg, u32 domain, u32 lpm_val)
355 {
356 	u32 lpm, authen;
357 
358 	if (lpcg >= CCGR_NUM || domain >= 16)
359 		return -EINVAL;
360 
361 	authen = readl(&ccm_reg->clk_lpcgs[lpcg].authen);
362 	if (!(authen & CCM_AUTHEN_CPULPM_MODE))
363 		return -EPERM;
364 
365 	if (domain > 7) {
366 		lpm = readl(&ccm_reg->clk_lpcgs[lpcg].lpm1);
367 		lpm &= ~(0x3 << ((domain - 8) * 4));
368 		lpm |= (lpm_val & 0x3) << ((domain - 8) * 4);
369 		writel(lpm, &ccm_reg->clk_lpcgs[lpcg].lpm1);
370 	} else {
371 		lpm = readl(&ccm_reg->clk_lpcgs[lpcg].lpm0);
372 		lpm &= ~(0x3 << (domain * 4));
373 		lpm |= (lpm_val & 0x3) << (domain * 4);
374 		writel(lpm, &ccm_reg->clk_lpcgs[lpcg].lpm0);
375 	}
376 
377 	return 0;
378 }
379 
ccm_lpcg_is_clk_on(u32 lpcg)380 bool ccm_lpcg_is_clk_on(u32 lpcg)
381 {
382 	return !!(readl(&ccm_reg->clk_lpcgs[lpcg].status0) & 0x1);
383 }
384 
ccm_lpcg_tz_access(u32 lpcg,bool non_secure,bool user_mode,bool lock_tz)385 int ccm_lpcg_tz_access(u32 lpcg, bool non_secure, bool user_mode, bool lock_tz)
386 {
387 	u32 authen;
388 
389 	if (lpcg >= CCGR_NUM)
390 		return -EINVAL;
391 
392 	authen = readl(&ccm_reg->clk_lpcgs[lpcg].authen);
393 
394 	authen |= non_secure ? CCM_AUTHEN_TZ_NS : 0;
395 	authen |= user_mode ? CCM_AUTHEN_TZ_USER : 0;
396 	authen |= lock_tz ? CCM_AUTHEN_LOCK_TZ : 0;
397 
398 	writel(authen, &ccm_reg->clk_lpcgs[lpcg].authen);
399 
400 	return 0;
401 }
402 
ccm_shared_gpr_set(u32 gpr,u32 val)403 int ccm_shared_gpr_set(u32 gpr, u32 val)
404 {
405 	if (gpr >= SHARED_GPR_NUM)
406 		return -EINVAL;
407 
408 	writel(val, &ccm_reg->clk_shared_gpr[gpr].gpr);
409 
410 	return 0;
411 }
412 
ccm_shared_gpr_get(u32 gpr,u32 * val)413 int ccm_shared_gpr_get(u32 gpr, u32 *val)
414 {
415 	if (gpr >= SHARED_GPR_NUM || !val)
416 		return -EINVAL;
417 
418 	*val = readl(&ccm_reg->clk_shared_gpr[gpr].gpr);
419 
420 	return 0;
421 }
422 
ccm_shared_gpr_tz_access(u32 gpr,bool non_secure,bool user_mode,bool lock_tz)423 int ccm_shared_gpr_tz_access(u32 gpr, bool non_secure, bool user_mode, bool lock_tz)
424 {
425 	u32 authen;
426 
427 	if (gpr >= SHARED_GPR_NUM)
428 		return -EINVAL;
429 
430 	authen = readl(&ccm_reg->clk_shared_gpr[gpr].authen);
431 
432 	authen |= non_secure ? CCM_AUTHEN_TZ_NS : 0;
433 	authen |= user_mode ? CCM_AUTHEN_TZ_USER : 0;
434 	authen |= lock_tz ? CCM_AUTHEN_LOCK_TZ : 0;
435 
436 	writel(authen, &ccm_reg->clk_shared_gpr[gpr].authen);
437 
438 	return 0;
439 }
440