diff options
| author | GUI <[email protected]> | 2022-03-29 11:08:25 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2022-03-29 11:08:25 +0800 |
| commit | f587a55bc2006f4316383425d518b734e42bb4a2 (patch) | |
| tree | 155cc0f274c4cb79d2ed8761e25532abbcabfad2 /libcpu/aarch64 | |
| parent | d23493d05db47bcf066894dd1e1cb43b77a76d54 (diff) | |
[libcpu/aarch64] add gicv3 support and bsp/rockchip/rk3568 (#5722)
* [libcpu/aarch64] add smp support
* [libcpu/aarch64] rt_hw_trap_irq get irq instead of iar when using gicv2
* [libcpu/aarch64] disable irq/fiq when switch thread
* [libcpu/aarch64] add gtimer frq set and stack align
* [libcpu/aarch64] add gicv3 support and bsp/rockchip/rk3568
Diffstat (limited to 'libcpu/aarch64')
| -rw-r--r-- | libcpu/aarch64/common/SConscript | 4 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gic.c | 68 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gic.h | 10 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gicv3.c | 849 | ||||
| -rw-r--r-- | libcpu/aarch64/common/gicv3.h | 77 | ||||
| -rw-r--r-- | libcpu/aarch64/common/interrupt.c | 11 | ||||
| -rw-r--r-- | libcpu/aarch64/common/psci.c | 14 | ||||
| -rw-r--r-- | libcpu/aarch64/common/psci.h | 5 | ||||
| -rw-r--r-- | libcpu/aarch64/cortex-a/entry_point.S | 41 |
9 files changed, 1024 insertions, 55 deletions
diff --git a/libcpu/aarch64/common/SConscript b/libcpu/aarch64/common/SConscript index 915b9d29aa..72fb8e26c3 100644 --- a/libcpu/aarch64/common/SConscript +++ b/libcpu/aarch64/common/SConscript @@ -6,10 +6,6 @@ Import('rtconfig') cwd = GetCurrentDir() src = Glob('*.c') + Glob('*.cpp') + Glob('*.S') - -if not GetDepend('BSP_USING_GIC'): - SrcRemove(src, 'gic.c') - CPPPATH = [cwd] group = DefineGroup('common', src, depend = [''], CPPPATH = CPPPATH) diff --git a/libcpu/aarch64/common/gic.c b/libcpu/aarch64/common/gic.c index 7a2c368d23..95a710c480 100644 --- a/libcpu/aarch64/common/gic.c +++ b/libcpu/aarch64/common/gic.c @@ -9,20 +9,25 @@ * 2014-04-03 Grissiom many enhancements * 2018-11-22 Jesven add rt_hw_ipi_send() * add rt_hw_ipi_handler_install() + * 2022-03-08 GuEe-GUI add BSP bind SPI CPU self support */ #include <rthw.h> #include <rtthread.h> +#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) + #include <gic.h> #include <cpuport.h> +#include <board.h> + struct arm_gic { rt_uint64_t offset; /* the first interrupt index in the vector table */ rt_uint64_t dist_hw_base; /* the base address of the gic distributor */ - rt_uint64_t cpu_hw_base; /* the base addrees of the gic cpu interface */ + rt_uint64_t cpu_hw_base; /* the base address of the gic cpu interface */ }; /* 'ARM_GIC_MAX_NR' is the number of cores */ @@ -30,33 +35,33 @@ 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) HWREG32((hw_base) + 0x00U) +#define GIC_CPU_PRIMASK(hw_base) HWREG32((hw_base) + 0x04U) +#define GIC_CPU_BINPOINT(hw_base) HWREG32((hw_base) + 0x08U) +#define GIC_CPU_INTACK(hw_base) HWREG32((hw_base) + 0x0cU) +#define GIC_CPU_EOI(hw_base) HWREG32((hw_base) + 0x10U) +#define GIC_CPU_RUNNINGPRI(hw_base) HWREG32((hw_base) + 0x14U) +#define GIC_CPU_HIGHPRI(hw_base) HWREG32((hw_base) + 0x18U) +#define GIC_CPU_IIDR(hw_base) HWREG32((hw_base) + 0xFCU) /** 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) HWREG32((hw_base) + 0x000U) +#define GIC_DIST_TYPE(hw_base) HWREG32((hw_base) + 0x004U) +#define GIC_DIST_IGROUP(hw_base, n) HWREG32((hw_base) + 0x080U + ((n)/32U) * 4U) +#define GIC_DIST_ENABLE_SET(hw_base, n) HWREG32((hw_base) + 0x100U + ((n)/32U) * 4U) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x180U + ((n)/32U) * 4U) +#define GIC_DIST_PENDING_SET(hw_base, n) HWREG32((hw_base) + 0x200U + ((n)/32U) * 4U) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) HWREG32((hw_base) + 0x280U + ((n)/32U) * 4U) +#define GIC_DIST_ACTIVE_SET(hw_base, n) HWREG32((hw_base) + 0x300U + ((n)/32U) * 4U) +#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x380U + ((n)/32U) * 4U) +#define GIC_DIST_PRI(hw_base, n) HWREG32((hw_base) + 0x400U + ((n)/4U) * 4U) +#define GIC_DIST_TARGET(hw_base, n) HWREG32((hw_base) + 0x800U + ((n)/4U) * 4U) +#define GIC_DIST_CONFIG(hw_base, n) HWREG32((hw_base) + 0xc00U + ((n)/16U) * 4U) +#define GIC_DIST_SOFTINT(hw_base) HWREG32((hw_base) + 0xf00U) +#define GIC_DIST_CPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf10U + ((n)/4U) * 4U) +#define GIC_DIST_SPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf20U + ((n)/4U) * 4U) +#define GIC_DIST_ICPIDR2(hw_base) HWREG32((hw_base) + 0xfe8U) static unsigned int _gic_max_irq; @@ -179,7 +184,7 @@ void arm_gic_clear_pending_irq(rt_uint64_t index, int irq) } } -void arm_gic_set_configuration(rt_uint64_t index, int irq, uint32_t config) +void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config) { rt_uint64_t icfgr; rt_uint64_t shift; @@ -323,6 +328,8 @@ void arm_gic_send_sgi(rt_uint64_t index, int irq, rt_uint64_t target_list, rt_ui GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL); + + __DSB(); } rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index) @@ -341,8 +348,8 @@ rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index) void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group) { - uint32_t igroupr; - uint32_t shift; + rt_uint32_t igroupr; + rt_uint32_t shift; RT_ASSERT(index < ARM_GIC_MAX_NR); RT_ASSERT(group <= 1U); @@ -373,6 +380,10 @@ int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start) unsigned int gic_type, i; rt_uint64_t cpumask = 1U << 0U; +#ifdef ARM_SPI_BIND_CPU_ID + cpumask = 1U << ARM_SPI_BIND_CPU_ID; +#endif + RT_ASSERT(index < ARM_GIC_MAX_NR); _gic_table[index].dist_hw_base = dist_base; @@ -502,3 +513,4 @@ long gic_dump(void) } MSH_CMD_EXPORT(gic_dump, show gic status); +#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */ diff --git a/libcpu/aarch64/common/gic.h b/libcpu/aarch64/common/gic.h index 54ab2bda18..7ea0d6d3af 100644 --- a/libcpu/aarch64/common/gic.h +++ b/libcpu/aarch64/common/gic.h @@ -11,9 +11,9 @@ #ifndef __GIC_H__ #define __GIC_H__ -#include <rthw.h> -#include <stdint.h> -#include <board.h> +#include <rtdef.h> + +#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) int arm_gic_get_active_irq(rt_uint64_t index); void arm_gic_ack(rt_uint64_t index, int irq); @@ -25,7 +25,7 @@ rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq); void arm_gic_set_pending_irq(rt_uint64_t index, int irq); void arm_gic_clear_pending_irq(rt_uint64_t index, int irq); -void arm_gic_set_configuration(rt_uint64_t index, int irq, uint32_t config); +void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config); rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq); void arm_gic_clear_active(rt_uint64_t index, int irq); @@ -59,5 +59,7 @@ int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base); void arm_gic_dump_type(rt_uint64_t index); void arm_gic_dump(rt_uint64_t index); +#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV2) */ + #endif diff --git a/libcpu/aarch64/common/gicv3.c b/libcpu/aarch64/common/gicv3.c new file mode 100644 index 0000000000..67010f1d57 --- /dev/null +++ b/libcpu/aarch64/common/gicv3.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + * 2014-04-03 Grissiom many enhancements + * 2018-11-22 Jesven add rt_hw_ipi_send() + * add rt_hw_ipi_handler_install() + * 2022-03-08 GuEe-GUI add BSP bind SPI CPU self support + * add GICv3 AArch64 system register interface + * modify arm_gic_redist_init() args + * modify arm_gic_cpu_init() args + * modify arm_gic_send_affinity_sgi() args + * remove arm_gic_redist_address_set() + * remove arm_gic_cpu_interface_address_set() + * remove arm_gic_secondary_cpu_init() + * remove get_main_cpu_affval() + * remove arm_gic_cpumask_to_affval() + */ + +#include <rthw.h> +#include <rtthread.h> + +#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) + +#include <gicv3.h> +#include <cpuport.h> + +#include <board.h> + +#ifndef ARM_SPI_BIND_CPU_ID +#define ARM_SPI_BIND_CPU_ID 0 +#endif + +#ifndef RT_USING_SMP +#define RT_CPUS_NR 1 +extern int rt_hw_cpu_id(void); +#else +extern rt_uint64_t rt_cpu_mpidr_early[]; +#endif /* RT_USING_SMP */ + +struct arm_gic +{ + rt_uint64_t offset; /* the first interrupt index in the vector table */ + rt_uint64_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */ + rt_uint64_t dist_hw_base; /* the base address of the gic distributor */ + rt_uint64_t cpu_hw_base[RT_CPUS_NR]; /* the base address 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 unsigned int _gic_max_irq; + +#define GET_GICV3_REG(reg, out) __asm__ volatile ("mrs %0, " reg:"=r"(out)::"memory"); +#define SET_GICV3_REG(reg, in) __asm__ volatile ("msr " reg ", %0"::"r"(in):"memory"); + +/* AArch64 System register interface to GICv3 */ +#define ICC_IAR0_EL1 "S3_0_C12_C8_0" +#define ICC_IAR1_EL1 "S3_0_C12_C12_0" +#define ICC_EOIR0_EL1 "S3_0_C12_C8_1" +#define ICC_EOIR1_EL1 "S3_0_C12_C12_1" +#define ICC_HPPIR0_EL1 "S3_0_C12_C8_2" +#define ICC_HPPIR1_EL1 "S3_0_C12_C12_2" +#define ICC_BPR0_EL1 "S3_0_C12_C8_3" +#define ICC_BPR1_EL1 "S3_0_C12_C12_3" +#define ICC_DIR_EL1 "S3_0_C12_C11_1" +#define ICC_PMR_EL1 "S3_0_C4_C6_0" +#define ICC_RPR_EL1 "S3_0_C12_C11_3" +#define ICC_CTLR_EL1 "S3_0_C12_C12_4" +#define ICC_CTLR_EL3 "S3_6_C12_C12_4" +#define ICC_SRE_EL1 "S3_0_C12_C12_5" +#define ICC_SRE_EL2 "S3_4_C12_C9_5" +#define ICC_SRE_EL3 "S3_6_C12_C12_5" +#define ICC_IGRPEN0_EL1 "S3_0_C12_C12_6" +#define ICC_IGRPEN1_EL1 "S3_0_C12_C12_7" +#define ICC_IGRPEN1_EL3 "S3_6_C12_C12_7" +#define ICC_SGI0R_EL1 "S3_0_C12_C11_7" +#define ICC_SGI1R_EL1 "S3_0_C12_C11_5" +#define ICC_ASGI1R_EL1 "S3_0_C12_C11_6" + +/* Macro to access the Distributor Control Register (GICD_CTLR) */ +#define GICD_CTLR_RWP (1 << 31) +#define GICD_CTLR_E1NWF (1 << 7) +#define GICD_CTLR_DS (1 << 6) +#define GICD_CTLR_ARE_NS (1 << 5) +#define GICD_CTLR_ARE_S (1 << 4) +#define GICD_CTLR_ENGRP1S (1 << 2) +#define GICD_CTLR_ENGRP1NS (1 << 1) +#define GICD_CTLR_ENGRP0 (1 << 0) + +/* Macro to access the Redistributor Control Register (GICR_CTLR) */ +#define GICR_CTLR_UWP (1 << 31) +#define GICR_CTLR_DPG1S (1 << 26) +#define GICR_CTLR_DPG1NS (1 << 25) +#define GICR_CTLR_DPG0 (1 << 24) +#define GICR_CTLR_RWP (1 << 3) +#define GICR_CTLR_IR (1 << 2) +#define GICR_CTLR_CES (1 << 1) +#define GICR_CTLR_EnableLPI (1 << 0) + +/* Macro to access the Generic Interrupt Controller Interface (GICC) */ +#define GIC_CPU_CTRL(hw_base) HWREG32((hw_base) + 0x00U) +#define GIC_CPU_PRIMASK(hw_base) HWREG32((hw_base) + 0x04U) +#define GIC_CPU_BINPOINT(hw_base) HWREG32((hw_base) + 0x08U) +#define GIC_CPU_INTACK(hw_base) HWREG32((hw_base) + 0x0cU) +#define GIC_CPU_EOI(hw_base) HWREG32((hw_base) + 0x10U) +#define GIC_CPU_RUNNINGPRI(hw_base) HWREG32((hw_base) + 0x14U) +#define GIC_CPU_HIGHPRI(hw_base) HWREG32((hw_base) + 0x18U) +#define GIC_CPU_IIDR(hw_base) HWREG32((hw_base) + 0xFCU) + +/* Macro to access the Generic Interrupt Controller Distributor (GICD) */ +#define GIC_DIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U) +#define GIC_DIST_TYPE(hw_base) HWREG32((hw_base) + 0x004U) +#define GIC_DIST_IGROUP(hw_base, n) HWREG32((hw_base) + 0x080U + ((n) / 32U) * 4U) +#define GIC_DIST_ENABLE_SET(hw_base, n) HWREG32((hw_base) + 0x100U + ((n) / 32U) * 4U) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x180U + ((n) / 32U) * 4U) +#define GIC_DIST_PENDING_SET(hw_base, n) HWREG32((hw_base) + 0x200U + ((n) / 32U) * 4U) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) HWREG32((hw_base) + 0x280U + ((n) / 32U) * 4U) +#define GIC_DIST_ACTIVE_SET(hw_base, n) HWREG32((hw_base) + 0x300U + ((n) / 32U) * 4U) +#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) HWREG32((hw_base) + 0x380U + ((n) / 32U) * 4U) +#define GIC_DIST_PRI(hw_base, n) HWREG32((hw_base) + 0x400U + ((n) / 4U) * 4U) +#define GIC_DIST_TARGET(hw_base, n) HWREG32((hw_base) + 0x800U + ((n) / 4U) * 4U) +#define GIC_DIST_CONFIG(hw_base, n) HWREG32((hw_base) + 0xc00U + ((n) / 16U) * 4U) +#define GIC_DIST_SOFTINT(hw_base) HWREG32((hw_base) + 0xf00U) +#define GIC_DIST_CPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf10U + ((n) / 4U) * 4U) +#define GIC_DIST_SPENDSGI(hw_base, n) HWREG32((hw_base) + 0xf20U + ((n) / 4U) * 4U) +#define GIC_DIST_ICPIDR2(hw_base) HWREG32((hw_base) + 0xfe8U) +#define GIC_DIST_IROUTER(hw_base, n) HWREG64((hw_base) + 0x6000U + (n) * 8U) + +/* SGI base address is at 64K offset from Redistributor base address */ +#define GIC_RSGI_OFFSET 0x10000 + +/* Macro to access the Generic Interrupt Controller Redistributor (GICR) */ +#define GIC_RDIST_CTRL(hw_base) HWREG32((hw_base) + 0x000U) +#define GIC_RDIST_IIDR(hw_base) HWREG32((hw_base) + 0x004U) +#define GIC_RDIST_TYPER(hw_base) HWREG64((hw_base) + 0x008U) +#define GIC_RDIST_TSTATUSR(hw_base) HWREG32((hw_base) + 0x010U) +#define GIC_RDIST_WAKER(hw_base) HWREG32((hw_base) + 0x014U) +#define GIC_RDIST_SETLPIR(hw_base) HWREG32((hw_base) + 0x040U) +#define GIC_RDIST_CLRLPIR(hw_base) HWREG32((hw_base) + 0x048U) +#define GIC_RDIST_PROPBASER(hw_base) HWREG32((hw_base) + 0x070U) +#define GIC_RDIST_PENDBASER(hw_base) HWREG32((hw_base) + 0x078U) +#define GIC_RDIST_INVLPIR(hw_base) HWREG32((hw_base) + 0x0A0U) +#define GIC_RDIST_INVALLR(hw_base) HWREG32((hw_base) + 0x0B0U) +#define GIC_RDIST_SYNCR(hw_base) HWREG32((hw_base) + 0x0C0U) + +#define GIC_RDISTSGI_IGROUPR0(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n) * 4U) +#define GIC_RDISTSGI_ISENABLER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x100U) +#define GIC_RDISTSGI_ICENABLER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x180U) +#define GIC_RDISTSGI_ISPENDR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x200U) +#define GIC_RDISTSGI_ICPENDR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x280U) +#define GIC_RDISTSGI_ISACTIVER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x300U) +#define GIC_RDISTSGI_ICACTIVER0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x380U) +#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U) +#define GIC_RDISTSGI_ICFGR0(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U) +#define GIC_RDISTSGI_ICFGR1(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U) +#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n) * 4) +#define GIC_RDISTSGI_NSACR(hw_base) HWREG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U) + +int arm_gic_get_active_irq(rt_uint64_t index) +{ + int irq; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + GET_GICV3_REG(ICC_IAR1_EL1, irq); + + irq = (irq & 0x1ffffff) + _gic_table[index].offset; + return irq; +} + +void arm_gic_ack(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + RT_ASSERT(irq >= 0); + + __DSB(); + SET_GICV3_REG(ICC_EOIR1_EL1, irq); +} + +void arm_gic_mask(rt_uint64_t index, int irq) +{ + rt_uint64_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq < 32) + { + rt_int32_t cpu_id = rt_hw_cpu_id(); + + GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask; + } + else + { + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + } +} + +void arm_gic_umask(rt_uint64_t index, int irq) +{ + rt_uint64_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq < 32) + { + rt_int32_t cpu_id = rt_hw_cpu_id(); + + GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask; + } + else + { + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; + } +} + +rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq) +{ + rt_uint64_t pend; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq >= 16) + { + pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1; + } + else + { + /* INTID 0-15 Software Generated Interrupt */ + pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff; + /* No CPU identification offered */ + if (pend != 0) + { + pend = 1; + } + else + { + pend = 0; + } + } + + return pend; +} + +void arm_gic_set_pending_irq(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq >= 16) + { + GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1 << (irq % 32); + } + else + { + /* INTID 0-15 Software Generated Interrupt */ + /* Forward the interrupt to the CPU interface that requested it */ + GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000); + } +} + +void arm_gic_clear_pending_irq(rt_uint64_t index, int irq) +{ + rt_uint64_t mask; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq >= 16) + { + mask = 1 << (irq % 32); + GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + } + else + { + mask = 1 << ((irq % 4) * 8); + GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask; + } +} + +void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config) +{ + rt_uint64_t icfgr; + rt_uint64_t shift; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq); + shift = (irq % 16) << 1; + + icfgr &= (~(3 << shift)); + icfgr |= (config << shift); + + GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr; +} + +rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16) >> 1)); +} + +void arm_gic_clear_active(rt_uint64_t index, int irq) +{ + rt_uint64_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +/* Set up the cpu mask for the specific interrupt */ +void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask) +{ + rt_uint64_t old_tgt; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq); + + old_tgt &= ~(0x0ff << ((irq % 4) * 8)); + old_tgt |= cpumask << ((irq % 4) * 8); + + GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt; +} + +rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff; +} + +void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority) +{ + rt_uint64_t mask; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq < 32) + { + rt_int32_t cpu_id = rt_hw_cpu_id(); + + mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq); + mask &= ~(0xff << ((irq % 4) * 8)); + mask |= ((priority & 0xff) << ((irq % 4) * 8)); + GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask; + } + else + { + mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq); + mask &= ~(0xff << ((irq % 4) * 8)); + mask |= ((priority & 0xff) << ((irq % 4) * 8)); + GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask; + } +} + +rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + if (irq < 32) + { + rt_int32_t cpu_id = rt_hw_cpu_id(); + + return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4) * 8)) & 0xff; + } + else + { + return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4) * 8)) & 0xff; + } +} + +void arm_gic_set_system_register_enable_mask(rt_uint64_t index, rt_uint64_t value) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + value &= 0xff; + /* set priority mask */ + SET_GICV3_REG(ICC_SRE_EL1, value); + __ISB(); +} + +rt_uint64_t arm_gic_get_system_register_enable_mask(rt_uint64_t index) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + rt_uint64_t value; + + GET_GICV3_REG(ICC_SRE_EL1, value); + return value; +} + +void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + priority &= 0xff; + /* set priority mask */ + SET_GICV3_REG(ICC_PMR_EL1, priority); +} + +rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + rt_uint64_t priority; + + GET_GICV3_REG(ICC_PMR_EL1, priority); + return priority; +} + +void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point) +{ + index = index; + binary_point &= 0x7; + + SET_GICV3_REG(ICC_BPR1_EL1, binary_point); +} + +rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index) +{ + rt_uint64_t binary_point; + + index = index; + GET_GICV3_REG(ICC_BPR1_EL1, binary_point); + return binary_point; +} + +rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq) +{ + rt_uint64_t pending, active; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1; + pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1; + + return ((active << 1) | pending); +} + +#ifdef RT_USING_SMP +void arm_gic_send_affinity_sgi(rt_uint64_t index, int irq, rt_uint64_t cpu_masks[], rt_uint64_t routing_mode) +{ + const int cpu_mask_cpu_max_nr = sizeof(cpu_masks[0]) * 8; + rt_uint64_t int_id = (irq & 0xf) << 24; + rt_uint64_t irm = routing_mode << 40; /* Interrupt Routing Mode */ + + if (routing_mode == GICV3_ROUTED_TO_SPEC) + { + int cpu_id, cpu_mask_bit, i, cpu_masks_nr = RT_CPUS_NR / cpu_mask_cpu_max_nr; + rt_uint16_t target_list; + rt_uint64_t rs = 0; /* Range Selector */ + rt_uint64_t affinity_val, next_affinity_val; + + if (cpu_masks_nr * cpu_mask_cpu_max_nr != RT_CPUS_NR) + { + ++cpu_masks_nr; + } + + for (i = cpu_id = 0; i < cpu_masks_nr;) + { + /* No cpu in this mask */ + if (cpu_masks[i] == 0) + { + ++i; + cpu_id += cpu_mask_cpu_max_nr; + continue; + } + + /* Get last cpu affinity value */ + affinity_val = rt_cpu_mpidr_early[cpu_id] & 0xff00ffff00ULL; + + /* Read 16 cpus information */ + for (cpu_mask_bit = 0; cpu_mask_bit < 16; ++cpu_mask_bit, ++cpu_id) + { + /* MPIDR_EL1: aff3[39:32], aff2[23:16], aff1[15:8] */ + next_affinity_val = rt_cpu_mpidr_early[cpu_id] & 0xff00ffff00ULL; + + /* Affinity value is different, read end */ + if (affinity_val != next_affinity_val) + { + break; + } + } + + /* Get all valid cpu mask */ + target_list = (0xffff >> (16 - cpu_mask_bit)) & cpu_masks[i]; + /* Clear read mask */ + cpu_masks[i] >>= cpu_mask_bit; + /* ICC_SGI1R_EL1: aff3[55:48], aff2[39:32], aff1[23:16] */ + affinity_val <<= 8; + + __DSB(); + /* Interrupts routed to the PEs specified by Aff3.Aff2.Aff1.<target list>. */ + SET_GICV3_REG(ICC_SGI1R_EL1, affinity_val | (rs << 44) | irm | int_id | target_list); + __ISB(); + + /* Check if reset the range selector */ + rs = affinity_val != next_affinity_val ? 0 : rs + 1; + } + } + else + { + __DSB(); + /* Interrupts routed to all PEs in the system, excluding "self". */ + SET_GICV3_REG(ICC_SGI1R_EL1, irm | int_id); + __ISB(); + } +} +#endif /* RT_USING_SMP */ + +rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index) +{ + rt_uint64_t irq; + RT_ASSERT(index < ARM_GIC_MAX_NR); + + index = index; + GET_GICV3_REG(ICC_HPPIR1_EL1, irq); + + return irq; +} + +rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index) +{ + rt_uint64_t ret = 0; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + if (_gic_table[index].cpu_hw_base != RT_NULL) + { + ret = GIC_CPU_IIDR(_gic_table[index].cpu_hw_base); + } + + return ret; +} + +void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group) +{ + rt_uint64_t igroupr; + rt_uint64_t shift; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + RT_ASSERT(group <= 1); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq); + shift = (irq % 32); + igroupr &= (~(1U << shift)); + igroupr |= ((group & 0x1U) << shift); + + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr; +} + +rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32)) & 0x1UL; +} + +static int arm_gicv3_wait_rwp(rt_uint64_t index, rt_uint64_t irq) +{ + rt_uint64_t rwp_bit; + rt_uint64_t base; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + if (irq < 32) + { + rt_int32_t cpu_id = rt_hw_cpu_id(); + + base = _gic_table[index].redist_hw_base[cpu_id]; + rwp_bit = GICR_CTLR_RWP; + } + else + { + base = _gic_table[index].dist_hw_base; + rwp_bit = GICD_CTLR_RWP; + } + + while (HWREG32(base) & rwp_bit) + { + } + + return 0; +} + +int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start) +{ + int i; + unsigned int gic_type; + rt_uint64_t main_cpu_affinity_val; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].dist_hw_base = dist_base; + _gic_table[index].offset = irq_start; + + + /* Find out how many interrupts are supported. */ + gic_type = GIC_DIST_TYPE(dist_base); + _gic_max_irq = ((gic_type & 0x1f) + 1) * 32; + + /* + * The GIC only supports up to 1020 interrupt sources. + * Limit this to either the architected maximum, or the + * platform maximum. + */ + if (_gic_max_irq > 1020) + { + _gic_max_irq = 1020; + } + if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */ + { + _gic_max_irq = ARM_GIC_NR_IRQS; + } + + GIC_DIST_CTRL(dist_base) = 0; + /* Wait for register write pending */ + arm_gicv3_wait_rwp(0, 32); + + /* Set all global interrupts to be level triggered, active low. */ + for (i = 32; i < _gic_max_irq; i += 16) + { + GIC_DIST_CONFIG(dist_base, i) = 0; + } + + arm_gicv3_wait_rwp(0, 32); + +#ifdef RT_USING_SMP + main_cpu_affinity_val = rt_cpu_mpidr_early[ARM_SPI_BIND_CPU_ID]; +#else + __asm__ volatile ("mrs %0, mpidr_el1":"=r"(main_cpu_affinity_val)); +#endif + + /* aff3[39:32], aff2[23:16], aff1[15:8], aff0[7:0] */ + main_cpu_affinity_val &= 0xff00ffffffULL; + + /* Set all global interrupts to this CPU only. */ + for (i = 32; i < _gic_max_irq; i++) + { + GIC_DIST_IROUTER(dist_base, i) = main_cpu_affinity_val | (GICV3_ROUTED_TO_SPEC << 31); + } + + arm_gicv3_wait_rwp(0, 32); + + /* Set priority on spi interrupts. */ + for (i = 32; i < _gic_max_irq; i += 4) + { + GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0; + } + + arm_gicv3_wait_rwp(0, 32); + /* Disable all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 32) + { + GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffff; + GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff; + } + + arm_gicv3_wait_rwp(0, 32); + /* All interrupts defaults to IGROUP1(IRQ). */ + for (i = 0; i < _gic_max_irq; i += 32) + { + GIC_DIST_IGROUP(dist_base, i) = 0xffffffff; + } + + arm_gicv3_wait_rwp(0, 32); + + /* + * The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode. + * Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled. + * If affinity routing is not enabled, GICv3 can be configured for legacy operation. + * Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state. + * Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1: + * GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts. + * GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts. + * GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts. + */ + GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS; + + return 0; +} + +int arm_gic_redist_init(rt_uint64_t index, rt_uint64_t redist_base) +{ + int i; + int cpu_id = rt_hw_cpu_id(); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + redist_base += cpu_id * (2 << 16); + _gic_table[index].redist_hw_base[cpu_id] = redist_base; + + /* redistributor enable */ + GIC_RDIST_WAKER(redist_base) &= ~(1 << 1); + while (GIC_RDIST_WAKER(redist_base) & (1 << 2)) + { + } + + /* Disable all sgi and ppi interrupt */ + GIC_RDISTSGI_ICENABLER0(redist_base) = 0xffffffff; + arm_gicv3_wait_rwp(0, 0); + + /* Clear all inetrrupt pending */ + GIC_RDISTSGI_ICPENDR0(redist_base) = 0xffffffff; + + /* the corresponding interrupt is Group 1 or Non-secure Group 1. */ + GIC_RDISTSGI_IGROUPR0(redist_base, 0) = 0xffffffff; + GIC_RDISTSGI_IGRPMODR0(redist_base, 0) = 0xffffffff; + + /* Configure default priorities for SGI 0:15 and PPI 16:31. */ + for (i = 0; i < 32; i += 4) + { + GIC_RDISTSGI_IPRIORITYR(redist_base, i) = 0xa0a0a0a0U; + } + + /* Trigger level for PPI interrupts*/ + GIC_RDISTSGI_ICFGR1(redist_base) = 0; + return 0; +} + +int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base) +{ + rt_uint64_t value; + int cpu_id = rt_hw_cpu_id(); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].cpu_hw_base[cpu_id] = cpu_base; + + value = arm_gic_get_system_register_enable_mask(index); + value |= (1 << 0); + arm_gic_set_system_register_enable_mask(index, value); + SET_GICV3_REG(ICC_CTLR_EL1, 0); + + arm_gic_set_interface_prior_mask(index, 0xff); + + /* Enable group1 interrupt */ + value = 1; + SET_GICV3_REG(ICC_IGRPEN1_EL1, value); + + arm_gic_set_binary_point(0, 0); + + /* ICC_BPR0_EL1 determines the preemption group for both Group 0 and Group 1 interrupts. */ + value = 1; /* ICC_BPR0_EL1 determines the preemption group for both Group 0 and Group 1 interrupts.*/ + value |= 1 << 18; /* Targeted SGIs with affinity level 0 values of 0 - 255 are supported. */ + SET_GICV3_REG(ICC_CTLR_EL1, value); + + return 0; +} + +void arm_gic_dump_type(rt_uint64_t index) +{ + unsigned int gic_type; + + gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base); + rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n", + (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf, + _gic_table[index].dist_hw_base, + _gic_max_irq, + gic_type & (1 << 10) ? "has" : "no", + gic_type); +} + +void arm_gic_dump(rt_uint64_t index) +{ + int i; + unsigned int val; + + val = arm_gic_get_high_pending_irq(0); + rt_kprintf("--- high pending priority: %d(%08x)\n", val, val); + + rt_kprintf("--- hw mask ---\n"); + for (i = 0; i < _gic_max_irq / 32; ++i) + { + rt_kprintf("0x%08x, ", GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, i * 32)); + } + + rt_kprintf("\b\b\n--- hw pending ---\n"); + for (i = 0; i < _gic_max_irq / 32; ++i) + { + rt_kprintf("0x%08x, ", GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, i * 32)); + } + + rt_kprintf("\b\b\n--- hw active ---\n"); + for (i = 0; i < _gic_max_irq / 32; ++i) + { + rt_kprintf("0x%08x, ", GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, i * 32)); + } + + rt_kprintf("\b\b\n"); +} + +long gic_dump(void) +{ + arm_gic_dump_type(0); + arm_gic_dump(0); + + return 0; +} +MSH_CMD_EXPORT(gic_dump, show gic status); + +#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) */ diff --git a/libcpu/aarch64/common/gicv3.h b/libcpu/aarch64/common/gicv3.h new file mode 100644 index 0000000000..0cb6bda03a --- /dev/null +++ b/libcpu/aarch64/common/gicv3.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + * 2014-04-03 Grissiom many enhancements + * 2018-11-22 Jesven add rt_hw_ipi_send() + * add rt_hw_ipi_handler_install() + */ + +#ifndef __GICV3_H__ +#define __GICV3_H__ + +#include <rtdef.h> + +#if defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) + +#define GICV3_ROUTED_TO_ALL 1UL +#define GICV3_ROUTED_TO_SPEC 0UL + +int arm_gic_get_active_irq(rt_uint64_t index); +void arm_gic_ack(rt_uint64_t index, int irq); + +void arm_gic_mask(rt_uint64_t index, int irq); +void arm_gic_umask(rt_uint64_t index, int irq); + +rt_uint64_t arm_gic_get_pending_irq(rt_uint64_t index, int irq); +void arm_gic_set_pending_irq(rt_uint64_t index, int irq); +void arm_gic_clear_pending_irq(rt_uint64_t index, int irq); + +void arm_gic_set_configuration(rt_uint64_t index, int irq, rt_uint32_t config); +rt_uint64_t arm_gic_get_configuration(rt_uint64_t index, int irq); + +void arm_gic_clear_active(rt_uint64_t index, int irq); + +void arm_gic_set_cpu(rt_uint64_t index, int irq, unsigned int cpumask); +rt_uint64_t arm_gic_get_target_cpu(rt_uint64_t index, int irq); + +void arm_gic_set_priority(rt_uint64_t index, int irq, rt_uint64_t priority); +rt_uint64_t arm_gic_get_priority(rt_uint64_t index, int irq); + +void arm_gic_set_interface_prior_mask(rt_uint64_t index, rt_uint64_t priority); +rt_uint64_t arm_gic_get_interface_prior_mask(rt_uint64_t index); + +void arm_gic_set_binary_point(rt_uint64_t index, rt_uint64_t binary_point); +rt_uint64_t arm_gic_get_binary_point(rt_uint64_t index); + +rt_uint64_t arm_gic_get_irq_status(rt_uint64_t index, int irq); + +#ifdef RT_USING_SMP +void arm_gic_send_affinity_sgi(rt_uint64_t index, int irq, rt_uint64_t cpu_masks[], rt_uint64_t routing_mode); +#endif + +rt_uint64_t arm_gic_get_high_pending_irq(rt_uint64_t index); + +rt_uint64_t arm_gic_get_interface_id(rt_uint64_t index); + +void arm_gic_set_group(rt_uint64_t index, int irq, rt_uint64_t group); +rt_uint64_t arm_gic_get_group(rt_uint64_t index, int irq); + +int arm_gic_redist_address_set(rt_uint64_t index, rt_uint64_t redist_addr, int cpu_id); +int arm_gic_cpu_interface_address_set(rt_uint64_t index, rt_uint64_t interface_addr, int cpu_id); + +int arm_gic_dist_init(rt_uint64_t index, rt_uint64_t dist_base, int irq_start); +int arm_gic_redist_init(rt_uint64_t index, rt_uint64_t redist_base); +int arm_gic_cpu_init(rt_uint64_t index, rt_uint64_t cpu_base); + +void arm_gic_dump_type(rt_uint64_t index); +void arm_gic_dump(rt_uint64_t index); + +#endif /* defined(BSP_USING_GIC) && defined(BSP_USING_GICV3) */ + +#endif + diff --git a/libcpu/aarch64/common/interrupt.c b/libcpu/aarch64/common/interrupt.c index f31003b2c0..c5db2d46af 100644 --- a/libcpu/aarch64/common/interrupt.c +++ b/libcpu/aarch64/common/interrupt.c @@ -13,6 +13,7 @@ #include <rtthread.h> #include "interrupt.h" #include "gic.h" +#include "gicv3.h" #include "armv8.h" #include "mmu.h" #include "cpuport.h" @@ -52,6 +53,9 @@ void rt_hw_interrupt_init(void) /* initialize ARM GIC */ arm_gic_dist_init(0, platform_get_gic_dist_base(), GIC_IRQ_START); arm_gic_cpu_init(0, platform_get_gic_cpu_base()); +#ifdef BSP_USING_GICV3 + arm_gic_redist_init(0, platform_get_gic_redist_base()); +#endif #endif } @@ -346,8 +350,12 @@ rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask) { #ifdef BSP_USING_GIC +#ifdef BSP_USING_GICV2 arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0); #else + arm_gic_send_affinity_sgi(0, ipi_vector, (rt_uint64_t *)&cpu_mask, GICV3_ROUTED_TO_SPEC); +#endif +#else int i; __DSB(); @@ -359,8 +367,9 @@ void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask) IPI_MAILBOX_SET(i) = 1 << ipi_vector; } } -#endif + __DSB(); +#endif } void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler) diff --git a/libcpu/aarch64/common/psci.c b/libcpu/aarch64/common/psci.c index 400db977ee..65e84ebf0a 100644 --- a/libcpu/aarch64/common/psci.c +++ b/libcpu/aarch64/common/psci.c @@ -29,11 +29,19 @@ static psci_call_handle psci_call = psci_smc_call; static uint64_t shutdown_args[3] = {0, 0, 0}; static uint64_t reboot_args[3] = {0, 0, 0}; -void arm_psci_init(uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args) +void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args) { - if (rt_hw_get_current_el() < 2) + switch (method) { - psci_call = psci_hvc_call; + case PSCI_METHOD_SMC: + psci_call = psci_smc_call; + break; + case PSCI_METHOD_HVC: + if (rt_hw_get_current_el() < 2) + { + psci_call = psci_hvc_call; + } + break; } if (platform_shutdown_args != RT_NULL) diff --git a/libcpu/aarch64/common/psci.h b/libcpu/aarch64/common/psci.h index e8b2e3129d..999489a801 100644 --- a/libcpu/aarch64/common/psci.h +++ b/libcpu/aarch64/common/psci.h @@ -18,6 +18,9 @@ */ #define PSCI_VER_0_2 0x00000002 +#define PSCI_METHOD_SMC 3 +#define PSCI_METHOD_HVC 2 + /* PSCI 0.2 interface */ #define PSCI_0_2_FN_BASE 0x84000000 #define PSCI_0_2_FN(n) (PSCI_0_2_FN_BASE + (n)) @@ -114,7 +117,7 @@ #define PSCI_RET_DISABLED (-8) #define PSCI_RET_INVALID_ADDRESS (-9) -void arm_psci_init(uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args); +void arm_psci_init(uint64_t method, uint64_t *platform_shutdown_args, uint64_t *platform_reboot_args); uint32_t arm_psci_get_version(); uint32_t arm_psci_get_affinity_info(uint64_t target_affinity, uint64_t lowest_affinity_level); diff --git a/libcpu/aarch64/cortex-a/entry_point.S b/libcpu/aarch64/cortex-a/entry_point.S index 5bf2b8a3a6..c605a41631 100644 --- a/libcpu/aarch64/cortex-a/entry_point.S +++ b/libcpu/aarch64/cortex-a/entry_point.S @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2020, RT-Thread Development Team + * Copyright (c) 2006-2022, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * @@ -11,19 +11,28 @@ */ #include "rtconfig.h" -.section ".text.entrypoint","ax" #define SECONDARY_STACK_SIZE 4096 +.section ".text.entrypoint","ax" + .globl _start .globl secondary_cpu_start _start: +#ifdef RT_USING_SMP mrs x1, mpidr_el1 - and x1, x1, #0xff - cbnz x1, cpu_idle /* If cpu id > 0, stop slave cores */ + adr x4, .boot_cpu_mpidr + str x1, [x4] + dsb sy +#endif + + bl __asm_flush_dcache_all /* The kernel and data must flush to DDR */ secondary_cpu_start: #ifdef RT_USING_SMP + adr x4, .boot_cpu_mpidr + ldr x4, [x4] + dsb sy /* Read cpu mpidr_el1 */ mrs x1, mpidr_el1 @@ -34,6 +43,7 @@ secondary_cpu_start: cpu_id_confirm: add x2, x2, #1 /* Next cpu id inc */ ldr x3, [x0], #8 + dsb sy cmp x3, #0 beq cpu_idle /* Mean that `rt_cpu_mpidr_early' table is end */ cmp x3, x1 @@ -42,7 +52,8 @@ cpu_id_confirm: /* Get cpu id success */ sub x0, x2, #1 msr tpidr_el1, x0 /* Save cpu id global */ - cbz x0, cpu_setup /* Only go to cpu_setup when cpu id = 0 */ + cmp x3, x4 /* If it is boot cpu */ + beq boot_cpu_setup /* Set current cpu's stack top */ sub x0, x0, #1 @@ -53,14 +64,9 @@ cpu_id_confirm: b cpu_check_el #else msr tpidr_el1, xzr - b cpu_setup #endif /* RT_USING_SMP */ -cpu_idle: - wfe - b cpu_idle - -cpu_setup: +boot_cpu_setup: ldr x1, =_start cpu_check_el: @@ -75,7 +81,7 @@ cpu_check_el: mov x2, #(1 << 0) /* EL0 and EL1 are in Non-Secure state */ orr x2, x2, #(1 << 4) /* RES1 */ orr x2, x2, #(1 << 5) /* RES1 */ - orr x2, x2, #(1 << 7) /* SMC instructions are undefined at EL1 and above */ + bic x2, x2, #(1 << 7) /* SMC instructions are enabled at EL1 and above */ orr x2, x2, #(1 << 8) /* HVC instructions are enabled at EL1 and above */ orr x2, x2, #(1 << 10) /* The next lower level is AArch64 */ msr scr_el3, x2 @@ -91,7 +97,7 @@ cpu_check_el: eret cpu_not_in_el3: /* Running at EL2 or EL1 */ - cmp x0, #4 /* EL1 = 0100 */ + cmp x0, #4 /* EL1 = 0100 */ beq cpu_in_el1 cpu_in_el2: @@ -159,9 +165,16 @@ clean_bss_check: jump_to_entry: b rtthread_startup - b cpu_idle /* For failsafe, halt this core too */ + +cpu_idle: + wfe + b cpu_idle #ifdef RT_USING_SMP +.align 3 +.boot_cpu_mpidr: + .quad 0x0 + .align 12 .secondary_cpu_stack: .space (SECONDARY_STACK_SIZE * (RT_CPUS_NR - 1)) |
