blob: 5dbc398e97f8b79e367eef9079b7cb6ad066360a [file] [log] [blame]
Peng Fan28b5cb52022-07-26 16:40:43 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 NXP
4 *
5 * Peng Fan <peng.fan@nxp.com>
6 */
7
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <config.h>
Peng Fan28b5cb52022-07-26 16:40:43 +08009#include <command.h>
Peng Fane2c76432024-10-23 12:03:17 +080010#include <asm/arch/ccm_regs.h>
Peng Fan28b5cb52022-07-26 16:40:43 +080011#include <asm/arch/clock.h>
Peng Fane2c76432024-10-23 12:03:17 +080012#include <asm/arch/imx-regs.h>
Peng Fan28b5cb52022-07-26 16:40:43 +080013#include <asm/arch/sys_proto.h>
Peng Fan28b5cb52022-07-26 16:40:43 +080014#include <asm/global_data.h>
15#include <linux/iopoll.h>
16
17DECLARE_GLOBAL_DATA_PTR;
18
19static struct ccm_reg *ccm_reg = (struct ccm_reg *)CCM_BASE_ADDR;
20
21static 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
33static 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 },
Peng Fand5c31832023-06-15 18:09:05 +080038 { ELE_CLK_ROOT, 2 },
Peng Fan28b5cb52022-07-26 16:40:43 +080039 { 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
131int 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] */
153int 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
174int 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
195int 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
221bool ccm_clk_src_is_clk_on(enum ccm_clk_src oscpll)
222{
223 return !!(readl(&ccm_reg->clk_oscplls[oscpll].status0) & 0x1);
224}
225
226int 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
244int 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
276u32 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
298int 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
316int 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
337int 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
354int 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
380bool ccm_lpcg_is_clk_on(u32 lpcg)
381{
382 return !!(readl(&ccm_reg->clk_lpcgs[lpcg].status0) & 0x1);
383}
384
385int 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
403int 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
413int 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
423int 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}