1 /***************************************************************************//**
2 * \file cyhal_irq_impl.h
3 *
4 * \brief
5 * Provides internal utility functions for working with interrupts on CAT1/CAT2.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2022 Cypress Semiconductor Corporation (an Infineon company) or
10 * an affiliate of Cypress Semiconductor Corporation
11 *
12 * SPDX-License-Identifier: Apache-2.0
13 *
14 * Licensed under the Apache License, Version 2.0 (the "License");
15 * you may not use this file except in compliance with the License.
16 * You may obtain a copy of the License at
17 *
18 * http://www.apache.org/licenses/LICENSE-2.0
19 *
20 * Unless required by applicable law or agreed to in writing, software
21 * distributed under the License is distributed on an "AS IS" BASIS,
22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 * See the License for the specific language governing permissions and
24 * limitations under the License.
25 *******************************************************************************/
26
27 #pragma once
28 #include "cyhal_utils.h"
29 #include "cy_result.h"
30 #include "cy_sysint.h"
31
32 /* System IRQ refers to signals that peripherals produce to request and interrupt,
33 * which may or may not correspond 1:1 to the CPU IRQ lines */
34 #if defined(COMPONENT_CAT1)
35 #define _CYHAL_IRQ_MUXING (CY_CPU_CORTEX_M0P || CPUSS_SYSTEM_IRQ_PRESENT)
36 #else
37 #define _CYHAL_IRQ_MUXING (0)
38 #endif
39 /* Old-style IRQ muxing where each CPU interrupt can be driven by exactly one System interrupt.
40 * This is a subset of _CYHAL_IRQ_MUXING. */
41 #define _CYHAL_IRQ_LEGACY_M0 (CY_CPU_CORTEX_M0P && (1u == CY_IP_M4CPUSS_VERSION))
42
43 #if !(_CYHAL_IRQ_LEGACY_M0)
44 /* Interrupt priority is set per CPU interrupt, but application-defined priorities are set
45 * in terms of system interrupts. So keep track of the IRQ per system interrupt and
46 * set the CPU interrupt priority to the lowest (i.e. most important) value of any
47 * system interrupt that is connected to it */
48 #if (CY_CPU_CORTEX_M0P)
49 #define _CYHAL_IRQ_PRIO_BITS (3u)
50 #elif defined(CY_IP_M4CPUSS)
51 #define _CYHAL_IRQ_PRIO_BITS (CPUSS_CM4_LVL_WIDTH)
52 #else /* M7CPUSS */
53 #define _CYHAL_IRQ_PRIO_BITS (CPUSS_CM7_LVL_WIDTH)
54 #endif
55
56 #if defined(CY_IP_M4CPUSS)
57 #define _CYHAL_IRQ_COUNT (CPUSS_IRQ_NR)
58 #else /* M7CPUSS */
59 #define _CYHAL_IRQ_COUNT (CPUSS_SYSTEM_INT_NR)
60 #endif
61
62 #endif // !(_CYHAL_IRQ_LEGACY_M0)
63
64 #if (_CYHAL_IRQ_MUXING)
65 typedef cy_en_intr_t _cyhal_system_irq_t;
66 #else
67 typedef IRQn_Type _cyhal_system_irq_t;
68 #endif
69
70 #if _CYHAL_IRQ_LEGACY_M0
71 IRQn_Type _cyhal_irq_find_cm0(cy_en_intr_t system_intr);
72 #elif _CYHAL_IRQ_MUXING
73 uint8_t _cyhal_system_irq_lookup_priority(cy_en_intr_t system_irq);
74 void _cyhal_system_irq_store_priority(cy_en_intr_t system_irq, uint8_t priority);
75 uint8_t _cyhal_system_irq_lowest_priority(IRQn_Type cpu_irq);
76 #endif
77
78 void _cyhal_system_irq_clear_disabled_in_pending(void);
79 cy_rslt_t _cyhal_irq_register(_cyhal_system_irq_t system_intr, uint8_t intr_priority, cy_israddress irq_handler);
80
81 // TODO: Remove this once DRIVERS-7707 is fixed
82 #if defined(CY_IP_M4CPUSS) && (CY_CPU_CORTEX_M0P) && !(_CYHAL_IRQ_LEGACY_M0)
Cy_SysInt_EnableSystemInt(cy_en_intr_t sysIntSrc)83 static void Cy_SysInt_EnableSystemInt(cy_en_intr_t sysIntSrc)
84 {
85 #if defined(CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk)
86 CPUSS_CM0_SYSTEM_INT_CTL[sysIntSrc] |= CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk;
87 #else
88 CPUSS_CM0_SYSTEM_INT_CTL[sysIntSrc] |= CPUSS_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk;
89 #endif
90 }
91
Cy_SysInt_DisableSystemInt(cy_en_intr_t sysIntSrc)92 static void Cy_SysInt_DisableSystemInt(cy_en_intr_t sysIntSrc)
93 {
94 #if defined(CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk)
95 CPUSS->CM0_SYSTEM_INT_CTL[sysIntSrc] &= (uint32_t) ~CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk;
96 #else
97 CPUSS->CM0_SYSTEM_INT_CTL[sysIntSrc] &= (uint32_t) ~CPUSS_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk;
98 #endif
99 }
100 #endif
101
_cyhal_irq_set_priority(_cyhal_system_irq_t system_irq,uint8_t intr_priority)102 static inline void _cyhal_irq_set_priority(_cyhal_system_irq_t system_irq, uint8_t intr_priority)
103 {
104 #if _CYHAL_IRQ_MUXING
105 #if _CYHAL_IRQ_LEGACY_M0
106 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
107 uint8_t priority_to_set = intr_priority;
108 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
109 IRQn_Type irqn = Cy_SysInt_GetNvicConnection(system_irq);
110 _cyhal_system_irq_store_priority(system_irq, intr_priority);
111 uint8_t priority_to_set = _cyhal_system_irq_lowest_priority(irqn);
112 #endif
113 #else
114 IRQn_Type irqn = system_irq;
115 uint8_t priority_to_set = intr_priority;
116 #endif
117 NVIC_SetPriority(irqn, priority_to_set);
118 }
119
_cyhal_irq_get_priority(_cyhal_system_irq_t system_irq)120 static inline uint8_t _cyhal_irq_get_priority(_cyhal_system_irq_t system_irq)
121 {
122 #if _CYHAL_IRQ_MUXING
123 #if _CYHAL_IRQ_LEGACY_M0
124 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
125 return NVIC_GetPriority(irqn);
126 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
127 return _cyhal_system_irq_lookup_priority(system_irq);
128 #endif
129 #else
130 return NVIC_GetPriority(system_irq);
131 #endif
132 }
133
_cyhal_irq_clear_pending(_cyhal_system_irq_t system_irq)134 static inline void _cyhal_irq_clear_pending(_cyhal_system_irq_t system_irq)
135 {
136 #if _CYHAL_IRQ_MUXING
137 #if _CYHAL_IRQ_LEGACY_M0
138 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
139 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
140 IRQn_Type irqn = Cy_SysInt_GetNvicConnection(system_irq);
141 #endif
142 #else
143 IRQn_Type irqn = system_irq;
144 #endif
145 NVIC_ClearPendingIRQ(irqn);
146 }
147
_cyhal_irq_enable(_cyhal_system_irq_t system_irq)148 static inline void _cyhal_irq_enable(_cyhal_system_irq_t system_irq)
149 {
150 #if _CYHAL_IRQ_MUXING
151 #if _CYHAL_IRQ_LEGACY_M0
152 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
153 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
154 Cy_SysInt_EnableSystemInt(system_irq);
155 IRQn_Type irqn = Cy_SysInt_GetNvicConnection(system_irq);
156 #endif
157 #else
158 IRQn_Type irqn = system_irq;
159 #endif
160 NVIC_EnableIRQ(irqn);
161 }
162
_cyhal_irq_disable(_cyhal_system_irq_t system_irq)163 static inline void _cyhal_irq_disable(_cyhal_system_irq_t system_irq)
164 {
165 #if _CYHAL_IRQ_MUXING
166 #if _CYHAL_IRQ_LEGACY_M0
167 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
168 NVIC_DisableIRQ(irqn);
169 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
170 Cy_SysInt_DisableSystemInt(system_irq);
171 /* Don't call NVIC_DisableIRQ because there could be other system interrupts still using this IRQn */
172 #endif
173 #else
174 NVIC_DisableIRQ(system_irq);
175 #endif
176 }
177
178 #if (_CYHAL_IRQ_MUXING) && defined (COMPONENT_CAT1A) && (!_CYHAL_IRQ_LEGACY_M0)
179 extern uint8_t _cpu_irq_tracker; // TODO: This is a temporary workaround to assign 1:1 CPU to system mapping.
180 #endif
181
_cyhal_irq_free(_cyhal_system_irq_t system_irq)182 static inline void _cyhal_irq_free(_cyhal_system_irq_t system_irq)
183 {
184 #if _CYHAL_IRQ_LEGACY_M0
185 /* Need to turn the IRQ off and also clear out the NVIC slot so that we
186 * know it's available for other drivers to use */
187 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
188 NVIC_DisableIRQ(irqn); /* Don't reuse irq_disable because it would have to repeat the find_cm0 */
189 Cy_SysInt_DisconnectInterruptSource(irqn, system_irq /* ignored for CPUSSv1 */);
190 #elif _CYHAL_IRQ_MUXING /* New style IRQ muxing */
191 /* DisconnectInterruptSource on M4CPUSS and DisableSystemInt on M7CPUSS are functionally equivalent */
192 IRQn_Type irqn = Cy_SysInt_GetNvicConnection(system_irq);
193 // TODO: This is a temporary workaround to assign 1:1 CPU to system mapping.
194 #if defined (COMPONENT_CAT1A)
195 _cpu_irq_tracker &= ~(1 << irqn);
196 #endif
197 #if defined(CY_IP_M4CPUSS)
198 Cy_SysInt_DisconnectInterruptSource(irqn, system_irq);
199 #elif defined(CY_IP_M7CPUSS)
200 Cy_SysInt_DisableSystemInt(system_irq);
201 #endif
202
203 /* Must happen after the interrupt source is disabled because we use GetNvicConnection to determine
204 * what system interrupts are actively associated with a given CPU interrupt */
205 uint8_t lowest_priority = _cyhal_system_irq_lowest_priority(irqn);
206 NVIC_SetPriority(irqn, lowest_priority);
207 #endif
208
209 _cyhal_irq_disable(system_irq);
210 }
211
_cyhal_irq_is_enabled(_cyhal_system_irq_t system_irq)212 static inline bool _cyhal_irq_is_enabled(_cyhal_system_irq_t system_irq)
213 {
214 #if _CYHAL_IRQ_MUXING
215 #if _CYHAL_IRQ_LEGACY_M0
216 IRQn_Type irqn = _cyhal_irq_find_cm0(system_irq);
217 return (unconnected_IRQn != irqn) && NVIC_GetEnableIRQ(irqn);
218 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
219 /* Based on Cy_SysInt_EnableSystemInt */
220 if (CY_CPU_CORTEX_M0P)
221 {
222 #if defined(CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk)
223 return (0u != (CPUSS_CM0_SYSTEM_INT_CTL[system_irq] & CPUSS_V2_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk));
224 #else
225 return (0u != (CPUSS_CM0_SYSTEM_INT_CTL[system_irq] & CPUSS_CM0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk));
226 #endif
227 }
228 #if defined(CY_IP_M7CPUSS)
229 else if (CY_IS_CM7_CORE_0)
230 {
231 return (0u != (CPUSS_CM7_0_SYSTEM_INT_CTL[system_irq] & CPUSS_CM7_0_SYSTEM_INT_CTL_CPU_INT_VALID_Msk));
232 }
233 else if (CY_IS_CM7_CORE_1)
234 {
235 return (0u != (CPUSS_CM7_1_SYSTEM_INT_CTL[system_irq] & CPUSS_CM7_1_SYSTEM_INT_CTL_CPU_INT_VALID_Msk));
236 }
237 #endif
238 else
239 {
240 CY_ASSERT(false); /* Unsupported CPU */
241 return false;
242 }
243 #endif
244 #else
245 return NVIC_GetEnableIRQ(system_irq);
246 #endif
247 }
248
_cyhal_irq_get_active(void)249 static inline _cyhal_system_irq_t _cyhal_irq_get_active(void)
250 {
251 IRQn_Type irqn = _CYHAL_UTILS_GET_CURRENT_IRQN();
252 #if _CYHAL_IRQ_MUXING
253 #if _CYHAL_IRQ_LEGACY_M0
254 /* No pre-built functionality for this. Need to see what CPU interrupt is active, then
255 * indirect through the NVIC mux to figure out what system IRQ it is mapped to. */
256 return Cy_SysInt_GetInterruptSource(irqn);
257 #else /* CM0+ on CPUSSv2, or CM4/CM7 on CPUSSv2 with SYSTEM_IRQ_PRESENT */
258 return Cy_SysInt_GetInterruptActive(irqn);
259 #endif
260 #else
261 return irqn;
262 #endif
263 }
264