diff options
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/aarch64/common/gic/SConscript | 6 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gic/gic_pl390.c | 273 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gic/gic_pl390.h | 27 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/entry_point.S | 7 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/interrupt.c | 19 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/interrupt.h | 2 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a53/trap.c | 25 |
7 files changed, 355 insertions, 4 deletions
diff --git a/libcpu/aarch64/common/gic/SConscript b/libcpu/aarch64/common/gic/SConscript index b114ba7678..28daac87ff 100644 --- a/libcpu/aarch64/common/gic/SConscript +++ b/libcpu/aarch64/common/gic/SConscript @@ -5,6 +5,10 @@ from building import * cwd = GetCurrentDir() CPPPATH = [cwd] +gic390_group = Split(''' +gic_pl390.c +''') + gic400_group = Split(''' gic_pl400.c ''') @@ -14,6 +18,8 @@ gic_pl500.c ''') src = () +if GetDepend('BSP_USING_GIC390'): + src = gic390_group if GetDepend('BSP_USING_GIC400'): src = gic400_group if GetDepend('BSP_USING_GIC500'): diff --git a/libcpu/aarch64/common/gic/gic_pl390.c b/libcpu/aarch64/common/gic/gic_pl390.c new file mode 100644 index 0000000000..a8e3b10d94 --- /dev/null +++ b/libcpu/aarch64/common/gic/gic_pl390.c @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-31 GuEe-GUI the first version + */ +#include <rtthread.h> + +#include "gic_pl390.h" + +#define BIT(n) (1ul<<(n)) +#define MASK(n) (BIT(n)-1ul) + +#define IRQ_REG(IRQ) ((IRQ) / 32) +#define IRQ_BIT(IRQ) BIT((IRQ) % 32) +#define IRQ_MASK MASK(10) +#define IRQ_SET_ALL 0xffffffff +#define IS_IRQ_VALID(X) (((X)&IRQ_MASK) < GIC390_SPECIAL_IRQ_START) + +#define TARGET_CPU_ALLINT(CPU) \ +( \ + (((CPU) & 0xff) << 0 ) | \ + (((CPU) & 0xff) << 8 ) | \ + (((CPU) & 0xff) << 16) | \ + (((CPU) & 0xff) << 24) \ +) +#define CPU(X) (1<<(X)) +#define TARGET_CPU0_ALLINT TARGET_CPU_ALLINT(CPU(0)) + +/* memory map for GIC distributor */ +struct gic_dist_map +{ + rt_uint32_t enable; /* 0x000 */ + rt_uint32_t ic_type; /* 0x004 */ + rt_uint32_t dist_ident; /* 0x008 */ + rt_uint32_t res1[29]; /* [0x00C, 0x080) */ + + rt_uint32_t security[32]; /* [0x080, 0x100) */ + + rt_uint32_t enable_set[32]; /* [0x100, 0x180) */ + rt_uint32_t enable_clr[32]; /* [0x180, 0x200) */ + rt_uint32_t pending_set[32]; /* [0x200, 0x280) */ + rt_uint32_t pending_clr[32]; /* [0x280, 0x300) */ + rt_uint32_t active[32]; /* [0x300, 0x380) */ + rt_uint32_t res2[32]; /* [0x380, 0x400) */ + + rt_uint32_t priority[255]; /* [0x400, 0x7FC) */ + rt_uint32_t res3; /* 0x7FC */ + + rt_uint32_t targets[255]; /* [0x800, 0xBFC) */ + rt_uint32_t res4; /* 0xBFC */ + + rt_uint32_t config[64]; /* [0xC00, 0xD00) */ + + rt_uint32_t spi[32]; /* [0xD00, 0xD80) */ + rt_uint32_t res5[20]; /* [0xD80, 0xDD0) */ + rt_uint32_t res6; /* 0xDD0 */ + rt_uint32_t legacy_int; /* 0xDD4 */ + rt_uint32_t res7[2]; /* [0xDD8, 0xDE0) */ + rt_uint32_t match_d; /* 0xDE0 */ + rt_uint32_t enable_d; /* 0xDE4 */ + rt_uint32_t res8[70]; /* [0xDE8, 0xF00) */ + + rt_uint32_t sgi_control; /* 0xF00 */ + rt_uint32_t res9[3]; /* [0xF04, 0xF10) */ + rt_uint32_t sgi_pending_clr[4]; /* [0xF10, 0xF20) */ + rt_uint32_t res10[40]; /* [0xF20, 0xFC0) */ + + rt_uint32_t periph_id[12]; /* [0xFC0, 0xFF0) */ + rt_uint32_t component_id[4]; /* [0xFF0, 0xFFF] */ +}; + +/* memory map for GIC CPU interface */ +struct gic_cpu_iface_map +{ + rt_uint32_t icontrol; /* 0x000 */ + rt_uint32_t pri_msk_c; /* 0x004 */ + rt_uint32_t pb_c; /* 0x008 */ + rt_uint32_t int_ack; /* 0x00C */ + rt_uint32_t eoi; /* 0x010 */ + rt_uint32_t run_priority; /* 0x014 */ + rt_uint32_t hi_pend; /* 0x018 */ + rt_uint32_t ns_alias_bp_c; /* 0x01C */ + rt_uint32_t ns_alias_ack; /* 0x020 GIC400 only */ + rt_uint32_t ns_alias_eoi; /* 0x024 GIC400 only */ + rt_uint32_t ns_alias_hi_pend; /* 0x028 GIC400 only */ + + rt_uint32_t res1[5]; /* [0x02C, 0x040) */ + + rt_uint32_t integ_en_c; /* 0x040 PL390 only */ + rt_uint32_t interrupt_out; /* 0x044 PL390 only */ + rt_uint32_t res2[2]; /* [0x048, 0x050) */ + + rt_uint32_t match_c; /* 0x050 PL390 only */ + rt_uint32_t enable_c; /* 0x054 PL390 only */ + + rt_uint32_t res3[30]; /* [0x058, 0x0FC) */ + rt_uint32_t active_priority[4]; /* [0x0D0, 0xDC] GIC400 only */ + rt_uint32_t ns_active_priority[4]; /* [0xE0,0xEC] GIC400 only */ + rt_uint32_t res4[3]; + + rt_uint32_t cpu_if_ident; /* 0x0FC */ + rt_uint32_t res5[948]; /* [0x100. 0xFC0) */ + + rt_uint32_t periph_id[8]; /* [0xFC0, 9xFF0) PL390 only */ + rt_uint32_t component_id[4]; /* [0xFF0, 0xFFF] PL390 only */ +}; + +volatile struct gic_dist_map *gic_dist = + (volatile struct gic_dist_map*)(GIC_PL390_DISTRIBUTOR_PPTR); + +volatile struct gic_cpu_iface_map *gic_cpuiface = + (volatile struct gic_cpu_iface_map*)(GIC_PL390_CONTROLLER_PPTR); + +/* + * The only sane way to get an GIC IRQ number that can be properly + * ACKED later is through the int_ack register. Unfortunately, reading + * this register changes the interrupt state to pending so future + * reads will not return the same value For this reason, we have a + * global variable to store the IRQ number. + */ +static rt_uint32_t active_irq = GIC390_IRQ_NONE; + +rt_inline int is_irq_edge_triggered(int irq) +{ + int word = irq / 16; + int bit = ((irq & 0xf) * 2); + + return !!(gic_dist->config[word] & BIT(bit + 1)); +} + +rt_inline void dist_pending_clr(int irq) +{ + int word = irq / 32; + int bit = irq & 0x1f; + gic_dist->pending_clr[word] = BIT(bit); +} + +rt_inline void dist_init(void) +{ + int i; + int nirqs = 32 * ((gic_dist->ic_type & 0x1f) + 1); + gic_dist->enable = 0; + + for (i = 0; i < nirqs; i += 32) + { + /* disable */ + gic_dist->enable_clr[i / 32] = IRQ_SET_ALL; + /* clear pending */ + gic_dist->pending_clr[i / 32] = IRQ_SET_ALL; + } + + /* reset interrupts priority */ + for (i = 32; i < nirqs; i += 4) + { + gic_dist->priority[i / 4] = 0x0; + } + + /* + * reset int target to cpu 0 + * (Should really query which processor we're running on and use that) + */ + for (i = 0; i < nirqs; i += 4) + { + gic_dist->targets[i / 4] = TARGET_CPU0_ALLINT; + } + + /* level-triggered, 1-N */ + for (i = 64; i < nirqs; i += 32) + { + gic_dist->config[i / 32] = 0; + } + /* enable the int controller */ + gic_dist->enable = 1; +} + +rt_inline void cpu_iface_init(void) +{ + rt_uint32_t i; + + /* For non-Exynos4, the registers are banked per CPU, need to clear them */ + gic_dist->enable_clr[0] = IRQ_SET_ALL; + gic_dist->pending_clr[0] = IRQ_SET_ALL; + gic_dist->priority[0] = 0x00; + /* put everything in group 0 */ + + /* clear any software generated interrupts */ + for (i = 0; i < 16; i += 4) + { + gic_dist->sgi_pending_clr[i / 4] = IRQ_SET_ALL; + } + + gic_cpuiface->icontrol = 0; + gic_cpuiface->pri_msk_c = 0x000000f0; + gic_cpuiface->pb_c = 0x00000003; + + while (((i = gic_cpuiface->int_ack) & IRQ_MASK) != GIC390_IRQ_NONE) + { + gic_cpuiface->eoi = i; + } + gic_cpuiface->icontrol = 0x1; +} + + +void arm_gic_irq_init(void) +{ + dist_init(); + cpu_iface_init(); +} + +int arm_gic_get_active_irq(void) +{ + int irq; + if (!IS_IRQ_VALID(active_irq)) + { + active_irq = gic_cpuiface->int_ack; + } + + if (IS_IRQ_VALID(active_irq)) + { + irq = active_irq & IRQ_MASK; + } + else + { + irq = GIC390_IRQ_NONE; + } + + return irq; +} + +void arm_gic_mask(int irq) +{ + int word = irq / 32; + int bit = irq & 0x1f; + + gic_dist->enable_clr[word] = BIT(bit); +} + +void arm_gic_umask(int irq) +{ + int word = irq / 32; + int bit = irq & 0x1f; + gic_dist->enable_set[word] = BIT(bit); +} + +void arm_gic_ack(int irq) +{ + if (!(IS_IRQ_VALID(active_irq) && (active_irq & IRQ_MASK) == irq)) + { + return; + } + if (is_irq_edge_triggered(irq)) + { + dist_pending_clr(irq); + } + + gic_cpuiface->eoi = active_irq; + active_irq = GIC390_IRQ_NONE; +} + +int rt_hw_interrupt_get_irq(void) +{ + return arm_gic_get_active_irq(); +} + +void rt_hw_interrupt_ack(int fiq_irq) +{ + return arm_gic_ack(fiq_irq); +} + diff --git a/libcpu/aarch64/common/gic/gic_pl390.h b/libcpu/aarch64/common/gic/gic_pl390.h new file mode 100644 index 0000000000..7ea574967d --- /dev/null +++ b/libcpu/aarch64/common/gic/gic_pl390.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2006-2021, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2021-07-31 GuEe-GUI the first version + */ + +#ifndef GIC_PL390_H__ +#define GIC_PL390_H__ + +#include <board.h> + +#define GIC390_SPECIAL_IRQ_START 1020 +#define GIC390_IRQ_NONE 1023 + +void arm_gic_irq_init(void); + +int arm_gic_get_active_irq(void); +void arm_gic_ack(int irq); + +void arm_gic_mask(int irq); +void arm_gic_umask(int irq); + +#endif diff --git a/libcpu/aarch64/cortex-a53/entry_point.S b/libcpu/aarch64/cortex-a53/entry_point.S index 6d2c69226b..552e5916ce 100644 --- a/libcpu/aarch64/cortex-a53/entry_point.S +++ b/libcpu/aarch64/cortex-a53/entry_point.S @@ -35,7 +35,7 @@ _start: // ldr x2, =EL1_stack // mov sp, x2 - ldr x1, =_start + ldr x1, =init_el1_stack_limit // set up EL1 mrs x0, CurrentEL // CurrentEL Register. bit 2, 3. Others reserved @@ -109,3 +109,8 @@ _start: bl entry // for failsafe, halt this core too b .L__current_cpu_idle +.bss +.align 3 +init_el1_stack: + .space 4096 +init_el1_stack_limit: diff --git a/libcpu/aarch64/cortex-a53/interrupt.c b/libcpu/aarch64/cortex-a53/interrupt.c index 4a5d502a3c..ba49be5132 100644 --- a/libcpu/aarch64/cortex-a53/interrupt.c +++ b/libcpu/aarch64/cortex-a53/interrupt.c @@ -9,6 +9,7 @@ * 2019-07-28 zdzn add smp support * 2019-08-09 zhangjun fixup the problem of smp startup and scheduling issues, * write addr to mailbox3 to startup smp, and we use mailbox0 for ipi + * 2021-07-31 GuEe-GUI Add gic pl390 branch */ #include <rthw.h> @@ -19,6 +20,10 @@ #include "armv8.h" #include "interrupt.h" +#ifdef BSP_USING_GIC390 +#include <gic_pl390.h> +#endif + #define MAX_HANDLERS 72 #ifdef RT_USING_SMP @@ -41,6 +46,7 @@ void rt_hw_vector_init(void) rt_hw_set_current_vbar((rt_ubase_t)&system_vectors); // cpu_gcc.S } +#ifndef BSP_USING_GIC static void default_isr_handler(int vector, void *param) { #ifdef RT_USING_SMP @@ -49,12 +55,16 @@ static void default_isr_handler(int vector, void *param) rt_kprintf("unhandled irq: %d\n",vector); #endif } +#endif /** * This function will initialize hardware interrupt */ void rt_hw_interrupt_init(void) { +#ifdef BSP_USING_GIC390 + arm_gic_irq_init(); +#else rt_uint32_t index; /* mask all of interrupts */ @@ -76,6 +86,7 @@ void rt_hw_interrupt_init(void) rt_interrupt_from_thread = 0; rt_interrupt_to_thread = 0; rt_thread_switch_interrupt_flag = 0; +#endif } /** @@ -84,6 +95,9 @@ void rt_hw_interrupt_init(void) */ void rt_hw_interrupt_mask(int vector) { +#ifdef BSP_USING_GIC390 + arm_gic_mask(vector); +#else if (vector < 32) { IRQ_DISABLE1 = (1 << vector); @@ -98,6 +112,7 @@ void rt_hw_interrupt_mask(int vector) vector = vector - 64; IRQ_DISABLE_BASIC = (1 << vector); } +#endif } /** @@ -106,6 +121,9 @@ void rt_hw_interrupt_mask(int vector) */ void rt_hw_interrupt_umask(int vector) { +#ifdef BSP_USING_GIC390 + arm_gic_umask(vector); +#else if (vector < 32) { IRQ_ENABLE1 = (1 << vector); @@ -120,6 +138,7 @@ void rt_hw_interrupt_umask(int vector) vector = vector - 64; IRQ_ENABLE_BASIC = (1 << vector); } +#endif } /** diff --git a/libcpu/aarch64/cortex-a53/interrupt.h b/libcpu/aarch64/cortex-a53/interrupt.h index 94a455550d..72e69bd808 100644 --- a/libcpu/aarch64/cortex-a53/interrupt.h +++ b/libcpu/aarch64/cortex-a53/interrupt.h @@ -14,8 +14,6 @@ #include <rthw.h> #include <board.h> -#include "raspi.h" - #define INT_IRQ 0x00 #define INT_FIQ 0x01 diff --git a/libcpu/aarch64/cortex-a53/trap.c b/libcpu/aarch64/cortex-a53/trap.c index d43e0e4d6a..ca5b6ecd44 100644 --- a/libcpu/aarch64/cortex-a53/trap.c +++ b/libcpu/aarch64/cortex-a53/trap.c @@ -4,7 +4,8 @@ * SPDX-License-Identifier: Apache-2.0 * * Date Author Notes - * 2018-10-06 ZhaoXiaowei the first version + * 2018-10-06 ZhaoXiaowei the first version + * 2021-07-31 GuEe-GUI Add gic_pl390 branch */ #include <rtthread.h> @@ -13,6 +14,10 @@ #include "interrupt.h" #include "armv8.h" +#ifdef BSP_USING_GIC390 +#include <gic_pl390.h> +#endif + extern struct rt_thread *rt_current_thread; #ifdef RT_USING_FINSH extern long list_thread(void); @@ -65,6 +70,8 @@ void rt_hw_trap_irq(void) uint32_t irq; rt_isr_handler_t isr_func; extern struct rt_irq_desc isr_table[]; + +#ifndef BSP_USING_GIC390 uint32_t value = 0; value = IRQ_PEND_BASIC & 0x3ff; #ifdef BSP_USING_CORETIMER @@ -100,6 +107,15 @@ void rt_hw_trap_irq(void) value &= 0x0f; irq = __rt_ffs(value) + 63; } +#else + irq = arm_gic_get_active_irq(); + + if (irq == GIC390_IRQ_NONE) + { + /* Spurious interrupt */ + return; + } +#endif /* get interrupt service routine */ isr_func = isr_table[irq].handler; @@ -113,11 +129,17 @@ void rt_hw_trap_irq(void) /* turn to interrupt service routine */ isr_func(irq, param); } +#ifndef BSP_USING_GIC390 } +#else + /* end of interrupt */ + arm_gic_ack(irq); +#endif } void rt_hw_trap_fiq(void) { +#ifndef BSP_USING_GIC390 void *param; uint32_t irq; rt_isr_handler_t isr_func; @@ -199,4 +221,5 @@ void rt_hw_trap_fiq(void) isr_func(irq, param); } } +#endif } |
