1 /*
2 * Copyright 2017-2020 NXP
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include "fsl_clock.h"
8
9 /*******************************************************************************
10 * Definitions
11 ******************************************************************************/
12 /* Component ID definition, used by tools. */
13 #ifndef FSL_COMPONENT_ID
14 #define FSL_COMPONENT_ID "platform.drivers.clock"
15 #endif
16 /* LPCG register Bits Mask. LPCG register generally comes in four bit groups, a STOP, Reserved, [P|B]CG(SWEN), HWEN
17 * nibble. The HWEN bits are optional, but the allocations of the nibble always be on four bit boundaries. */
18 #define LPCG_CLK_HWEN_MASK (0x11111111U)
19 #define LPCG_CLK_SWEN_MASK (0x22222222U)
20 #define LPCG_CLK_STOP_MASK (0x88888888U)
21
22 /*******************************************************************************
23 * Variables
24 ******************************************************************************/
25 static sc_ipc_t ipcHandle;
26
27 /*******************************************************************************
28 * Prototypes
29 ******************************************************************************/
30
31 /*******************************************************************************
32 * Code
33 ******************************************************************************/
34
35 /*!
36 * brief Initialize Clock module.
37 *
38 * param ipc IPC handle for communication with SCU, see \ref sc_ipc_t.
39 */
CLOCK_Init(sc_ipc_t ipc)40 void CLOCK_Init(sc_ipc_t ipc)
41 {
42 ipcHandle = ipc;
43 }
44
45 /*!
46 * brief Deinitialize Clock module.
47 */
CLOCK_Deinit(void)48 void CLOCK_Deinit(void)
49 {
50 }
51
52 /*!
53 * brief Enable the clock for specific IP, with gate setting.
54 *
55 * param name Which clock to enable, see \ref clock_ip_name_t.
56 * param gate 0: clock always on, 1: HW auto clock gating.
57 * return true if success, false if failure.
58 */
CLOCK_EnableClockExt(clock_ip_name_t name,uint32_t gate)59 bool CLOCK_EnableClockExt(clock_ip_name_t name, uint32_t gate)
60 {
61 return CLOCK_EnableClockExtMapped((uint32_t *)LPCG_TUPLE_REG_BASE(name), name, gate);
62 }
63
64
65 /*!
66 * brief Enable the clock for specific IP, with gate setting (mapped version).
67 *
68 * param lpcgBase Virtual/physical base address of the LPCG region associated with IP.
69 * param name Which clock to enable, see \ref clock_ip_name_t.
70 * param gate 0: clock always on, 1: HW auto clock gating.
71 * return true if success, false if failure.
72 */
CLOCK_EnableClockExtMapped(uint32_t * lpcgBase,clock_ip_name_t name,uint32_t gate)73 bool CLOCK_EnableClockExtMapped(uint32_t *lpcgBase, clock_ip_name_t name, uint32_t gate)
74 {
75 sc_err_t err;
76
77 err = sc_pm_clock_enable(ipcHandle, LPCG_TUPLE_RSRC(name), SC_PM_CLK_PER, true, (bool)gate);
78
79 /* Enable the Clock Gate control in LPCG */
80 CLOCK_ConfigLPCGMapped(lpcgBase, name, true, (bool)gate);
81
82 if (err != SC_ERR_NONE)
83 {
84 return false;
85 }
86 else
87 {
88 return true;
89 }
90 }
91
92 /*!
93 * brief Disable the clock for specific IP.
94 *
95 * param name Which clock to disable, see \ref clock_ip_name_t.
96 * return true for success, false for failure.
97 */
CLOCK_DisableClock(clock_ip_name_t name)98 bool CLOCK_DisableClock(clock_ip_name_t name)
99 {
100 return CLOCK_DisableClockMapped((uint32_t *)LPCG_TUPLE_REG_BASE(name), name);
101 }
102
103 /*!
104 * brief Disable the clock for specific IP (mapped version).
105 *
106 * param lpcgBase Virtual/physical base address of the LPCG region associated with IP.
107 * param name Which clock to disable, see \ref clock_ip_name_t.
108 * return true for success, false for failure.
109 */
CLOCK_DisableClockMapped(uint32_t * lpcgBase,clock_ip_name_t name)110 bool CLOCK_DisableClockMapped(uint32_t *lpcgBase, clock_ip_name_t name)
111 {
112 sc_err_t err;
113
114 /* Disable the Clock Gate control in LPCG */
115 CLOCK_ConfigLPCGMapped(lpcgBase, name, false, false);
116
117 err = sc_pm_clock_enable(ipcHandle, LPCG_TUPLE_RSRC(name), SC_PM_CLK_PER, false, false);
118
119 if (err != SC_ERR_NONE)
120 {
121 return false;
122 }
123 else
124 {
125 return true;
126 }
127 }
128
129 /*!
130 * brief Set the clock frequency for specific IP module.
131 *
132 * This function sets the IP module clock frequency.
133 *
134 * param name Which peripheral to check, see \ref clock_ip_name_t.
135 * param freq Target clock frequency value in hertz.
136 * return the Real clock frequency value in hertz, or 0 if failed
137 */
CLOCK_SetIpFreq(clock_ip_name_t name,uint32_t freq)138 uint32_t CLOCK_SetIpFreq(clock_ip_name_t name, uint32_t freq)
139 {
140 uint32_t target = freq;
141 sc_err_t err;
142
143 err = sc_pm_set_clock_rate(ipcHandle, LPCG_TUPLE_RSRC(name), SC_PM_CLK_PER, &target);
144 if (err != SC_ERR_NONE)
145 {
146 return 0;
147 }
148 else
149 {
150 return target;
151 }
152 }
153
154 /*!
155 * brief Get the clock frequency for a specific IP module.
156 *
157 * This function gets the IP module clock frequency.
158 *
159 * param name Which peripheral to get, see \ref clock_ip_name_t.
160 * return Clock frequency value in hertz, or 0 if failed
161 */
CLOCK_GetIpFreq(clock_ip_name_t name)162 uint32_t CLOCK_GetIpFreq(clock_ip_name_t name)
163 {
164 uint32_t freq;
165 sc_err_t err;
166
167 err = sc_pm_get_clock_rate(ipcHandle, LPCG_TUPLE_RSRC(name), SC_PM_CLK_PER, &freq);
168 if (err != SC_ERR_NONE)
169 {
170 return 0;
171 }
172 else
173 {
174 return freq;
175 }
176 }
177
178 /*!
179 * brief Get the core clock or system clock frequency.
180 *
181 * return Clock frequency in Hz.
182 */
CLOCK_GetCoreSysClkFreq(void)183 uint32_t CLOCK_GetCoreSysClkFreq(void)
184 {
185 uint32_t freq;
186 sc_err_t err;
187 #if defined(MIMX8QM_CM4_CORE0)
188 err = sc_pm_get_clock_rate(ipcHandle, SC_R_M4_0_PID0, SC_PM_CLK_PER, &freq);
189 #elif defined(MIMX8QM_CM4_CORE1)
190 err = sc_pm_get_clock_rate(ipcHandle, SC_R_M4_1_PID0, SC_PM_CLK_PER, &freq);
191 #else
192 /* core is not supported, set error code to a value != SC_ERR_NONE such
193 * that the reported frequency will be 0 (same as if an IPC error occured).
194 */
195 err = SC_ERR_NOTFOUND;
196 #endif
197 if (err != SC_ERR_NONE)
198 {
199 freq = 0U;
200 }
201
202 return freq;
203 }
204
205 /*!
206 * brief Gets the clock frequency for a specific clock name.
207 *
208 * This function checks the current clock configurations and then calculates
209 * the clock frequency for a specific clock name defined in clock_name_t.
210 *
211 * param clockName Clock names defined in clock_name_t
212 * return Clock frequency value in hertz
213 */
CLOCK_GetFreq(clock_name_t name)214 uint32_t CLOCK_GetFreq(clock_name_t name)
215 {
216 uint32_t freq;
217
218 switch (name)
219 {
220 case kCLOCK_CONECTIVITY_AhbClk:
221 freq = 167000000U; /* The CONNECTIVITY SS AHB clock is fixed to 166MHZ */
222 break;
223 case kCLOCK_CoreSysClk:
224 freq = CLOCK_GetCoreSysClkFreq();
225 break;
226 default:
227 freq = 0U;
228 break;
229 }
230
231 return freq;
232 }
233
234 /*!
235 * brief Set LPCG gate for specific LPCG.
236 *
237 * param regBase LPCG register base address.
238 * param swGate Software clock gating. 0: clock is gated; 1: clock is enabled
239 * param hwGate Hardware auto gating. 0: disable the HW clock gate control; 1: HW clock gating is enabled
240 * param bitsMask The available bits in LPCG register. Each bit indicate the corresponding bit is available or not.
241 */
CLOCK_SetLpcgGate(volatile uint32_t * regBase,bool swGate,bool hwGate,uint32_t bitsMask)242 void CLOCK_SetLpcgGate(volatile uint32_t *regBase, bool swGate, bool hwGate, uint32_t bitsMask)
243 {
244 if (regBase != NULL)
245 {
246 if (swGate)
247 {
248 *regBase |= bitsMask & LPCG_CLK_SWEN_MASK;
249 }
250 else
251 {
252 *regBase &= ~(bitsMask & LPCG_CLK_SWEN_MASK);
253 }
254
255 if (hwGate)
256 {
257 *regBase |= bitsMask & LPCG_CLK_HWEN_MASK;
258 }
259 else
260 {
261 *regBase &= ~(bitsMask & LPCG_CLK_HWEN_MASK);
262 }
263 }
264 }
265
266 /*!
267 * brief Config the LPCG cell for specific IP.
268 *
269 * param name Which clock to enable, see \ref clock_ip_name_t.
270 * param swGate Software clock gating. 0: clock is gated; 1: clock is enabled
271 * param swGate Hardware auto gating. 0: disable the HW clock gate control; 1: HW clock gating is enabled
272 */
CLOCK_ConfigLPCG(clock_ip_name_t name,bool swGate,bool hwGate)273 void CLOCK_ConfigLPCG(clock_ip_name_t name, bool swGate, bool hwGate)
274 {
275 CLOCK_ConfigLPCGMapped((uint32_t *)LPCG_TUPLE_REG_BASE(name), name, swGate, hwGate);
276 }
277
278 /*!
279 * brief Config the LPCG cell for specific IP (mapped version).
280 *
281 * param lpcgBase Virtual/physical base address of the LPCG region associated with IP.
282 * param name Which clock to enable, see \ref clock_ip_name_t.
283 * param swGate Software clock gating. 0: clock is gated; 1: clock is enabled
284 * param swGate Hardware auto gating. 0: disable the HW clock gate control; 1: HW clock gating is enabled
285 */
CLOCK_ConfigLPCGMapped(uint32_t * lpcgBase,clock_ip_name_t name,bool swGate,bool hwGate)286 void CLOCK_ConfigLPCGMapped(uint32_t *lpcgBase, clock_ip_name_t name, bool swGate, bool hwGate)
287 {
288 volatile uint32_t *regBase;
289
290 regBase = lpcgBase;
291
292 /* Return if LPCG Cell is not available. */
293 if (regBase == NULL)
294 {
295 return;
296 }
297
298 /* Config the LPCG. LPCG Cells have different configurations per each clock target. */
299 switch (name)
300 {
301 /* LPCG cell avalialbe bits field mask 0xBBAAAB, 0xBBAAAB (2 32-bits LPCG registers). */
302 case kCLOCK_CONNECTIVITY_Enet0:
303 case kCLOCK_CONNECTIVITY_Enet1:
304 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xBBAAABU);
305 CLOCK_SetLpcgGate(®Base[1U], swGate, hwGate, 0xAU);
306 break;
307
308 /* LPCG cell avalialbe bits field mask 0xA000B.*/
309 case kCLOCK_AUDIO_Esai0:
310 case kCLOCK_AUDIO_Esai1:
311 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xA000BU);
312 break;
313
314 /* LPCG cell avalialbe bits field mask 0xAA000B.*/
315 case kCLOCK_AUDIO_Gpt0:
316 case kCLOCK_AUDIO_Gpt1:
317 case kCLOCK_AUDIO_Gpt2:
318 case kCLOCK_AUDIO_Gpt3:
319 case kCLOCK_AUDIO_Gpt4:
320 case kCLOCK_AUDIO_Gpt5:
321 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xAA000BU);
322 break;
323
324 /* LPCG cell avalialbe bits field mask 0xAAB0AAB.*/
325 case kCLOCK_LSIO_Gpt0:
326 case kCLOCK_LSIO_Gpt1:
327 case kCLOCK_LSIO_Gpt2:
328 case kCLOCK_LSIO_Gpt3:
329 case kCLOCK_LSIO_Gpt4:
330 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xAAB0AABU);
331 break;
332
333 /* LPCG cell avalialbe bits field mask 0xB0000.*/
334 case kCLOCK_HSIO_Gpio:
335 case kCLOCK_LSIO_Gpio0:
336 case kCLOCK_LSIO_Gpio1:
337 case kCLOCK_LSIO_Gpio2:
338 case kCLOCK_LSIO_Gpio3:
339 case kCLOCK_LSIO_Gpio4:
340 case kCLOCK_LSIO_Gpio5:
341 case kCLOCK_LSIO_Gpio6:
342 case kCLOCK_LSIO_Gpio7:
343 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xB0000U);
344 break;
345 /* LPCG cell avalialbe bits field mask 0xB000A. */
346 case kCLOCK_DMA_Lpadc0:
347 case kCLOCK_DMA_Lpadc1:
348 case kCLOCK_LSIO_Mu5A:
349 case kCLOCK_LSIO_Mu6A:
350 case kCLOCK_LSIO_Mu7A:
351 case kCLOCK_LSIO_Mu8A:
352 case kCLOCK_LSIO_Mu9A:
353 case kCLOCK_LSIO_Mu10A:
354 case kCLOCK_LSIO_Mu11A:
355 case kCLOCK_LSIO_Mu12A:
356 case kCLOCK_LSIO_Mu13A:
357 case kCLOCK_LSIO_Mu5B:
358 case kCLOCK_LSIO_Mu6B:
359 case kCLOCK_LSIO_Mu7B:
360 case kCLOCK_LSIO_Mu8B:
361 case kCLOCK_LSIO_Mu9B:
362 case kCLOCK_LSIO_Mu10B:
363 case kCLOCK_LSIO_Mu11B:
364 case kCLOCK_LSIO_Mu12B:
365 case kCLOCK_LSIO_Mu13B:
366 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xB000AU);
367 break;
368
369 /* LPCG cell avalialbe bits field mask 0xB000B. */
370 case kCLOCK_DMA_Lpspi0:
371 case kCLOCK_DMA_Lpspi1:
372 case kCLOCK_DMA_Lpspi2:
373 case kCLOCK_DMA_Lpspi3:
374 case kCLOCK_DMA_Lpuart0:
375 case kCLOCK_DMA_Lpuart1:
376 case kCLOCK_DMA_Lpuart2:
377 case kCLOCK_DMA_Lpuart3:
378 case kCLOCK_DMA_Lpuart4:
379 case kCLOCK_DMA_Lpi2c0:
380 case kCLOCK_DMA_Lpi2c1:
381 case kCLOCK_DMA_Lpi2c2:
382 case kCLOCK_DMA_Lpi2c3:
383 case kCLOCK_DMA_Lpi2c4:
384 case kCLOCK_DMA_Ftm0:
385 case kCLOCK_DMA_Ftm1:
386 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xB000BU);
387 break;
388
389 /* LPCG cell avalialbe bits field mask 0xA0B0A.*/
390 case kCLOCK_AUDIO_Sai0:
391 case kCLOCK_AUDIO_Sai1:
392 case kCLOCK_AUDIO_Sai2:
393 case kCLOCK_AUDIO_Sai3:
394 case kCLOCK_AUDIO_Sai4:
395 case kCLOCK_AUDIO_Sai5:
396 case kCLOCK_AUDIO_Sai6:
397 case kCLOCK_AUDIO_Sai7:
398 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xA0B0AU);
399 break;
400
401 /* LPCG cell avalialbe bits field mask 0xBB000B.*/
402 case kCLOCK_DMA_Can0:
403 case kCLOCK_DMA_Can1:
404 case kCLOCK_DMA_Can2:
405 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xBB000B);
406 break;
407
408 /* LPCG cell avalialbe bits field mask 0xBAA000A.*/
409 case kCLOCK_LSIO_Flexspi0:
410 case kCLOCK_LSIO_Flexspi1:
411 CLOCK_SetLpcgGate(regBase, swGate, hwGate, 0xBAA000A);
412 break;
413
414 /* LPCG cell is not avaliable or is not supported by this function. */
415 default:
416 /* Add comments to avoid the violation of MISRA C-2012 rule 16.4. */
417 break;
418 }
419 }
420