Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] <Support Cortex-A35> #316

Open
cyliangtw opened this issue Apr 23, 2021 · 6 comments
Open

[Feature Request] <Support Cortex-A35> #316

cyliangtw opened this issue Apr 23, 2021 · 6 comments
Labels
enhancement New feature or request

Comments

@cyliangtw
Copy link

Is your feature request related to a problem? Please describe.
So far, the support Cortex-A CPU cores are A9 and A53. I can't find CPU core Cortex-A35 64-bit in the list.

Describe the solution you'd like
I am eager to see Cortex-A35 64-bit in GCC CPU list or RVDS CPU list ,then I could apply FreeRTOS on our Cortex-A35 platform.

Describe alternatives you've considered
None

Additional context
None

@cyliangtw cyliangtw added the enhancement New feature or request label Apr 23, 2021
@RichardBarry
Copy link
Contributor

What are the major differences between the A35 and A55 (64-bit)?

@cyliangtw
Copy link
Author

This web page arm-cortex-a35-in-comparison comparing the Cortex-A35 and Cortex-A53.
In RTOS porting layer, it's relative to ARM CPU instructions, for example Cortex-M3 is different from Cortex-M4 in APSR, xPSR, SCB at least.

@Atomar25
Copy link
Contributor

Atomar25 commented May 25, 2021

I don't think, there is lot of difference between Cortex-A35 and Cortex-A53 when it comes to CPU instructions, Cortex-A35 is Armv8-A 64-bit processor which is what Cortex-A53 based on. So, I believe any code that runs on Cortex-A53 should work on Cortex-A35. It just you need to figure out what the Memory Map your SBC has , and enable the Devices (GIC and UART to start with).

I would like to try this out but unfortunately doesn't have an SBC with Cortex-A35.

@cyliangtw
Copy link
Author

@Atomar25 , Thanks of your comment, according to my experience in Cortex-M23, both of Cortex-M23 and Cortex-M33 are Armv8M, the CPU instructions are similar but still need to divide as ARM_CM23 and ARM_CM33 at portable/GCC

If just verify CPU core only, keil Simulator is a good choice. In Keil IDE project options, press "Debug" and check radio button of "Use Simulator".

@sean-ascent
Copy link

sean-ascent commented Sep 3, 2024

@RichardBarry @Atomar25 I would like to revive this request and add a few contributions from my side. I just finished making modifications to the AARCH64 port to get the kernel running on an A35 core. Details below:

Target

  • Development board: STM32MP257F-EV1
  • Instruction Set Architecture: A64
  • IDE and version: VsCode 1.92.2
  • Toolchain and version: arm-gnu-toolchain-13.2.Rel1-x86_64-aarch64-none-elf

Host

  • Host OS: Ubuntu (Docker)
  • Version: 22.04

Expected Behavior
Kernel will preemptively switch tasks via either the FreeRTOS_SWI_Handler (by way of SMC instruction) or via the FreeRTOS_Tick_Handler in conjunction with the FreeRTOS_IRQ_Handler.

Actual Behavior
Kernel successfully switches to initial task via FreeRTOS_SWI_Handler but subsequent switch attempts by the tick mechanism result in an ambiguous synchronous exception (ESR = 0x0, ELR = 0x3C).

Modifications

The STM32MP2xx microprocessor utilizes GIC v2.0 which supports interrupt grouping and security extensions. By implementation, all non-secure IRQs are routed to the GIC as IRQs and all secure IRQs are routed as FIQs. The AARCH64 port currently does not correctly handle the discovery and clearing of IRQs by interrupt group. The AARCH64 port was modified to utilize the ICCHPPIR register, in conjunction with the aliased and non-aliased ICCIAR and ICCEOIR registers, to correctly handle interrupts for this part. Interrupt pending bit clearing is delegated to user vApplicationIRQHandler. Context switching occurs via FreeRTOS_Tick_Handler call from the physical timer interrupt handler.

Diff

portable/GCC/ARM_AARCH64/port.c

diff --git a/portable/GCC/ARM_AARCH64/port.c b/portable/GCC/ARM_AARCH64/port.c
index 238874edc..7d2b3e673 100644
--- a/portable/GCC/ARM_AARCH64/port.c
+++ b/portable/GCC/ARM_AARCH64/port.c
@@ -166,9 +166,12 @@ uint64_t ullPortYieldRequired = pdFALSE;
 uint64_t ullPortInterruptNesting = 0;
 
 /* Used in the ASM code. */
-__attribute__( ( used ) ) const uint64_t ullICCEOIR = portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS;
-__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 ullICCHPPIR = portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_REGISTER_ADDRESS;
+__attribute__( ( used ) ) const uint64_t ullICCIAR = portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS;
+__attribute__( ( used ) ) const uint64_t ullICCEOIR = portICCEOIR_END_OF_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;
 __attribute__( ( used ) ) const uint64_t ullMaxAPIPriorityMask = ( configMAX_API_CALL_INTERRUPT_PRIORITY << portPRIORITY_SHIFT );
 
 /*-----------------------------------------------------------*/

portable/GCC/ARM_AARCH64/portASM.S

diff --git a/portable/GCC/ARM_AARCH64/portASM.S b/portable/GCC/ARM_AARCH64/portASM.S
index e684755bf..f75d34dd8 100644
--- a/portable/GCC/ARM_AARCH64/portASM.S
+++ b/portable/GCC/ARM_AARCH64/portASM.S
@@ -307,13 +307,32 @@ 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 HPPIR register 
+     * This determines which interrupt group the IRQ belongs to.
+     */
+    LDR     X2, ullICCHPPIRConst
+    LDR     X2, [X2]
+    LDR     W3, [X2]
+    CMP     W3, #0x3FE
+    B.NE    1f
+
+    /* Interrupt group 1 (IRQ, nonsecure)
+     * Read from aliased register groups to get non-secure IRQ number
+     */
+2:  LDR     X2, ullICCAIARConst
+    MOV     X1, #1
+    B       0f
+    
+    /* Interrupt group 0 (FIQ, secure)
+     * Read from non-alised register groups to get secure FIQ number
+     */
+1:  LDR     X2, ullICCIARConst
+    MOV     X1, #0
+
+0:  LDR     W2, [X2]
+    LDR     W0, [X2]
+    
+    /* Maintain the ICC(A)IAR values across the function call. */
     STP     X0, X1, [SP, #-0x10]!
 
     /* Call the C handler. */
@@ -328,8 +347,21 @@ FreeRTOS_IRQ_Handler:
     LDP     X0, X1, [SP], #0x10
 
     /* End IRQ processing by writing ICCIAR to the EOI register. */
-    LDR     X4, ullICCEOIRConst
-    LDR     X4, [X4]
+    CMP     X1, #1
+    B.NE    1f
+
+    /* Interrupt group 1 (IRQ, nonsecure)
+     * Write to aliased EOI register.
+     */
+2:  LDR     X4, ullICCAEOIRConst
+    B       0f
+
+    /* Interrupt group 0 (FIQ, secure)
+     * Write to non-aliased EOI register.
+     */
+1:  LDR     X4, ullICCEOIRConst
+
+0:  LDR     W4, [X4]
     STR     W0, [X4]
 
     /* Restore the critical nesting count. */
@@ -418,8 +450,11 @@ ullICCPMRConst: .dword ullICCPMR
 ullMaxAPIPriorityMaskConst: .dword ullMaxAPIPriorityMask
 ullPortInterruptNestingConst: .dword ullPortInterruptNesting
 ullPortYieldRequiredConst: .dword ullPortYieldRequired
+ullICCHPPIRConst: .dword ullICCHPPIR
 ullICCIARConst: .dword ullICCIAR
 ullICCEOIRConst: .dword ullICCEOIR
+ullICCAIARConst: .dword ullICCAIAR
+ullICCAEOIRConst: .dword ullICCAEOIR
 vApplicationIRQHandlerConst: .word vApplicationIRQHandler

portable/GCC/ARM_AARCH64/portmacro.h

diff --git a/portable/GCC/ARM_AARCH64/portmacro.h b/portable/GCC/ARM_AARCH64/portmacro.h
index e89abb661..b63bf31a1 100644
--- a/portable/GCC/ARM_AARCH64/portmacro.h
+++ b/portable/GCC/ARM_AARCH64/portmacro.h
@@ -200,18 +200,24 @@ void FreeRTOS_Tick_Handler( void );
 
 /* Interrupt controller access addresses. */
 #define portICCPMR_PRIORITY_MASK_OFFSET                      ( 0x04 )
+#define portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_OFFSET       ( 0x18 )
 #define portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET              ( 0x0C )
 #define portICCEOIR_END_OF_INTERRUPT_OFFSET                  ( 0x10 )
+#define portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_OFFSET     ( 0x20 )
+#define portICCAEOIR_ALIASED_END_OF_INTERRUPT_OFFSET         ( 0x24 )
 #define portICCBPR_BINARY_POINT_OFFSET                       ( 0x08 )
 #define portICCRPR_RUNNING_PRIORITY_OFFSET                   ( 0x14 )
 
-#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS       ( configINTERRUPT_CONTROLLER_BASE_ADDRESS + co
nfigINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
-#define portICCPMR_PRIORITY_MASK_REGISTER                    ( *( ( volatile uint32_t * ) ( portINTERRUPT_C
ONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
-#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS    ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRE
SS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
-#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS        ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRE
SS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
-#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS            ( portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRE
SS + portICCPMR_PRIORITY_MASK_OFFSET )
-#define portICCBPR_BINARY_POINT_REGISTER                     ( *( ( const volatile uint32_t * ) ( portINTER
RUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
-#define portICCRPR_RUNNING_PRIORITY_REGISTER                 ( *( ( const volatile uint32_t * ) ( portINTER
RUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
+#define portINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS              ( configINTERRUPT_CONTROLLER_BASE_ADDRE
SS + configINTERRUPT_CONTROLLER_CPU_INTERFACE_OFFSET )
+#define portICCPMR_PRIORITY_MASK_REGISTER                           ( *( ( volatile uint32_t * ) ( portINTE
RRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET ) ) )
+#define portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_REGISTER_ADDRESS    ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCHPPIR_HIGHEST_PRIORITY_INTERRUPT_OFFSET )
+#define portICCIAR_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS           ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCIAR_INTERRUPT_ACKNOWLEDGE_OFFSET )
+#define portICCPMR_PRIORITY_MASK_REGISTER_ADDRESS                   ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCPMR_PRIORITY_MASK_OFFSET )
+#define portICCEOIR_END_OF_INTERRUPT_REGISTER_ADDRESS               ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCEOIR_END_OF_INTERRUPT_OFFSET )
+#define portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_REGISTER_ADDRESS  ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCAIAR_ALIASED_INTERRUPT_ACKNOWLEDGE_OFFSET )
+#define portICCAEOIR_ALIASED_END_OF_INTERRUPT_REGISTER_ADDRESS      ( portINTERRUPT_CONTROLLER_CPU_INTERFAC
E_ADDRESS + portICCAEOIR_ALIASED_END_OF_INTERRUPT_OFFSET )
+#define portICCBPR_BINARY_POINT_REGISTER                            ( *( ( const volatile uint32_t * ) ( po
rtINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCBPR_BINARY_POINT_OFFSET ) ) )
+#define portICCRPR_RUNNING_PRIORITY_REGISTER                        ( *( ( const volatile uint32_t * ) ( po
rtINTERRUPT_CONTROLLER_CPU_INTERFACE_ADDRESS + portICCRPR_RUNNING_PRIORITY_OFFSET ) ) )
 
 #define portMEMORY_BARRIER()    __asm volatile ( "" ::: "memory" )

Hope this helps.

@n9wxu
Copy link
Member

n9wxu commented Sep 3, 2024

Can you submit a PR with your changes?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants