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