1 /*
2 * Copyright (c) 2020 - 2024 Renesas Electronics Corporation and/or its affiliates
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 /***********************************************************************************************************************
8 * Includes
9 **********************************************************************************************************************/
10 #include "r_intc_irq.h"
11 #include "r_intc_irq_cfg.h"
12
13 /***********************************************************************************************************************
14 * Macro definitions
15 **********************************************************************************************************************/
16
17 /** "IRQ" in ASCII, used to determine if channel is open. */
18 #define INTC_IRQ_OPEN (0x0000495251U)
19
20 #define INTC_IRQ_TRIG_LEVEL_LOW (0U)
21 #define INTC_IRQ_TRIG_FALLING (1U)
22 #define INTC_IRQ_TRIG_RISING (2U)
23 #define INTC_IRQ_TRIG_BOTH_EDGE (3U)
24
25 #define INTC_IRQ_IITSR_IITSEL_MASK (3U)
26 #define INTC_IRQ_IITSR_IITSEL_WIDTH (2U)
27
28 #define INTC_IRQ_ISCR_ISTAT_MASK (1U)
29
30 /***********************************************************************************************************************
31 * Typedef definitions
32 **********************************************************************************************************************/
33
34 #if defined(__ARMCC_VERSION) || defined(__ICCARM__)
35 typedef void (BSP_CMSE_NONSECURE_CALL * intc_irq_prv_ns_callback)(external_irq_callback_args_t * p_args);
36 #elif defined(__GNUC__)
37 typedef BSP_CMSE_NONSECURE_CALL void (*volatile intc_irq_prv_ns_callback)(external_irq_callback_args_t * p_args);
38 #endif
39
40 /***********************************************************************************************************************
41 * Private function prototypes
42 **********************************************************************************************************************/
43 void r_intc_irq_isr(void);
44
45 /***********************************************************************************************************************
46 * Private global variables
47 **********************************************************************************************************************/
48
49 /***********************************************************************************************************************
50 * Global Variables
51 **********************************************************************************************************************/
52
53 /* INTC_IRQ implementation of External IRQ API. */
54 const external_irq_api_t g_external_irq_on_intc_irq =
55 {
56 .open = R_INTC_IRQ_ExternalIrqOpen,
57 .enable = R_INTC_IRQ_ExternalIrqEnable,
58 .disable = R_INTC_IRQ_ExternalIrqDisable,
59 .callbackSet = R_INTC_IRQ_ExternalIrqCallbackSet,
60 .close = R_INTC_IRQ_ExternalIrqClose,
61 };
62
63 /*******************************************************************************************************************//**
64 * @addtogroup INTC_IRQ
65 * @{
66 **********************************************************************************************************************/
67
68 /***********************************************************************************************************************
69 * Functions
70 **********************************************************************************************************************/
71
72 /*******************************************************************************************************************//**
73 * Configure an IRQ input pin for use with the external interrupt interface. Implements @ref external_irq_api_t::open.
74 *
75 * The Open function is responsible for preparing an external IRQ pin for operation.
76 *
77 * @retval FSP_SUCCESS Open successful.
78 * @retval FSP_ERR_ASSERTION One of the following is invalid:
79 * - p_ctrl or p_cfg is NULL
80 * @retval FSP_ERR_ALREADY_OPEN The channel specified has already been opened. No configurations were changed.
81 * Call the associated Close function to reconfigure the channel.
82 * @retval FSP_ERR_IP_CHANNEL_NOT_PRESENT The channel requested in p_cfg is not available on the device selected in
83 * r_bsp_cfg.h.
84 * @note This function is reentrant for different channels. It is not reentrant for the same channel.
85 **********************************************************************************************************************/
R_INTC_IRQ_ExternalIrqOpen(external_irq_ctrl_t * const p_api_ctrl,external_irq_cfg_t const * const p_cfg)86 fsp_err_t R_INTC_IRQ_ExternalIrqOpen (external_irq_ctrl_t * const p_api_ctrl, external_irq_cfg_t const * const p_cfg)
87 {
88 intc_irq_instance_ctrl_t * p_ctrl = (intc_irq_instance_ctrl_t *) p_api_ctrl;
89
90 #if INTC_IRQ_CFG_PARAM_CHECKING_ENABLE
91 FSP_ASSERT(NULL != p_ctrl);
92 FSP_ERROR_RETURN(INTC_IRQ_OPEN != p_ctrl->open, FSP_ERR_ALREADY_OPEN);
93 FSP_ASSERT(NULL != p_cfg);
94 FSP_ERROR_RETURN(0 != ((1U << p_cfg->channel) & BSP_FEATURE_INTC_IRQ_VALID_CHANNEL_MASK), FSP_ERR_IP_CHANNEL_NOT_PRESENT);
95 #endif
96
97 p_ctrl->irq = p_cfg->irq;
98
99 #if BSP_TZ_SECURE_BUILD
100
101 /* If this is a secure build, the callback provided in p_cfg must be secure. */
102 p_ctrl->p_callback_memory = NULL;
103 #endif
104
105 /* Initialize control block. */
106 p_ctrl->p_callback = p_cfg->p_callback;
107 p_ctrl->p_context = p_cfg->p_context;
108 p_ctrl->channel = p_cfg->channel;
109
110 uint32_t trigger = 0;
111 /* Convert the trigger. */
112 if (EXTERNAL_IRQ_TRIG_LEVEL_LOW == p_cfg->trigger)
113 {
114 trigger = INTC_IRQ_TRIG_LEVEL_LOW;
115 }
116 else if (EXTERNAL_IRQ_TRIG_FALLING == p_cfg->trigger)
117 {
118 trigger = INTC_IRQ_TRIG_FALLING;
119 }
120 else if (EXTERNAL_IRQ_TRIG_RISING == p_cfg->trigger)
121 {
122 trigger = INTC_IRQ_TRIG_RISING;
123 }
124 else if (EXTERNAL_IRQ_TRIG_BOTH_EDGE == p_cfg->trigger)
125 {
126 trigger = INTC_IRQ_TRIG_BOTH_EDGE;
127 }
128 else
129 {
130 /* Do nothing. */
131 }
132
133 /* Set the trigger. */
134 uint32_t iitsr = R_INTC_IM33->IITSR;
135 iitsr &= ~(INTC_IRQ_IITSR_IITSEL_MASK << (p_ctrl->channel * INTC_IRQ_IITSR_IITSEL_WIDTH));
136 iitsr |= (trigger << (p_ctrl->channel * INTC_IRQ_IITSR_IITSEL_WIDTH));
137 R_INTC_IM33->IITSR = iitsr;
138
139 if (INTC_IRQ_TRIG_LEVEL_LOW == trigger)
140 {
141 /* Do nothing. */
142 }
143 else
144 {
145 /* Dummy read the ISCR before clearing the ISTAT bit. */
146 volatile uint32_t iscr = R_INTC_IM33->ISCR;
147 FSP_PARAMETER_NOT_USED(iscr);
148
149 /* Clear the ISTAT bit after changing the trigger setting to the edge type.
150 * Reference section "Precaution when Changing Interrupt Settings" of the user's manual. */
151 R_INTC_IM33->ISCR = ~(INTC_IRQ_ISCR_ISTAT_MASK << p_ctrl->channel);
152
153 /* Dummy read the ISCR to prevent the interrupt cause that have been cleared from being accidentally accepted.
154 * Reference section "Clear Timing of Interrupt Cause" of the user's manual. */
155 iscr = R_INTC_IM33->ISCR;
156 FSP_PARAMETER_NOT_USED(iscr);
157 }
158
159 if (p_ctrl->irq >= 0)
160 {
161 R_BSP_IrqCfg(p_ctrl->irq, p_cfg->ipl, p_ctrl);
162 }
163
164 /* Mark the control block as open. */
165 p_ctrl->open = INTC_IRQ_OPEN;
166
167 return FSP_SUCCESS;
168 }
169
170 /*******************************************************************************************************************//**
171 * Enable external interrupt for specified channel at NVIC. Implements @ref external_irq_api_t::enable.
172 *
173 * @retval FSP_SUCCESS Interrupt Enabled successfully.
174 * @retval FSP_ERR_ASSERTION The p_ctrl parameter was null.
175 * @retval FSP_ERR_NOT_OPEN The channel is not opened.
176 * @retval FSP_ERR_IRQ_BSP_DISABLED Requested IRQ is not defined in this system.
177 **********************************************************************************************************************/
R_INTC_IRQ_ExternalIrqEnable(external_irq_ctrl_t * const p_api_ctrl)178 fsp_err_t R_INTC_IRQ_ExternalIrqEnable (external_irq_ctrl_t * const p_api_ctrl)
179 {
180 intc_irq_instance_ctrl_t * p_ctrl = (intc_irq_instance_ctrl_t *) p_api_ctrl;
181
182 #if INTC_IRQ_CFG_PARAM_CHECKING_ENABLE
183 FSP_ASSERT(NULL != p_ctrl);
184 FSP_ERROR_RETURN(INTC_IRQ_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
185 FSP_ERROR_RETURN(p_ctrl->irq >= 0, FSP_ERR_IRQ_BSP_DISABLED);
186 #endif
187
188 /* Clear the interrupt status and Pending bits, before the interrupt is enabled. */
189 R_BSP_IrqEnable(p_ctrl->irq);
190
191 return FSP_SUCCESS;
192 }
193
194 /*******************************************************************************************************************//**
195 * Disable external interrupt for specified channel at NVIC. Implements @ref external_irq_api_t::disable.
196 *
197 * @retval FSP_SUCCESS Interrupt disabled successfully.
198 * @retval FSP_ERR_ASSERTION The p_ctrl parameter was null.
199 * @retval FSP_ERR_NOT_OPEN The channel is not opened.
200 * @retval FSP_ERR_IRQ_BSP_DISABLED Requested IRQ is not defined in this system.
201 **********************************************************************************************************************/
R_INTC_IRQ_ExternalIrqDisable(external_irq_ctrl_t * const p_api_ctrl)202 fsp_err_t R_INTC_IRQ_ExternalIrqDisable (external_irq_ctrl_t * const p_api_ctrl)
203 {
204 intc_irq_instance_ctrl_t * p_ctrl = (intc_irq_instance_ctrl_t *) p_api_ctrl;
205
206 #if INTC_IRQ_CFG_PARAM_CHECKING_ENABLE
207 FSP_ASSERT(NULL != p_ctrl);
208 FSP_ERROR_RETURN(INTC_IRQ_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
209 FSP_ERROR_RETURN(p_ctrl->irq >= 0, FSP_ERR_IRQ_BSP_DISABLED);
210 #endif
211
212 /* Disable the interrupt, and then clear the interrupt pending bits and interrupt status. */
213 R_BSP_IrqDisable(p_ctrl->irq);
214
215 return FSP_SUCCESS;
216 }
217
218 /*******************************************************************************************************************//**
219 * Updates the user callback and has option of providing memory for callback structure.
220 * Implements external_irq_api_t::callbackSet.
221 *
222 * @retval FSP_SUCCESS Callback updated successfully.
223 * @retval FSP_ERR_ASSERTION A required pointer is NULL.
224 * @retval FSP_ERR_NOT_OPEN The control block has not been opened.
225 * @retval FSP_ERR_NO_CALLBACK_MEMORY p_callback is non-secure and p_callback_memory is either secure or NULL.
226 **********************************************************************************************************************/
R_INTC_IRQ_ExternalIrqCallbackSet(external_irq_ctrl_t * const p_api_ctrl,void (* p_callback)(external_irq_callback_args_t *),void const * const p_context,external_irq_callback_args_t * const p_callback_memory)227 fsp_err_t R_INTC_IRQ_ExternalIrqCallbackSet (external_irq_ctrl_t * const p_api_ctrl,
228 void ( * p_callback)(
229 external_irq_callback_args_t *),
230 void const * const p_context,
231 external_irq_callback_args_t * const p_callback_memory)
232 {
233 intc_irq_instance_ctrl_t * p_ctrl = p_api_ctrl;
234
235 #if BSP_TZ_SECURE_BUILD
236
237 /* cmse_check_address_range returns NULL if p_callback is located in secure memory. */
238 bool callback_is_secure =
239 (NULL == cmse_check_address_range((void *) p_callback, sizeof(void *), CMSE_AU_NONSECURE));
240 #else
241 FSP_PARAMETER_NOT_USED(p_callback_memory);
242 #endif
243
244 #if INTC_IRQ_CFG_PARAM_CHECKING_ENABLE
245 FSP_ASSERT(NULL != p_ctrl);
246 FSP_ERROR_RETURN(INTC_IRQ_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
247 FSP_ASSERT(NULL != p_callback);
248
249 #if BSP_TZ_SECURE_BUILD
250
251 /* In secure projects, p_callback_memory must be provided in non-secure space if p_callback is non-secure. */
252 external_irq_callback_args_t * const p_callback_memory_checked = cmse_check_pointed_object(p_callback_memory,
253 CMSE_AU_NONSECURE);
254 FSP_ERROR_RETURN(callback_is_secure || (NULL != p_callback_memory_checked), FSP_ERR_NO_CALLBACK_MEMORY);
255 #endif
256 #endif
257
258 #if BSP_TZ_SECURE_BUILD
259 p_ctrl->p_callback_memory = p_callback_memory;
260 p_ctrl->p_callback = callback_is_secure ? p_callback :
261 (void (*)(external_irq_callback_args_t *))cmse_nsfptr_create(p_callback);
262 #else
263 p_ctrl->p_callback = p_callback;
264 #endif
265 p_ctrl->p_context = p_context;
266
267 return FSP_SUCCESS;
268 }
269
270 /*******************************************************************************************************************//**
271 * Close the external interrupt channel. Implements @ref external_irq_api_t::close.
272 *
273 * @retval FSP_SUCCESS Successfully closed.
274 * @retval FSP_ERR_ASSERTION The parameter p_ctrl is NULL.
275 * @retval FSP_ERR_NOT_OPEN The channel is not opened.
276 **********************************************************************************************************************/
R_INTC_IRQ_ExternalIrqClose(external_irq_ctrl_t * const p_api_ctrl)277 fsp_err_t R_INTC_IRQ_ExternalIrqClose (external_irq_ctrl_t * const p_api_ctrl)
278 {
279 intc_irq_instance_ctrl_t * p_ctrl = (intc_irq_instance_ctrl_t *) p_api_ctrl;
280
281 #if INTC_IRQ_CFG_PARAM_CHECKING_ENABLE
282 FSP_ASSERT(NULL != p_ctrl);
283 FSP_ERROR_RETURN(INTC_IRQ_OPEN == p_ctrl->open, FSP_ERR_NOT_OPEN);
284 #endif
285
286 /* Cleanup. Disable interrupt. */
287 if (p_ctrl->irq >= 0)
288 {
289 /* Disable the interrupt, and then clear the interrupt pending bits and interrupt status. */
290 R_BSP_IrqDisable(p_ctrl->irq);
291 R_FSP_IsrContextSet(p_ctrl->irq, NULL);
292 }
293
294 p_ctrl->open = 0U;
295
296 return FSP_SUCCESS;
297 }
298
299 /*******************************************************************************************************************//**
300 * @} (end addtogroup INTC_IRQ)
301 **********************************************************************************************************************/
302
303 /*******************************************************************************************************************//**
304 * INTC_IRQ External Interrupt ISR.
305 **********************************************************************************************************************/
r_intc_irq_isr(void)306 void r_intc_irq_isr (void)
307 {
308 /* Save context if RTOS is used. */
309 FSP_CONTEXT_SAVE
310
311 IRQn_Type irq = R_FSP_CurrentIrqGet();
312 intc_irq_instance_ctrl_t * p_ctrl = (intc_irq_instance_ctrl_t *) R_FSP_IsrContextGet(irq);
313
314 /* Retrieve the trigger setting. */
315 uint32_t iitsr = R_INTC_IM33->IITSR;
316 iitsr &= (INTC_IRQ_IITSR_IITSEL_MASK << (p_ctrl->channel * INTC_IRQ_IITSR_IITSEL_WIDTH));
317 iitsr >>= (p_ctrl->channel * INTC_IRQ_IITSR_IITSEL_WIDTH);
318
319 if (INTC_IRQ_TRIG_LEVEL_LOW == iitsr)
320 {
321 /* Do nothing. */
322 }
323 else
324 {
325 /* Dummy read the ISCR before clearing the ISTAT bit. */
326 volatile uint32_t iscr = R_INTC_IM33->ISCR;
327 FSP_PARAMETER_NOT_USED(iscr);
328
329 /* Clear the ISTAT bit before calling the user callback so that if an edge is detected while the ISR is active
330 * it will not be missed. */
331 R_INTC_IM33->ISCR = ~(INTC_IRQ_ISCR_ISTAT_MASK << p_ctrl->channel);
332
333 /* Dummy read the ISCR to prevent the interrupt cause that should have been cleared from being accidentally
334 * accepted again. Reference section "Clear Timing of Interrupt Cause" of the user's manual. */
335 iscr = R_INTC_IM33->ISCR;
336 FSP_PARAMETER_NOT_USED(iscr);
337 }
338
339 if ((NULL != p_ctrl) && (NULL != p_ctrl->p_callback))
340 {
341 #if BSP_TZ_SECURE_BUILD
342
343 /* p_callback can point to a secure function or a non-secure function. */
344 external_irq_callback_args_t args;
345 if (!cmse_is_nsfptr(p_ctrl->p_callback))
346 {
347 /* If p_callback is secure, then the project does not need to change security state. */
348 args.channel = p_ctrl->channel;
349 args.p_context = p_ctrl->p_context;
350 p_ctrl->p_callback(&args);
351 }
352 else
353 {
354 /* Save current state of p_callback_args so that it can be shared between interrupts. */
355 args = *p_ctrl->p_callback_memory;
356
357 /* Set the callback args passed to the Non-secure callback. */
358 p_ctrl->p_callback_memory->channel = p_ctrl->channel;
359 p_ctrl->p_callback_memory->p_context = p_ctrl->p_context;
360
361 /* If p_callback is Non-secure, then the project must change to Non-secure state in order to call the callback. */
362 intc_irq_prv_ns_callback p_callback = (intc_irq_prv_ns_callback) (p_ctrl->p_callback);
363 p_callback(p_ctrl->p_callback_memory);
364
365 /* Restore the state of p_callback_args. */
366 *p_ctrl->p_callback_memory = args;
367 }
368
369 #else
370
371 /* Set data to identify callback to user, then call user callback. */
372 external_irq_callback_args_t args;
373 args.channel = p_ctrl->channel;
374 args.p_context = p_ctrl->p_context;
375 p_ctrl->p_callback(&args);
376 #endif
377 }
378
379 /* Restore context if RTOS is used. */
380 FSP_CONTEXT_RESTORE
381 }
382