From d905b3df300c1a822e666c5d8bd903ce16f5d507 Mon Sep 17 00:00:00 2001 From: Runyang Chen Date: Thu, 19 Dec 2024 19:53:22 +0800 Subject: [PATCH] feat(mediatek): add gic driver Add GIC driver for taking interrupts to core. Signed-off-by: Runyang Chen Change-Id: Id4d702b8579488befc1a1b6d37e66287dd534798 --- plat/mediatek/drivers/gicv3/mt_gic_v3.c | 187 ++++++++++++++++++++ plat/mediatek/drivers/gicv3/mt_gic_v3.h | 30 ++++ plat/mediatek/drivers/gicv3/rules.mk | 16 ++ plat/mediatek/mt8196/include/platform_def.h | 6 + plat/mediatek/mt8196/platform.mk | 1 + 5 files changed, 240 insertions(+) create mode 100644 plat/mediatek/drivers/gicv3/mt_gic_v3.c create mode 100644 plat/mediatek/drivers/gicv3/mt_gic_v3.h create mode 100644 plat/mediatek/drivers/gicv3/rules.mk diff --git a/plat/mediatek/drivers/gicv3/mt_gic_v3.c b/plat/mediatek/drivers/gicv3/mt_gic_v3.c new file mode 100644 index 000000000..659ca9ca1 --- /dev/null +++ b/plat/mediatek/drivers/gicv3/mt_gic_v3.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2025, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static gicv3_redist_ctx_t rdist_ctx; +static gicv3_dist_ctx_t dist_ctx; + +/* Configure Secure IRQs */ +static const interrupt_prop_t mt_interrupt_props[] = { + PLATFORM_G1S_PROPS(INTR_GROUP1S) +}; + +static unsigned int mt_mpidr_to_core_pos(u_register_t mpidr) +{ + return plat_core_pos_by_mpidr(mpidr); +} + +gicv3_driver_data_t mt_gicv3_data = { + .gicd_base = MT_GIC_BASE, + .gicr_base = MT_GIC_RDIST_BASE, + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = rdistif_base_addrs, + .mpidr_to_core_pos = mt_mpidr_to_core_pos, + .interrupt_props = mt_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(mt_interrupt_props), +}; + +int32_t mt_irq_get_pending(uint32_t irq) +{ + uint32_t val; + + if (!IS_SPI(irq)) + return -EINVAL; + + val = mmio_read_32(BASE_GICD_BASE + GICD_ISPENDR + + irq / 32 * 4); + val = (val >> (irq % 32)) & 1U; + + return (int32_t)val; +} + +int32_t mt_irq_set_pending(uint32_t irq) +{ + uint32_t bit = 1U << (irq % 32); + + if (!IS_SPI(irq)) + return -EINVAL; + + mmio_write_32(BASE_GICD_BASE + GICD_ISPENDR + + irq / 32 * 4, bit); + + return 0; +} + +uint32_t gicr_get_sgi_pending(void) +{ + uint32_t result = 0, ispendr0, proc_num; + + for (proc_num = 0; proc_num < PLATFORM_CORE_COUNT; proc_num++) { + ispendr0 = + gicr_read_ispendr0(MT_GIC_RDIST_BASE + proc_num * SZ_64K * 2); + result |= ((ispendr0 & SGI_MASK) ? 1 : 0) << proc_num; + } + + return result; +} + +void mt_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} + +void mt_gic_distif_save(void) +{ + /* Save the GIC Distributor context */ + gicv3_distif_save(&dist_ctx); +} + +void mt_gic_distif_restore(void) +{ + /* Restore the GIC Distributor context */ + gicv3_distif_init_restore(&dist_ctx); +} + +void mt_gic_rdistif_save(void) +{ + uint32_t cpu; + + /* + * For all cores, save the GIC Redistributors and ITS contexts + * before the Distributor context. + */ + for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) + gicv3_rdistif_save(cpu, &rdist_ctx); +} + +void mt_gic_rdistif_restore(void) +{ + uint32_t cpu; + + /* + * Restore the GIC Redistributor and ITS contexts after the + * Distributor context. As we only handle SYSTEM SUSPEND API, + * we only need to restore the context of the CPU that issued + * the SYSTEM SUSPEND call. + */ + for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) + gicv3_rdistif_init_restore(cpu, &rdist_ctx); +} + +void mt_gic_redistif_on(void) +{ + gicv3_rdistif_on(plat_my_core_pos()); +} + +void mt_gic_redistif_off(void) +{ + gicv3_rdistif_off(plat_my_core_pos()); +} + +void mt_gic_redistif_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} + +void mt_gic_cpuif_enable(void) +{ + gicv3_cpuif_enable(plat_my_core_pos()); +} + +void mt_gic_cpuif_disable(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} +void mt_gic_driver_init(void) +{ + /* + * The GICv3 driver is initialized in EL3 and does not need + * to be initialized again in SEL1. This is because the S-EL1 + * can use GIC system registers to manage interrupts and does + * not need GIC interface base addresses to be configured. + */ +#if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \ + (defined(__aarch64__) && defined(IMAGE_BL31)) + gicv3_driver_init(&mt_gicv3_data); +#endif +} + +void mt_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +int mt_gic_one_init(void) +{ + INFO("[%s] GIC initialization\n", __func__); + + mt_gic_driver_init(); + mt_gic_init(); + + return 0; +} + +MTK_PLAT_SETUP_0_INIT(mt_gic_one_init); diff --git a/plat/mediatek/drivers/gicv3/mt_gic_v3.h b/plat/mediatek/drivers/gicv3/mt_gic_v3.h new file mode 100644 index 000000000..f50b0fd1a --- /dev/null +++ b/plat/mediatek/drivers/gicv3/mt_gic_v3.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2025, MediaTek Inc. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MT_GIC_V3_H +#define MT_GIC_V3_H + +#include +#include + +int32_t mt_irq_get_pending(uint32_t irq); +int32_t mt_irq_set_pending(uint32_t irq); +uint32_t gicr_get_sgi_pending(void); + +void mt_gic_pcpu_init(void); +void mt_gic_distif_save(void); +void mt_gic_distif_restore(void); +void mt_gic_rdistif_save(void); +void mt_gic_rdistif_restore(void); +void mt_gic_redistif_on(void); +void mt_gic_redistif_off(void); +void mt_gic_redistif_init(void); +void mt_gic_cpuif_enable(void); +void mt_gic_cpuif_disable(void); +void mt_gic_driver_init(void); +void mt_gic_init(void); + +#endif /* MT_GIC_V3_H */ diff --git a/plat/mediatek/drivers/gicv3/rules.mk b/plat/mediatek/drivers/gicv3/rules.mk new file mode 100644 index 000000000..c241e6ad0 --- /dev/null +++ b/plat/mediatek/drivers/gicv3/rules.mk @@ -0,0 +1,16 @@ +# +# Copyright (c) 2025, MediaTek Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +LOCAL_DIR := $(call GET_LOCAL_DIR) + +MODULE := gicv3 +LOCAL_SRCS-y := $(LOCAL_DIR)/mt_gic_v3.c + +PLAT_INCLUDES += -I${LOCAL_DIR} \ + -Iinclude/plat/common/ \ + -Idrivers/arm/gic/v3/ \ + +$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL))) diff --git a/plat/mediatek/mt8196/include/platform_def.h b/plat/mediatek/mt8196/include/platform_def.h index 6b6416ac0..68c82bac3 100644 --- a/plat/mediatek/mt8196/include/platform_def.h +++ b/plat/mediatek/mt8196/include/platform_def.h @@ -109,6 +109,12 @@ #define BASE_GICD_BASE (MT_GIC_BASE) #define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x40000) #define MTK_GIC_REG_SIZE 0x400000 +#define SGI_MASK 0xffff +#define DEV_IRQ_ID 982 + +#define PLATFORM_G1S_PROPS(grp) \ + INTR_PROP_DESC(DEV_IRQ_ID, GIC_HIGHEST_SEC_PRIORITY, grp, \ + GIC_INTR_CFG_LEVEL) /******************************************************************************* * MM IOMMU & SMI related constants diff --git a/plat/mediatek/mt8196/platform.mk b/plat/mediatek/mt8196/platform.mk index 8ae8e285d..05e42beba 100644 --- a/plat/mediatek/mt8196/platform.mk +++ b/plat/mediatek/mt8196/platform.mk @@ -28,6 +28,7 @@ MODULES-y += $(MTK_PLAT)/lib/pm MODULES-y += $(MTK_PLAT)/drivers/apusys MODULES-y += $(MTK_PLAT)/drivers/dp MODULES-y += $(MTK_PLAT)/drivers/emi +MODULES-y += $(MTK_PLAT)/drivers/gicv3 MODULES-y += $(MTK_PLAT)/drivers/mcusys MODULES-y += $(MTK_PLAT)/drivers/timer MODULES-y += $(MTK_PLAT)/drivers/vcp