blob: 7d7ae865946f3b232276b7cbdb17ddc586307bfa [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
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
16DECLARE_GLOBAL_DATA_PTR;
17
18static struct ccm_reg *ccm_reg = (struct ccm_reg *)CCM_BASE_ADDR;
19
20static 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
32static 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 },
Peng Fand5c31832023-06-15 18:09:05 +080037 { ELE_CLK_ROOT, 2 },
Peng Fan28b5cb52022-07-26 16:40:43 +080038 { 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
130int 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] */
152int 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
173int 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
194int 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
220bool ccm_clk_src_is_clk_on(enum ccm_clk_src oscpll)
221{
222 return !!(readl(&ccm_reg->clk_oscplls[oscpll].status0) & 0x1);
223}
224
225int 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
243int 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
275u32 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
297int 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
315int 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
336int 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
353int 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
379bool ccm_lpcg_is_clk_on(u32 lpcg)
380{
381 return !!(readl(&ccm_reg->clk_lpcgs[lpcg].status0) & 0x1);
382}
383
384int 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
402int 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
412int 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
422int 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}