diff --git a/portable/GCC/ARM_AARCH64/port.c b/portable/GCC/ARM_AARCH64/port.c index 238874edc8..41db96cfe0 100644 --- a/portable/GCC/ARM_AARCH64/port.c +++ b/portable/GCC/ARM_AARCH64/port.c @@ -170,6 +170,9 @@ __attribute__( ( used ) ) const uint64_t ullICCEOIR = portICCEOIR_END_OF_INTERRU __attribute__( ( used ) ) const uint64_t ullICCIAR = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS; __attribute__( ( used ) ) const uint64_t ullICCPMR = portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS; __attribute__( ( used ) ) const uint64_t ullMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT ); +__attribute__( ( used ) ) const uint64_t ullICCHPPIR = portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_REGISTER_ADDRESS; +__attribute__( ( used ) ) const uint64_t ullICCAIAR = portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS; +__attribute__( ( used ) ) const uint64_t ullICCAEOIR = portICCAEOIR_ALIASED_END_OF_INTERRUPT_REGISTER_ADDRESS; /*-----------------------------------------------------------*/ diff --git a/portable/GCC/ARM_AARCH64/portASM.S b/portable/GCC/ARM_AARCH64/portASM.S index e684755bf1..56eb64d678 100644 --- a/portable/GCC/ARM_AARCH64/portASM.S +++ b/portable/GCC/ARM_AARCH64/portASM.S @@ -307,13 +307,34 @@ FreeRTOS_IRQ_Handler: /* Maintain the interrupt nesting information across the function call. */ STP X1, X5, [SP, #-0x10]! - /* Read value from the interrupt acknowledge register, which is stored in W0 - for future parameter and interrupt clearing use. */ - LDR X2, ullICCIARConst - LDR X3, [X2] - LDR W0, [X3] /* ICCIAR in W0 as parameter. */ - - /* Maintain the ICCIAR value across the function call. */ + /* Read value from the HPPI register + * In GIC v2, the HPPI register will contain: + * - 0x3FF on GIC ack or spurious IRQ + * - 0x3FE on pending IRQ within Group 1 (IRQ, non-secure) + * - IRQn on pending IRQ within Group 0 (FIQ, secure) + * + * X0 to contain IRQn + * X1 to contain IRQn Group number + */ + LDR X2, ullICCHPPIRConst + LDR X2, [X2] + LDR W3, [X2] + CMP W3, #0x3FE + B.NE 1f + + /* if IRQn Group 1, AIAR contains IRQn */ +2: LDR X2, ullICCAIARConst + MOV X1, #1 + B 0f + + /* if IRQn Group 0, IAR contains IRQn */ +1: LDR X2, ullICCIARConst + MOV X1, #0 + +0: LDR W2, [X2] + LDR W0, [X2] + + /* Maintain the IRQn value across the function call. */ STP X0, X1, [SP, #-0x10]! /* Call the C handler. */ @@ -324,12 +345,25 @@ FreeRTOS_IRQ_Handler: DSB SY ISB SY - /* Restore the ICCIAR value. */ + /* Restore the IRqn value. */ LDP X0, X1, [SP], #0x10 - /* End IRQ processing by writing ICCIAR to the EOI register. */ - LDR X4, ullICCEOIRConst - LDR X4, [X4] + /* End IRQ processing by writing to the EOI register. + * In GIV v2, the EOI register to be used depends on the interrupt group: + * - IRQn Group 0 -> EOI + * - IRQn Group 1 -> AEOI + */ + CMP X1, #1 + B.NE 1f + + /* if IRQn Group 1, use AEOIR */ +2: LDR X4, ullICCAEOIRConst + B 0f + + /* if IRQn Group 0, use EOIR */ +1: LDR X4, ullICCEOIRConst + +0: LDR W4, [X4] STR W0, [X4] /* Restore the critical nesting count. */ @@ -420,6 +454,9 @@ ullPortInterruptNestingConst: .dword ullPortInterruptNesting ullPortYieldRequiredConst: .dword ullPortYieldRequired ullICCIARConst: .dword ullICCIAR ullICCEOIRConst: .dword ullICCEOIR +ullICCHPPIRConst: .dword ullICCHPPIR +ullICCAIARConst: .dword ullICCAIAR +ullICCAEOIRConst: .dword ullICCAEOIR vApplicationIRQHandlerConst: .word vApplicationIRQHandler diff --git a/portable/GCC/ARM_AARCH64/portmacro.h b/portable/GCC/ARM_AARCH64/portmacro.h index e89abb6619..42e797f66e 100644 --- a/portable/GCC/ARM_AARCH64/portmacro.h +++ b/portable/GCC/ARM_AARCH64/portmacro.h @@ -204,14 +204,21 @@ void FreeRTOS_Tick_Handler( void ); #define portICCEOIR_END_OF_INTERRUPT_OFFSET ( 0x10 ) #define portICCBPR_BINARY_POINT_OFFSET ( 0x08 ) #define portICCRPR_RUNNING_PRIORITY_OFFSET ( 0x14 ) +#define portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_OFFSET ( 0x18 ) +#define portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_OFFSET ( 0x20 ) +#define portICCAEOIR_ALIASED_END_OF_INTERRUPT_OFFSET ( 0x24 ) + +#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET ) +#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) ) +#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ) +#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET ) +#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) +#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) ) +#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) ) +#define portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_OFFSET ) +#define portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_OFFSET ) +#define portICCAEOIR_ALIASED_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCAEOIR_ALIASED_END_OF_INTERRUPT_OFFSET ) -#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET ) -#define portICCPMR_PRIORITY_MASK_REGISTER ( *( ( volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) ) -#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET ) -#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET ) -#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) -#define portICCBPR_BINARY_POINT_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) ) -#define portICCRPR_RUNNING_PRIORITY_REGISTER ( *( ( const volatile uint32_t * ) ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) ) #define portMEMORY_BARRIER() __asm volatile ( "" ::: "memory" )