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(&regBase[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