summaryrefslogtreecommitdiff
path: root/Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c
diff options
context:
space:
mode:
Diffstat (limited to 'Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c')
-rw-r--r--Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c b/Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c
new file mode 100644
index 0000000..cf08a53
--- /dev/null
+++ b/Drivers/CMSIS/Core_A/Source/irq_ctrl_gic.c
@@ -0,0 +1,410 @@
+/**************************************************************************//**
+ * @file irq_ctrl_gic.c
+ * @brief Interrupt controller handling implementation for GIC
+ * @version V1.0.1
+ * @date 9. April 2018
+ ******************************************************************************/
+/*
+ * Copyright (c) 2017 ARM Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the License); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stddef.h>
+
+#include "RTE_Components.h"
+#include CMSIS_device_header
+
+#include "irq_ctrl.h"
+
+#if defined(__GIC_PRESENT) && (__GIC_PRESENT == 1U)
+
+/// Number of implemented interrupt lines
+#ifndef IRQ_GIC_LINE_COUNT
+#define IRQ_GIC_LINE_COUNT (1020U)
+#endif
+
+static IRQHandler_t IRQTable[IRQ_GIC_LINE_COUNT] = { 0U };
+static uint32_t IRQ_ID0;
+
+/// Initialize interrupt controller.
+__WEAK int32_t IRQ_Initialize (void) {
+ uint32_t i;
+
+ for (i = 0U; i < IRQ_GIC_LINE_COUNT; i++) {
+ IRQTable[i] = (IRQHandler_t)NULL;
+ }
+ GIC_Enable();
+ return (0);
+}
+
+
+/// Register interrupt handler.
+__WEAK int32_t IRQ_SetHandler (IRQn_ID_t irqn, IRQHandler_t handler) {
+ int32_t status;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ IRQTable[irqn] = handler;
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Get the registered interrupt handler.
+__WEAK IRQHandler_t IRQ_GetHandler (IRQn_ID_t irqn) {
+ IRQHandler_t h;
+
+ // Ignore CPUID field (software generated interrupts)
+ irqn &= 0x3FFU;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ h = IRQTable[irqn];
+ } else {
+ h = (IRQHandler_t)0;
+ }
+
+ return (h);
+}
+
+
+/// Enable interrupt.
+__WEAK int32_t IRQ_Enable (IRQn_ID_t irqn) {
+ int32_t status;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_EnableIRQ ((IRQn_Type)irqn);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Disable interrupt.
+__WEAK int32_t IRQ_Disable (IRQn_ID_t irqn) {
+ int32_t status;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_DisableIRQ ((IRQn_Type)irqn);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Get interrupt enable state.
+__WEAK uint32_t IRQ_GetEnableState (IRQn_ID_t irqn) {
+ uint32_t enable;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ enable = GIC_GetEnableIRQ((IRQn_Type)irqn);
+ } else {
+ enable = 0U;
+ }
+
+ return (enable);
+}
+
+
+/// Configure interrupt request mode.
+__WEAK int32_t IRQ_SetMode (IRQn_ID_t irqn, uint32_t mode) {
+ uint32_t val;
+ uint8_t cfg;
+ uint8_t secure;
+ uint8_t cpu;
+ int32_t status = 0;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ // Check triggering mode
+ val = (mode & IRQ_MODE_TRIG_Msk);
+
+ if (val == IRQ_MODE_TRIG_LEVEL) {
+ cfg = 0x00U;
+ } else if (val == IRQ_MODE_TRIG_EDGE) {
+ cfg = 0x02U;
+ } else {
+ cfg = 0x00U;
+ status = -1;
+ }
+
+ // Check interrupt type
+ val = mode & IRQ_MODE_TYPE_Msk;
+
+ if (val != IRQ_MODE_TYPE_IRQ) {
+ status = -1;
+ }
+
+ // Check interrupt domain
+ val = mode & IRQ_MODE_DOMAIN_Msk;
+
+ if (val == IRQ_MODE_DOMAIN_NONSECURE) {
+ secure = 0U;
+ } else {
+ // Check security extensions support
+ val = GIC_DistributorInfo() & (1UL << 10U);
+
+ if (val != 0U) {
+ // Security extensions are supported
+ secure = 1U;
+ } else {
+ secure = 0U;
+ status = -1;
+ }
+ }
+
+ // Check interrupt CPU targets
+ val = mode & IRQ_MODE_CPU_Msk;
+
+ if (val == IRQ_MODE_CPU_ALL) {
+ cpu = 0xFFU;
+ } else {
+ cpu = val >> IRQ_MODE_CPU_Pos;
+ }
+
+ // Apply configuration if no mode error
+ if (status == 0) {
+ GIC_SetConfiguration((IRQn_Type)irqn, cfg);
+ GIC_SetTarget ((IRQn_Type)irqn, cpu);
+
+ if (secure != 0U) {
+ GIC_SetGroup ((IRQn_Type)irqn, secure);
+ }
+ }
+ }
+
+ return (status);
+}
+
+
+/// Get interrupt mode configuration.
+__WEAK uint32_t IRQ_GetMode (IRQn_ID_t irqn) {
+ uint32_t mode;
+ uint32_t val;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ mode = IRQ_MODE_TYPE_IRQ;
+
+ // Get trigger mode
+ val = GIC_GetConfiguration((IRQn_Type)irqn);
+
+ if ((val & 2U) != 0U) {
+ // Corresponding interrupt is edge triggered
+ mode |= IRQ_MODE_TRIG_EDGE;
+ } else {
+ // Corresponding interrupt is level triggered
+ mode |= IRQ_MODE_TRIG_LEVEL;
+ }
+
+ // Get interrupt CPU targets
+ mode |= GIC_GetTarget ((IRQn_Type)irqn) << IRQ_MODE_CPU_Pos;
+
+ } else {
+ mode = IRQ_MODE_ERROR;
+ }
+
+ return (mode);
+}
+
+
+/// Get ID number of current interrupt request (IRQ).
+__WEAK IRQn_ID_t IRQ_GetActiveIRQ (void) {
+ IRQn_ID_t irqn;
+ uint32_t prio;
+
+ /* Dummy read to avoid GIC 390 errata 801120 */
+ GIC_GetHighPendingIRQ();
+
+ irqn = GIC_AcknowledgePending();
+
+ __DSB();
+
+ /* Workaround GIC 390 errata 733075 (GIC-390_Errata_Notice_v6.pdf, 09-Jul-2014) */
+ /* The following workaround code is for a single-core system. It would be */
+ /* different in a multi-core system. */
+ /* If the ID is 0 or 0x3FE or 0x3FF, then the GIC CPU interface may be locked-up */
+ /* so unlock it, otherwise service the interrupt as normal. */
+ /* Special IDs 1020=0x3FC and 1021=0x3FD are reserved values in GICv1 and GICv2 */
+ /* so will not occur here. */
+
+ if ((irqn == 0) || (irqn >= 0x3FE)) {
+ /* Unlock the CPU interface with a dummy write to Interrupt Priority Register */
+ prio = GIC_GetPriority((IRQn_Type)0);
+ GIC_SetPriority ((IRQn_Type)0, prio);
+
+ __DSB();
+
+ if ((irqn == 0U) && ((GIC_GetIRQStatus ((IRQn_Type)irqn) & 1U) != 0U) && (IRQ_ID0 == 0U)) {
+ /* If the ID is 0, is active and has not been seen before */
+ IRQ_ID0 = 1U;
+ }
+ /* End of Workaround GIC 390 errata 733075 */
+ }
+
+ return (irqn);
+}
+
+
+/// Get ID number of current fast interrupt request (FIQ).
+__WEAK IRQn_ID_t IRQ_GetActiveFIQ (void) {
+ return ((IRQn_ID_t)-1);
+}
+
+
+/// Signal end of interrupt processing.
+__WEAK int32_t IRQ_EndOfInterrupt (IRQn_ID_t irqn) {
+ int32_t status;
+ IRQn_Type irq = (IRQn_Type)irqn;
+
+ irqn &= 0x3FFU;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_EndInterrupt (irq);
+
+ if (irqn == 0) {
+ IRQ_ID0 = 0U;
+ }
+
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Set interrupt pending flag.
+__WEAK int32_t IRQ_SetPending (IRQn_ID_t irqn) {
+ int32_t status;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_SetPendingIRQ ((IRQn_Type)irqn);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+/// Get interrupt pending flag.
+__WEAK uint32_t IRQ_GetPending (IRQn_ID_t irqn) {
+ uint32_t pending;
+
+ if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ pending = GIC_GetPendingIRQ ((IRQn_Type)irqn);
+ } else {
+ pending = 0U;
+ }
+
+ return (pending & 1U);
+}
+
+
+/// Clear interrupt pending flag.
+__WEAK int32_t IRQ_ClearPending (IRQn_ID_t irqn) {
+ int32_t status;
+
+ if ((irqn >= 16) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_ClearPendingIRQ ((IRQn_Type)irqn);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Set interrupt priority value.
+__WEAK int32_t IRQ_SetPriority (IRQn_ID_t irqn, uint32_t priority) {
+ int32_t status;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ GIC_SetPriority ((IRQn_Type)irqn, priority);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Get interrupt priority.
+__WEAK uint32_t IRQ_GetPriority (IRQn_ID_t irqn) {
+ uint32_t priority;
+
+ if ((irqn >= 0) && (irqn < (IRQn_ID_t)IRQ_GIC_LINE_COUNT)) {
+ priority = GIC_GetPriority ((IRQn_Type)irqn);
+ } else {
+ priority = IRQ_PRIORITY_ERROR;
+ }
+
+ return (priority);
+}
+
+
+/// Set priority masking threshold.
+__WEAK int32_t IRQ_SetPriorityMask (uint32_t priority) {
+ GIC_SetInterfacePriorityMask (priority);
+ return (0);
+}
+
+
+/// Get priority masking threshold
+__WEAK uint32_t IRQ_GetPriorityMask (void) {
+ return GIC_GetInterfacePriorityMask();
+}
+
+
+/// Set priority grouping field split point
+__WEAK int32_t IRQ_SetPriorityGroupBits (uint32_t bits) {
+ int32_t status;
+
+ if (bits == IRQ_PRIORITY_Msk) {
+ bits = 7U;
+ }
+
+ if (bits < 8U) {
+ GIC_SetBinaryPoint (7U - bits);
+ status = 0;
+ } else {
+ status = -1;
+ }
+
+ return (status);
+}
+
+
+/// Get priority grouping field split point
+__WEAK uint32_t IRQ_GetPriorityGroupBits (void) {
+ uint32_t bp;
+
+ bp = GIC_GetBinaryPoint() & 0x07U;
+
+ return (7U - bp);
+}
+
+#endif