|
@@ -25,41 +25,60 @@ struct arm_gic
|
|
|
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
|
|
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-/* 'ARM_GIC_MAX_NR' is the number of cores */
|
|
|
|
|
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
|
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
|
|
|
|
|
|
|
|
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
|
/** Macro to access the Generic Interrupt Controller Interface (GICC)
|
|
|
*/
|
|
*/
|
|
|
-#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
|
|
|
|
|
-#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
|
|
|
|
|
-#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
|
|
|
|
|
-#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
|
|
|
|
|
-#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
|
|
|
|
|
-#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
|
|
|
|
|
-#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
|
|
|
|
|
-#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
|
|
|
|
|
|
|
+#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U) /* GICC_CTLR */
|
|
|
|
|
+#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U) /* GICC_PMR */
|
|
|
|
|
+#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U) /* GICC_BPR */
|
|
|
|
|
+#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU) /* GICC_IAR */
|
|
|
|
|
+#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U) /* GICC_EOIR */
|
|
|
|
|
+#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U) /* GICC_RPR */
|
|
|
|
|
+#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U) /* GICC_HPPIR */
|
|
|
|
|
+#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU) /* GICC_IIDR */
|
|
|
|
|
|
|
|
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
|
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
|
|
|
*/
|
|
*/
|
|
|
-#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
|
|
|
|
|
-#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
|
|
|
|
|
-#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
|
|
|
|
|
-#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
|
|
|
|
|
-#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
|
|
|
|
|
-#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
|
|
|
|
|
-#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
|
|
|
|
|
-#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
|
|
|
|
|
-#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
|
|
|
|
|
-#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
|
|
|
|
|
|
|
+#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U) /* GICD_CTLR */
|
|
|
|
|
+#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U) /* GICD_TYPER */
|
|
|
|
|
+#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U) /* GICD_IGROUPRn */
|
|
|
|
|
+#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U) /* GICD_ISENABLERn */
|
|
|
|
|
+#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U) /* GICD_ICENABLERn */
|
|
|
|
|
+#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U) /* GICD_ISPENDRn */
|
|
|
|
|
+#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U) /* GICD_ICPENDRn */
|
|
|
|
|
+#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U) /* GICD_ISACTIVERn */
|
|
|
|
|
+#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U) /* GICD_ICACTIVERn */
|
|
|
|
|
+#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U) /* GICD_IPRIORITYRn */
|
|
|
|
|
+#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U) /* GICD_ITARGETSRn */
|
|
|
|
|
+#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U) /* GICD_ICFGRn */
|
|
|
|
|
+#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U) /* GICD_SGIR */
|
|
|
|
|
+#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U) /* GICD_CPENDSGIRn */
|
|
|
|
|
+#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U) /* GICD_SPENDSGIRn */
|
|
|
|
|
+#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U) /* ICPIDR2 */
|
|
|
|
|
|
|
|
static unsigned int _gic_max_irq;
|
|
static unsigned int _gic_max_irq;
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the active interrupt number
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note Read the GICC_IAR register and add the interrupt number offset to get
|
|
|
|
|
+ * the actual interrupt number.
|
|
|
|
|
+ * This read acts as an acknowledge for the interrupt, changing the interrupt
|
|
|
|
|
+ * state from pending to active.
|
|
|
|
|
+ *
|
|
|
|
|
+ * GICC_IAR register bit fields:
|
|
|
|
|
+ * - GICC_IAR[31:13]: Reserved, read as 0
|
|
|
|
|
+ * - GICC_IAR[12:10]: CPUID
|
|
|
|
|
+ * For SGIs: This value is the CPUID that requested the interrupt.
|
|
|
|
|
+ * For other interrupts: This value reads as 0 (RAZ).
|
|
|
|
|
+ * - GICC_IAR[9:0]: Interrupt ID
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The actual interrupt number (with offset added).
|
|
|
|
|
+ * Note: For SGIs, the return value may include CPUID information in the upper bits.
|
|
|
|
|
+ */
|
|
|
int arm_gic_get_active_irq(rt_uint32_t index)
|
|
int arm_gic_get_active_irq(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
int irq;
|
|
int irq;
|
|
@@ -71,6 +90,21 @@ int arm_gic_get_active_irq(rt_uint32_t index)
|
|
|
return irq;
|
|
return irq;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Acknowledge and end the interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function completes the interrupt handling by:
|
|
|
|
|
+ * 1. Clearing the pending status of the interrupt in the Distributor (GICD_ICPENDRn).
|
|
|
|
|
+ * 2. Writing the interrupt ID to the End of Interrupt Register (GICC_EOIR).
|
|
|
|
|
+ * This signals the GIC that interrupt processing is complete and changes
|
|
|
|
|
+ * the interrupt state from active to inactive.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This function should be called after the interrupt handler has finished
|
|
|
|
|
+ * processing the interrupt, typically at the end of the interrupt service routine.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number (with offset) to acknowledge
|
|
|
|
|
+ */
|
|
|
void arm_gic_ack(rt_uint32_t index, int irq)
|
|
void arm_gic_ack(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
@@ -84,6 +118,12 @@ void arm_gic_ack(rt_uint32_t index, int irq)
|
|
|
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
|
|
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Disable the forwarding of the corresponding interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ */
|
|
|
void arm_gic_mask(rt_uint32_t index, int irq)
|
|
void arm_gic_mask(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
@@ -96,6 +136,12 @@ void arm_gic_mask(rt_uint32_t index, int irq)
|
|
|
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
|
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Enables the forwarding of the corresponding interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ */
|
|
|
void arm_gic_umask(rt_uint32_t index, int irq)
|
|
void arm_gic_umask(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
@@ -105,9 +151,17 @@ void arm_gic_umask(rt_uint32_t index, int irq)
|
|
|
irq = irq - _gic_table[index].offset;
|
|
irq = irq - _gic_table[index].offset;
|
|
|
RT_ASSERT(irq >= 0U);
|
|
RT_ASSERT(irq >= 0U);
|
|
|
|
|
|
|
|
- GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
|
|
|
|
|
|
|
+ GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; /* GICD_ISENABLERn */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Identifies whether the interrupt is pending
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 0: not pending, 1: pending
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t pend;
|
|
rt_uint32_t pend;
|
|
@@ -119,12 +173,12 @@ rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
|
|
|
|
|
|
|
if (irq >= 16U)
|
|
if (irq >= 16U)
|
|
|
{
|
|
{
|
|
|
- pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
|
|
|
|
|
|
+ pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL; /* GICD_ISPENDRn */
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
/* INTID 0-15 Software Generated Interrupt */
|
|
/* INTID 0-15 Software Generated Interrupt */
|
|
|
- pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
|
|
|
|
|
|
+ pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL; /* GICD_SPENDSGIRn */
|
|
|
/* No CPU identification offered */
|
|
/* No CPU identification offered */
|
|
|
if (pend != 0U)
|
|
if (pend != 0U)
|
|
|
{
|
|
{
|
|
@@ -139,6 +193,12 @@ rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
|
|
return (pend);
|
|
return (pend);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set the interrupt as pending
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
|
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -158,6 +218,12 @@ void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief clears the pending state of the interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ */
|
|
|
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
|
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask;
|
|
rt_uint32_t mask;
|
|
@@ -179,6 +245,24 @@ void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Configure whether the corresponding interrupt is edge-triggered or level-sensitive
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note For SGIs (interrupt IDs 0-15), the Int_config fields are read-only,
|
|
|
|
|
+ * meaning that GICD_ICFGR0 is read-only. Writing to this register for SGIs
|
|
|
|
|
+ * will have no effect.
|
|
|
|
|
+ *
|
|
|
|
|
+ * For PPIs (interrupt IDs 16-31), it is IMPLEMENTATION DEFINED whether
|
|
|
|
|
+ * the most significant bit of the Int_config field is programmable.
|
|
|
|
|
+ * Some implementations may make PPI configuration registers read-only.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This function is primarily intended for configuring SPIs (interrupt IDs 32+),
|
|
|
|
|
+ * which have fully programmable configuration registers.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ * @param config 0: level-sensitive, 1: edge-triggered
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
|
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t icfgr;
|
|
rt_uint32_t icfgr;
|
|
@@ -198,6 +282,14 @@ void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
|
|
|
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
|
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Identifies whether the corresponding interrupt is edge-triggered or level-sensitive
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 0: level-sensitive, 1: edge-triggered
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -208,6 +300,12 @@ rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
|
|
|
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
|
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Deactivates the corresponding interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ */
|
|
|
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
|
void arm_gic_clear_active(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
rt_uint32_t mask = 1U << (irq % 32U);
|
|
@@ -220,7 +318,14 @@ void arm_gic_clear_active(rt_uint32_t index, int irq)
|
|
|
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
|
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-/* Set up the cpu mask for the specific interrupt */
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set up the cpu mask for the specific interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param cpumask CPU targets. Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
|
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t old_tgt;
|
|
rt_uint32_t old_tgt;
|
|
@@ -238,6 +343,14 @@ void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask)
|
|
|
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
|
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the CPU targets for the specific interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return CPU targets
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -248,6 +361,15 @@ rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
|
|
|
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
|
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set the priority for the specific interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note The lower the value, the greater the priority of the corresponding interrupt.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ * @param priority The priority to set.Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
|
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t mask;
|
|
rt_uint32_t mask;
|
|
@@ -263,6 +385,15 @@ void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
|
|
|
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
|
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the priority for the specific interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number(with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The priority of the corresponding interrupt.Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -273,6 +404,15 @@ rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
|
|
|
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
|
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set the priority mask for the specific CPU
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note Only interrupts with higher priority than the value in this
|
|
|
|
|
+ * register are signaled to the processor.
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param priority The priority mask to set.Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
|
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -281,6 +421,13 @@ void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
|
|
|
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
|
|
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the priority mask for the specific CPU
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The priority mask to return. Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
|
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -288,16 +435,49 @@ rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
|
|
|
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
|
|
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set the binary point value for interrupt priority splitting
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function sets the GICC_BPR (Binary Point Register) value, which is used
|
|
|
|
|
+ * to split the priority field into group priority and subpriority fields.
|
|
|
|
|
+ * The binary point determines how many bits are used for group priority:
|
|
|
|
|
+ * - A larger value results in fewer bits for group priority,
|
|
|
|
|
+ * reducing interrupt preemption capability.
|
|
|
|
|
+ * - A smaller value results in more bits for group priority,
|
|
|
|
|
+ * increasing interrupt preemption capability.
|
|
|
|
|
+ * - Only the lower 3 bits are valid (bits [2:0], range 0-7).
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param binary_point Binary point value. Only the lower 3 bits are valid (bits [2:0]).
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
|
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
|
|
|
{
|
|
{
|
|
|
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
|
|
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the binary point value for interrupt priority splitting
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @return Binary point value. Only the lower 3 bits are valid (bits [2:0]).
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
|
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
|
|
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the status of the specified interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function reads both the active and pending status of the interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number (with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return Encoded interrupt status:
|
|
|
|
|
+ * - Bit 0: Pending status
|
|
|
|
|
+ * - Bit 1: Active status
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t pending;
|
|
rt_uint32_t pending;
|
|
@@ -314,6 +494,28 @@ rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
|
|
return ((active << 1U) | pending);
|
|
return ((active << 1U) | pending);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Send a Software Generated Interrupt (SGI) to specified CPU(s)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function writes to the GICD_SGIR (Software Generated Interrupt Register)
|
|
|
|
|
+ * to generate an SGI. The register value is constructed as follows:
|
|
|
|
|
+ * - Bits [25:24]: TargetListFilter - determines how the SGI is forwarded
|
|
|
|
|
+ * * 0b00: Forward to CPUs specified in CPUTargetList
|
|
|
|
|
+ * * 0b01: Forward to all CPUs except the requesting CPU
|
|
|
|
|
+ * * 0b10: Forward only to the requesting CPU
|
|
|
|
|
+ * * 0b11: Reserved
|
|
|
|
|
+ * - Bits [23:16]: CPUTargetList - 8-bit mask specifying target CPUs
|
|
|
|
|
+ * (only used when TargetListFilter = 0b00)
|
|
|
|
|
+ * * Each bit represents a CPU: bit 0 = CPU 0, bit 1 = CPU 1, etc.
|
|
|
|
|
+ * - Bits [3:0]: SGIINTID - the SGI interrupt ID (0-15)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number (with offset).
|
|
|
|
|
+ * @param target_list CPU target mask. Only the lower 8 bits are valid (bits [7:0]).
|
|
|
|
|
+ * Each bit represents a CPU. Used when filter_list = 0b00.
|
|
|
|
|
+ * @param filter_list Target list filter mode. Only the lower 2 bits are valid (bits [1:0]).
|
|
|
|
|
+ * Determines how the SGI is forwarded to CPUs.
|
|
|
|
|
+ */
|
|
|
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
|
|
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -324,6 +526,21 @@ void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_ui
|
|
|
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
|
|
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the highest priority pending interrupt ID without acknowledging it
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function reads the GICC_HPPIR (Highest Priority Pending Interrupt Register)
|
|
|
|
|
+ * to get the interrupt ID of the highest priority pending interrupt.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Unlike reading GICC_IAR (via arm_gic_get_active_irq()), reading GICC_HPPIR
|
|
|
|
|
+ * does NOT acknowledge the interrupt. This means:
|
|
|
|
|
+ * - The interrupt state remains unchanged (still pending)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The 32-bit value read from the GICC_HPPIR register.
|
|
|
|
|
+ * The caller can extract specific fields (hardware interrupt ID without offset added).
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
|
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -331,6 +548,14 @@ rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
|
|
|
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
|
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the CPU Interface Identification Register (GICC_IIDR) value
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The 32-bit value read from the GICC_IIDR register.
|
|
|
|
|
+ * The caller can extract specific fields (implementer, product ID, revision, architecture version.)
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
|
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -338,6 +563,19 @@ rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
|
|
|
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
|
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Set the interrupt group for the specified interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function configures the interrupt group in the GICD_IGROUPRn register.
|
|
|
|
|
+ * The interrupt group determines the security classification of the interrupt
|
|
|
|
|
+ * when the GIC implements Security Extensions:
|
|
|
|
|
+ * - Group 0 (group = 0): Secure interrupts, used for secure world
|
|
|
|
|
+ * - Group 1 (group = 1): Non-secure interrupts, used for non-secure world
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number (with offset)
|
|
|
|
|
+ * @param group Interrupt group: 0 for Group 0 (secure), 1 for Group 1 (non-secure)
|
|
|
|
|
+ */
|
|
|
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
|
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
|
|
{
|
|
{
|
|
|
rt_uint32_t igroupr;
|
|
rt_uint32_t igroupr;
|
|
@@ -357,6 +595,19 @@ void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
|
|
|
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
|
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Get the interrupt group for the specified interrupt
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note This function reads the interrupt group from the GICD_IGROUPRn register.
|
|
|
|
|
+ * The return value indicates which security group the interrupt belongs to:
|
|
|
|
|
+ * - 0: Group 0 (Secure interrupt)
|
|
|
|
|
+ * - 1: Group 1 (Non-secure interrupt)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param irq The actual interrupt number (with offset)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return The interrupt group: 0 for Group 0 (secure), 1 for Group 1 (non-secure)
|
|
|
|
|
+ */
|
|
|
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
|
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -367,6 +618,19 @@ rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
|
|
|
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
|
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Initialize the GIC Distributor (GICD)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note: The exact bit definitions and behavior may vary depending on
|
|
|
|
|
+ * the GIC implementation (GICv1/GICv2) and security context.
|
|
|
|
|
+ *
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param dist_base Base address of the GIC Distributor (GICD)
|
|
|
|
|
+ * @param irq_start The first interrupt index offset in the vector table
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 0
|
|
|
|
|
+ */
|
|
|
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
|
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
|
|
{
|
|
{
|
|
|
unsigned int gic_type, i;
|
|
unsigned int gic_type, i;
|
|
@@ -427,6 +691,17 @@ int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Initialize the GIC CPU Interface (GICC)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @note: The exact bit definitions and behavior may vary depending on
|
|
|
|
|
+ * the GIC implementation (GICv1/GICv2) and security context..
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ * @param cpu_base Base address of the GIC CPU Interface (GICC)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @return 0
|
|
|
|
|
+ */
|
|
|
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
|
|
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
|
|
|
{
|
|
{
|
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
RT_ASSERT(index < ARM_GIC_MAX_NR);
|
|
@@ -445,6 +720,11 @@ int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Print the GIC infomations(version, base addr, max irq nums, security extension)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index GIC controller index
|
|
|
|
|
+ */
|
|
|
void arm_gic_dump_type(rt_uint32_t index)
|
|
void arm_gic_dump_type(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
unsigned int gic_type;
|
|
unsigned int gic_type;
|
|
@@ -458,6 +738,11 @@ void arm_gic_dump_type(rt_uint32_t index)
|
|
|
gic_type);
|
|
gic_type);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @brief Print the GIC status(highest priority pending interrupt, enable status, pending status , active status)
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param index
|
|
|
|
|
+ */
|
|
|
void arm_gic_dump(rt_uint32_t index)
|
|
void arm_gic_dump(rt_uint32_t index)
|
|
|
{
|
|
{
|
|
|
unsigned int i, k;
|
|
unsigned int i, k;
|