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