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