1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017, 2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_irqsteer.h"
10 
11 /*******************************************************************************
12  * Definitions
13  ******************************************************************************/
14 
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.irqsteer"
18 #endif
19 
20 /*******************************************************************************
21  * Prototypes
22  ******************************************************************************/
23 
24 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
25 /*!
26  * @brief Get instance number for IRQSTEER.
27  *
28  * @param base IRQSTEER peripheral base address.
29  */
30 static uint32_t IRQSTEER_GetInstance(IRQSTEER_Type *base);
31 #endif
32 
33 /*******************************************************************************
34  * Variables
35  ******************************************************************************/
36 
37 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
38 /*! @brief Array to map IRQSTEER instance number to base pointer. */
39 static IRQSTEER_Type *const s_irqsteerBases[] = IRQSTEER_BASE_PTRS;
40 
41 /*! @brief Array to map IRQSTEER instance number to clock name. */
42 static const clock_ip_name_t s_irqsteerClockName[] = IRQSTEER_CLOCKS;
43 #endif
44 
45 #if FSL_IRQSTEER_ENABLE_MASTER_INT
46 /*! @brief Array to map IRQSTEER instance number to IRQ number. */
47 static const IRQn_Type s_irqsteerIRQNumber[] = IRQSTEER_IRQS;
48 #endif
49 
50 /*******************************************************************************
51  * Code
52  ******************************************************************************/
53 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
IRQSTEER_GetInstance(IRQSTEER_Type * base)54 static uint32_t IRQSTEER_GetInstance(IRQSTEER_Type *base)
55 {
56     uint32_t instance;
57 
58     /* Find the instance index from base address mappings. */
59     for (instance = 0; instance < ARRAY_SIZE(s_irqsteerBases); instance++)
60     {
61         if (s_irqsteerBases[instance] == base)
62         {
63             break;
64         }
65     }
66 
67     assert(instance < ARRAY_SIZE(s_irqsteerBases));
68 
69     return instance;
70 }
71 #endif
72 
73 /*!
74  * brief Initializes the IRQSTEER module.
75  *
76  * This function enables the clock gate for the specified IRQSTEER.
77  *
78  * param base IRQSTEER peripheral base address.
79  */
IRQSTEER_Init(IRQSTEER_Type * base)80 void IRQSTEER_Init(IRQSTEER_Type *base)
81 {
82     uint32_t i;
83 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
84     /* Enable clock. */
85     (void)CLOCK_EnableClock(s_irqsteerClockName[IRQSTEER_GetInstance(base)]);
86 #endif
87     /* Mask all interrupts. */
88     for (i = 0; i < (uint32_t)FSL_FEATURE_IRQSTEER_CHn_MASK_COUNT; i++)
89     {
90         base->CHn_MASK[i] &= ~IRQSTEER_CHn_MASK_MASKFLD_MASK;
91     }
92 
93 #if FSL_IRQSTEER_ENABLE_MASTER_INT
94     /* Enable NVIC vectors for all IRQSTEER master. */
95     for (i = 0; i < (uint32_t)FSL_FEATURE_IRQSTEER_MASTER_COUNT; i++)
96     {
97         (void)EnableIRQ(s_irqsteerIRQNumber[i]);
98     }
99 #endif
100 }
101 
102 /*!
103  * brief Deinitializes an IRQSTEER instance for operation.
104  *
105  * The clock gate for the specified IRQSTEER is disabled.
106  *
107  * param base IRQSTEER peripheral base address.
108  */
IRQSTEER_Deinit(IRQSTEER_Type * base)109 void IRQSTEER_Deinit(IRQSTEER_Type *base)
110 {
111 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
112     /* Disable clock. */
113     (void)CLOCK_DisableClock(s_irqsteerClockName[IRQSTEER_GetInstance(base)]);
114 #endif
115 
116 #if FSL_IRQSTEER_ENABLE_MASTER_INT
117     uint32_t master;
118 
119     /* Disable NVIC vectors for all IRQSTEER master. */
120     for (master = 0; master < (uint32_t)FSL_FEATURE_IRQSTEER_MASTER_COUNT; master++)
121     {
122         (void)DisableIRQ(s_irqsteerIRQNumber[master]);
123     }
124 #endif
125 }
126 
127 /*
128  * brief Get the number of interrupt for a given master.
129  *
130  * param base IRQSTEER peripheral base address.
131  * param intMasterIndex Master index of interrupt sources, options available in
132  * enumeration ::irqsteer_int_master_t.
133  * return Number of interrupts for a given master.
134  */
IRQSTEER_GetMasterIrqCount(IRQSTEER_Type * base,irqsteer_int_master_t intMasterIndex)135 uint32_t IRQSTEER_GetMasterIrqCount(IRQSTEER_Type *base, irqsteer_int_master_t intMasterIndex)
136 {
137     uint32_t count;
138 
139     /*
140      * With IRQSTEER, each interrupt group has 32 interrupt sources. How many
141      * interrupt groups are connected to one interrupt master, it relates to
142      * the SOC integration.
143      *
144      * There are two cases based on SOC integration:
145      *
146      * 1. The interrupt group count (number of CHn_MASKx registers) is even number.
147      *    In this case, every two interrupt groups are connected to one interrupt master.
148      *    So each master has 64 interrupt sources connected.
149      * 2. The interrupt group count (number of CHn_MASKx registers) is odd number.
150      *    In this case, master 0 is connected to one interrupt group, while other masters
151      *    are all connected to two interrupt groups.
152      *    So each master 0 has 32 interrupt sources connected, and for other masters,
153      *    every master has 64 interrupt sources connected.
154      */
155     if ((FSL_FEATURE_IRQSTEER_CHn_MASK_COUNT % 2U) == 0U)
156     {
157         count = IRQSTEER_INT_MASTER_AGGREGATED_INT_NUM;
158     }
159     else
160     {
161         if (intMasterIndex == 0U)
162         {
163             count = IRQSTEER_INT_SRC_REG_WIDTH;
164         }
165         else
166         {
167             count = IRQSTEER_INT_MASTER_AGGREGATED_INT_NUM;
168         }
169     }
170 
171     return count;
172 }
173 
IRQSTEER_GetRegIndex(irqsteer_int_master_t intMasterIndex,uint32_t slice,uint32_t sliceNum)174 static uint32_t IRQSTEER_GetRegIndex(irqsteer_int_master_t intMasterIndex,
175 				     uint32_t slice, uint32_t sliceNum)
176 {
177     uint32_t base = FSL_FEATURE_IRQSTEER_CHn_MASK_COUNT - 1 - intMasterIndex * 2;
178 
179     if (FSL_FEATURE_IRQSTEER_CHn_MASK_COUNT % 2) {
180         base += sliceNum - 1;
181     }
182 
183     return base - slice;
184 }
185 
186 /*!
187  * brief Gets the next interrupt source (currently set) of one specific master.
188  *
189  * param base IRQSTEER peripheral base address.
190  * param intMasterIndex Master index of interrupt sources. ref "irqsteer_int_master_t".
191  * return The current set next interrupt source number of one specific master.
192  *         Return IRQSTEER_INT_Invalid if no interrupt set.
193  */
194 #if defined(__CORTEX_M)
IRQSTEER_GetMasterNextInterrupt(IRQSTEER_Type * base,irqsteer_int_master_t intMasterIndex)195 IRQn_Type IRQSTEER_GetMasterNextInterrupt(IRQSTEER_Type *base, irqsteer_int_master_t intMasterIndex)
196 {
197     uint32_t regIndex = (uint32_t)FSL_FEATURE_IRQSTEER_CHn_MASK_COUNT - 1U - ((uint32_t)intMasterIndex) * 2U;
198     uint32_t bitOffset;
199     uint32_t irqNum;
200 
201     bitOffset = __CLZ(__RBIT(base->CHn_STATUS[regIndex]));
202     /* When no result found, continue the loop to parse the next CHn_STATUS register. */
203     if (IRQSTEER_INT_SRC_REG_WIDTH == bitOffset)
204     {
205         regIndex--;
206         bitOffset = __CLZ(__RBIT(base->CHn_STATUS[regIndex]));
207     }
208 
209     if (IRQSTEER_INT_SRC_REG_WIDTH == bitOffset)
210     {
211         return NotAvail_IRQn;
212     }
213     else
214     {
215         irqNum = (uint32_t)IRQSTEER_INT_SRC_NUM(regIndex, bitOffset) + (uint32_t)FSL_FEATURE_IRQSTEER_IRQ_START_INDEX;
216         return (IRQn_Type)irqNum;
217     }
218 }
219 #else  /* **not** __CORTEX_M */
IRQSTEER_GetMasterNextInterrupt(IRQSTEER_Type * base,irqsteer_int_master_t intMasterIndex)220 IRQn_Type IRQSTEER_GetMasterNextInterrupt(IRQSTEER_Type *base, irqsteer_int_master_t intMasterIndex)
221 {
222     uint32_t bitOffset, regIndex, chanStatus, sliceNum;
223     int i, j;
224 
225     sliceNum = IRQSTEER_GetMasterIrqCount(base, intMasterIndex) / 32 - 1;
226 
227     for (i = 0; i <= sliceNum; i++)
228     {
229         bitOffset = 0;
230 
231         /* compute the index of the register to be queried */
232         regIndex = IRQSTEER_GetRegIndex(intMasterIndex, i, sliceNum + 1);
233 
234         /* get register's value */
235         chanStatus = base->CHn_STATUS[regIndex];
236 
237         for (j = 0; j < IRQSTEER_INT_SRC_REG_WIDTH; j++)
238         {
239             if ((chanStatus & 1U) != 0U)
240             {
241                 return (IRQn_Type)(uint32_t)IRQSTEER_INT_SRC_NUM(regIndex, bitOffset);
242             }
243 
244             bitOffset++;
245             chanStatus = chanStatus >> 1U;
246         }
247     }
248 
249     return NotAvail_IRQn;
250 }
251 #endif /* __CORTEX_M */
252 
IRQSTEER_GetMasterInterruptsStatus(IRQSTEER_Type * base,irqsteer_int_master_t intMasterIndex)253 uint64_t IRQSTEER_GetMasterInterruptsStatus(IRQSTEER_Type *base, irqsteer_int_master_t intMasterIndex)
254 {
255     uint32_t sliceNum, i, regIndex, chanStatus;
256     uint64_t interrupts;
257 
258     interrupts = 0;
259     sliceNum = IRQSTEER_GetMasterIrqCount(base, intMasterIndex) / 32 - 1;
260 
261     for (i = 0; i <= sliceNum; i++) {
262         regIndex = IRQSTEER_GetRegIndex(intMasterIndex, i, sliceNum + 1);
263 
264         chanStatus = base->CHn_STATUS[regIndex];
265 
266         interrupts |= ((uint64_t)chanStatus << (32 * i));
267     }
268 
269     return interrupts;
270 }
271 
272 #if FSL_IRQSTEER_USE_DRIVER_IRQ_HANDLER
IRQSTEER_CommonIRQHandler(IRQSTEER_Type * base,irqsteer_int_master_t intMasterIndex)273 static void IRQSTEER_CommonIRQHandler(IRQSTEER_Type *base, irqsteer_int_master_t intMasterIndex)
274 {
275     IRQn_Type intSource;
276     uint32_t isr;
277 
278     intSource = IRQSTEER_GetMasterNextInterrupt(base, intMasterIndex);
279     if (NotAvail_IRQn != intSource)
280     {
281         isr = *(uint32_t *)(SCB->VTOR + (((uint32_t)intSource + 16UL) << 2U));
282 
283         ((void (*)(void))isr)();
284     }
285 #if defined(FSL_FEATURE_EDMA_IRQSTEER_INTERRUPT_PATCH)
286     /*This is used for ESAI Interrupt IRQSTEER triggering*/
287     else
288     {
289         if ((intMasterIndex == 6) && ((base->CHn_MASK[2]) & 0x10))
290         {
291             isr = *(uint32_t *)(SCB->VTOR + (((uint32_t)ADMA_ESAI0_INT_IRQn + 16UL) << 2U));
292             ((void (*)(void))isr)();
293         }
294     }
295 #endif
296     SDK_ISR_EXIT_BARRIER;
297 }
298 
299 #if defined(IRQSTEER)
300 void IRQSTEER_0_DriverIRQHandler(void);
IRQSTEER_0_DriverIRQHandler(void)301 void IRQSTEER_0_DriverIRQHandler(void)
302 {
303     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster0);
304 }
305 
306 void IRQSTEER_1_DriverIRQHandler(void);
IRQSTEER_1_DriverIRQHandler(void)307 void IRQSTEER_1_DriverIRQHandler(void)
308 {
309     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster1);
310 }
311 
312 void IRQSTEER_2_DriverIRQHandler(void);
IRQSTEER_2_DriverIRQHandler(void)313 void IRQSTEER_2_DriverIRQHandler(void)
314 {
315     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster2);
316 }
317 
318 void IRQSTEER_3_DriverIRQHandler(void);
IRQSTEER_3_DriverIRQHandler(void)319 void IRQSTEER_3_DriverIRQHandler(void)
320 {
321     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster3);
322 }
323 
324 void IRQSTEER_4_DriverIRQHandler(void);
IRQSTEER_4_DriverIRQHandler(void)325 void IRQSTEER_4_DriverIRQHandler(void)
326 {
327     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster4);
328 }
329 
330 void IRQSTEER_5_DriverIRQHandler(void);
IRQSTEER_5_DriverIRQHandler(void)331 void IRQSTEER_5_DriverIRQHandler(void)
332 {
333     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster5);
334 }
335 
336 void IRQSTEER_6_DriverIRQHandler(void);
IRQSTEER_6_DriverIRQHandler(void)337 void IRQSTEER_6_DriverIRQHandler(void)
338 {
339     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster6);
340 }
341 
342 void IRQSTEER_7_DriverIRQHandler(void);
IRQSTEER_7_DriverIRQHandler(void)343 void IRQSTEER_7_DriverIRQHandler(void)
344 {
345     IRQSTEER_CommonIRQHandler(IRQSTEER, kIRQSTEER_InterruptMaster7);
346 }
347 #endif /* defined(IRQSTEER) */
348 #endif /* FSL_IRQSTEER_USE_DRIVER_IRQ_HANDLER */
349