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