mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-02-04 04:51:53 +00:00
[docs][libcpu][arm][cortex-a] add comment for gic.c
This commit is contained in:
@@ -25,41 +25,60 @@ struct arm_gic
|
||||
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];
|
||||
|
||||
/** 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)
|
||||
*/
|
||||
#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;
|
||||
|
||||
/**
|
||||
* @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 irq;
|
||||
@@ -71,6 +90,21 @@ int arm_gic_get_active_irq(rt_uint32_t index)
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
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 pend;
|
||||
@@ -119,12 +173,12 @@ rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
|
||||
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
|
||||
{
|
||||
/* 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 */
|
||||
if (pend != 0U)
|
||||
{
|
||||
@@ -139,6 +193,12 @@ rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 pending;
|
||||
@@ -314,6 +494,28 @@ rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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_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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
unsigned int gic_type;
|
||||
@@ -458,6 +738,11 @@ void arm_gic_dump_type(rt_uint32_t index)
|
||||
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)
|
||||
{
|
||||
unsigned int i, k;
|
||||
|
||||
Reference in New Issue
Block a user