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