diff options
Diffstat (limited to 'drivers/arm/gic')
-rw-r--r-- | drivers/arm/gic/common/gic_common.c | 4 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicdv2_helpers.c | 340 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicv2.mk | 15 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicv2_helpers.c | 3 | ||||
-rw-r--r-- | drivers/arm/gic/v2/gicv2_main.c | 25 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gic-x00.c | 174 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gic500.c | 22 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gic600.c | 140 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gic600_multichip_private.h | 14 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicdv3_helpers.c | 244 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicrv3_helpers.c | 139 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3.mk | 38 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_helpers.c | 495 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 547 | ||||
-rw-r--r-- | drivers/arm/gic/v3/gicv3_private.h | 438 |
15 files changed, 1905 insertions, 733 deletions
diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c index 38b2f6719..bf6405f7f 100644 --- a/drivers/arm/gic/common/gic_common.c +++ b/drivers/arm/gic/common/gic_common.c @@ -1,9 +1,11 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ +#pragma message __FILE__ " is deprecated, use gicv2.mk instead" + #include <assert.h> #include <drivers/arm/gic_common.h> diff --git a/drivers/arm/gic/v2/gicdv2_helpers.c b/drivers/arm/gic/v2/gicdv2_helpers.c new file mode 100644 index 000000000..db9ba87c4 --- /dev/null +++ b/drivers/arm/gic/v2/gicdv2_helpers.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <drivers/arm/gic_common.h> +#include <lib/mmio.h> + +#include "../common/gic_common_private.h" + +/******************************************************************************* + * GIC Distributor interface accessors for reading entire registers + ******************************************************************************/ +/* + * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt + * `id`, 32 interrupt ids at a time. + */ +unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> IGROUPR_SHIFT; + + return mmio_read_32(base + GICD_IGROUPR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISENABLER corresponding to the + * interrupt `id`, 32 interrupt ids at a time. + */ +unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ISENABLER_SHIFT; + + return mmio_read_32(base + GICD_ISENABLER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ICENABLER_SHIFT; + + return mmio_read_32(base + GICD_ICENABLER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ISPENDR_SHIFT; + + return mmio_read_32(base + GICD_ISPENDR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ICPENDR_SHIFT; + + return mmio_read_32(base + GICD_ICPENDR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ISACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ISACTIVER_SHIFT; + + return mmio_read_32(base + GICD_ISACTIVER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ICACTIVER_SHIFT; + + return mmio_read_32(base + GICD_ICACTIVER + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> IPRIORITYR_SHIFT; + + return mmio_read_32(base + GICD_IPRIORITYR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor ICGFR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> ICFGR_SHIFT; + + return mmio_read_32(base + GICD_ICFGR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor NSACR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id) +{ + unsigned int n = id >> NSACR_SHIFT; + + return mmio_read_32(base + GICD_NSACR + (n << 2)); +} + +/******************************************************************************* + * GIC Distributor interface accessors for writing entire registers + ******************************************************************************/ +/* + * Accessor to write the GIC Distributor IGROUPR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> IGROUPR_SHIFT; + + mmio_write_32(base + GICD_IGROUPR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ISENABLER_SHIFT; + + mmio_write_32(base + GICD_ISENABLER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICENABLER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ICENABLER_SHIFT; + + mmio_write_32(base + GICD_ICENABLER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ISPENDR_SHIFT; + + mmio_write_32(base + GICD_ISPENDR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICPENDR corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ICPENDR_SHIFT; + + mmio_write_32(base + GICD_ICPENDR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ISACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ISACTIVER_SHIFT; + + mmio_write_32(base + GICD_ISACTIVER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICACTIVER corresponding to the + * interrupt `id`, 32 interrupt IDs at a time. + */ +void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ICACTIVER_SHIFT; + + mmio_write_32(base + GICD_ICACTIVER + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor IPRIORITYR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> IPRIORITYR_SHIFT; + + mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor ICFGR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> ICFGR_SHIFT; + + mmio_write_32(base + GICD_ICFGR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor NSACR corresponding to the + * interrupt `id`, 16 interrupt IDs at a time. + */ +void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned int n = id >> NSACR_SHIFT; + + mmio_write_32(base + GICD_NSACR + (n << 2), val); +} + +/******************************************************************************* + * GIC Distributor functions for accessing the GIC registers + * corresponding to a single interrupt ID. These functions use bitwise + * operations or appropriate register accesses to modify or return + * the bit-field corresponding the single interrupt ID. + ******************************************************************************/ +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); + unsigned int reg_val = gicd_read_igroupr(base, id); + + return (reg_val >> bit_num) & 0x1U; +} + +void gicd_set_igroupr(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val | (1U << bit_num)); +} + +void gicd_clr_igroupr(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val & ~(1U << bit_num)); +} + +void gicd_set_isenabler(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U); + + gicd_write_isenabler(base, id, (1U << bit_num)); +} + +void gicd_set_icenabler(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U); + + gicd_write_icenabler(base, id, (1U << bit_num)); +} + +void gicd_set_ispendr(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U); + + gicd_write_ispendr(base, id, (1U << bit_num)); +} + +void gicd_set_icpendr(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U); + + gicd_write_icpendr(base, id, (1U << bit_num)); +} + +unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); + unsigned int reg_val = gicd_read_isactiver(base, id); + + return (reg_val >> bit_num) & 0x1U; +} + +void gicd_set_isactiver(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); + + gicd_write_isactiver(base, id, (1U << bit_num)); +} + +void gicd_set_icactiver(uintptr_t base, unsigned int id) +{ + unsigned int bit_num = id & ((1U << ICACTIVER_SHIFT) - 1U); + + gicd_write_icactiver(base, id, (1U << bit_num)); +} + +void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) +{ + uint8_t val = pri & GIC_PRI_MASK; + + mmio_write_8(base + GICD_IPRIORITYR + id, val); +} + +void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg) +{ + /* Interrupt configuration is a 2-bit field */ + unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); + unsigned int bit_shift = bit_num << 1; + + uint32_t reg_val = gicd_read_icfgr(base, id); + + /* Clear the field, and insert required configuration */ + reg_val &= ~(GIC_CFG_MASK << bit_shift); + reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); + + gicd_write_icfgr(base, id, reg_val); +} diff --git a/drivers/arm/gic/v2/gicv2.mk b/drivers/arm/gic/v2/gicv2.mk new file mode 100644 index 000000000..49996bb51 --- /dev/null +++ b/drivers/arm/gic/v2/gicv2.mk @@ -0,0 +1,15 @@ +# +# Copyright (c) 2020, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# No support for extended PPI and SPI range +GIC_EXT_INTID := 0 + +GICV2_SOURCES += drivers/arm/gic/v2/gicv2_main.c \ + drivers/arm/gic/v2/gicv2_helpers.c \ + drivers/arm/gic/v2/gicdv2_helpers.c + +# Set GICv2 build option +$(eval $(call add_define,GIC_EXT_INTID))
\ No newline at end of file diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c index 6739a782c..751316c03 100644 --- a/drivers/arm/gic/v2/gicv2_helpers.c +++ b/drivers/arm/gic/v2/gicv2_helpers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,7 +7,6 @@ #include <assert.h> #include <arch.h> -#include <arch_helpers.h> #include <common/debug.h> #include <common/interrupt_props.h> #include <drivers/arm/gic_common.h> diff --git a/drivers/arm/gic/v2/gicv2_main.c b/drivers/arm/gic/v2/gicv2_main.c index c5bced00d..939d09718 100644 --- a/drivers/arm/gic/v2/gicv2_main.c +++ b/drivers/arm/gic/v2/gicv2_main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -247,6 +247,15 @@ void gicv2_end_of_interrupt(unsigned int id) assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); + /* + * Ensure the write to peripheral registers are *complete* before the write + * to GIC_EOIR. + * + * Note: The completion gurantee depends on various factors of system design + * and the barrier is the best core can do by which execution of further + * instructions waits till the barrier is alive. + */ + dsbishst(); gicc_write_EOIR(driver_data->gicc_base, id); } @@ -287,8 +296,8 @@ void gicv2_set_pe_target_mask(unsigned int proc_num) assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(driver_data->target_masks != NULL); - assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); - assert((unsigned int)proc_num < driver_data->target_masks_num); + assert(proc_num < GICV2_MAX_TARGET_PE); + assert(proc_num < driver_data->target_masks_num); /* Return if the target mask is already populated */ if (driver_data->target_masks[proc_num] != 0U) @@ -413,7 +422,8 @@ void gicv2_raise_sgi(int sgi_num, int proc_num) unsigned int sgir_val, target; assert(driver_data != NULL); - assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); + assert(proc_num >= 0); + assert(proc_num < (int)GICV2_MAX_TARGET_PE); assert(driver_data->gicd_base != 0U); /* @@ -421,7 +431,7 @@ void gicv2_raise_sgi(int sgi_num, int proc_num) * should be valid. */ assert(driver_data->target_masks != NULL); - assert((unsigned int)proc_num < driver_data->target_masks_num); + assert(proc_num < (int)driver_data->target_masks_num); /* Don't raise SGI if the mask hasn't been populated */ target = driver_data->target_masks[proc_num]; @@ -457,8 +467,9 @@ void gicv2_set_spi_routing(unsigned int id, int proc_num) * should be valid. */ assert(driver_data->target_masks != NULL); - assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); - assert((unsigned int)proc_num < driver_data->target_masks_num); + assert(proc_num < (int)GICV2_MAX_TARGET_PE); + assert(driver_data->target_masks_num < INT_MAX); + assert(proc_num < (int)driver_data->target_masks_num); if (proc_num < 0) { /* Target all PEs */ diff --git a/drivers/arm/gic/v3/gic-x00.c b/drivers/arm/gic/v3/gic-x00.c new file mode 100644 index 000000000..6e106babf --- /dev/null +++ b/drivers/arm/gic/v3/gic-x00.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Driver for GIC-500 and GIC-600 specific features. This driver only + * overrides APIs that are different to those generic ones in GICv3 + * driver. + * + * GIC-600 supports independently power-gating redistributor interface. + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <drivers/arm/gicv3.h> + +#include "gicv3_private.h" + +/* GIC-600 specific register offsets */ +#define GICR_PWRR 0x24U +#define IIDR_MODEL_ARM_GIC_600 U(0x0200043b) +#define IIDR_MODEL_ARM_GIC_600AE U(0x0300043b) +#define IIDR_MODEL_ARM_GIC_CLAYTON U(0x0400043b) + +/* GICR_PWRR fields */ +#define PWRR_RDPD_SHIFT 0 +#define PWRR_RDAG_SHIFT 1 +#define PWRR_RDGPD_SHIFT 2 +#define PWRR_RDGPO_SHIFT 3 + +#define PWRR_RDPD (1U << PWRR_RDPD_SHIFT) +#define PWRR_RDAG (1U << PWRR_RDAG_SHIFT) +#define PWRR_RDGPD (1U << PWRR_RDGPD_SHIFT) +#define PWRR_RDGPO (1U << PWRR_RDGPO_SHIFT) + +/* + * Values to write to GICR_PWRR register to power redistributor + * for operating through the core (GICR_PWRR.RDAG = 0) + */ +#define PWRR_ON (0U << PWRR_RDPD_SHIFT) +#define PWRR_OFF (1U << PWRR_RDPD_SHIFT) + +#if GICV3_SUPPORT_GIC600 + +/* GIC-600/Clayton specific accessor functions */ +static void gicr_write_pwrr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_PWRR, val); +} + +static uint32_t gicr_read_pwrr(uintptr_t base) +{ + return mmio_read_32(base + GICR_PWRR); +} + +static void gicr_wait_group_not_in_transit(uintptr_t base) +{ + uint32_t pwrr; + + do { + pwrr = gicr_read_pwrr(base); + + /* Check group not transitioning: RDGPD == RDGPO */ + } while (((pwrr & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) != + ((pwrr & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT)); +} + +static void gic600_pwr_on(uintptr_t base) +{ + do { /* Wait until group not transitioning */ + gicr_wait_group_not_in_transit(base); + + /* Power on redistributor */ + gicr_write_pwrr(base, PWRR_ON); + + /* + * Wait until the power on state is reflected. + * If RDPD == 0 then powered on. + */ + } while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON); +} + +static void gic600_pwr_off(uintptr_t base) +{ + /* Wait until group not transitioning */ + gicr_wait_group_not_in_transit(base); + + /* Power off redistributor */ + gicr_write_pwrr(base, PWRR_OFF); + + /* + * If this is the last man, turning this redistributor frame off will + * result in the group itself being powered off and RDGPD = 1. + * In that case, wait as long as it's in transition, or has aborted + * the transition altogether for any reason. + */ + if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0U) { + /* Wait until group not transitioning */ + gicr_wait_group_not_in_transit(base); + } +} + +static uintptr_t get_gicr_base(unsigned int proc_num) +{ + uintptr_t gicr_base; + + assert(gicv3_driver_data != NULL); + assert(proc_num < gicv3_driver_data->rdistif_num); + assert(gicv3_driver_data->rdistif_base_addrs != NULL); + + gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + assert(gicr_base != 0UL); + + return gicr_base; +} + +static bool gicv3_redists_need_power_mgmt(uintptr_t gicr_base) +{ + uint32_t reg = mmio_read_32(gicr_base + GICR_IIDR); + + /* + * The Arm GIC-600 and GIC-Clayton models have their redistributors + * powered down at reset. + */ + return (((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) || + ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600AE) || + ((reg & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_CLAYTON)); +} + +#endif /* GICV3_SUPPORT_GIC600 */ + +void gicv3_distif_pre_save(unsigned int proc_num) +{ + arm_gicv3_distif_pre_save(proc_num); +} + +void gicv3_distif_post_restore(unsigned int proc_num) +{ + arm_gicv3_distif_post_restore(proc_num); +} + +/* + * Power off GIC-600 redistributor (if configured and detected) + */ +void gicv3_rdistif_off(unsigned int proc_num) +{ +#if GICV3_SUPPORT_GIC600 + uintptr_t gicr_base = get_gicr_base(proc_num); + + /* Attempt to power redistributor off */ + if (gicv3_redists_need_power_mgmt(gicr_base)) { + gic600_pwr_off(gicr_base); + } +#endif +} + +/* + * Power on GIC-600 redistributor (if configured and detected) + */ +void gicv3_rdistif_on(unsigned int proc_num) +{ +#if GICV3_SUPPORT_GIC600 + uintptr_t gicr_base = get_gicr_base(proc_num); + + /* Power redistributor on */ + if (gicv3_redists_need_power_mgmt(gicr_base)) { + gic600_pwr_on(gicr_base); + } +#endif +} diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c deleted file mode 100644 index f03e33f86..000000000 --- a/drivers/arm/gic/v3/gic500.c +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * Driver for GIC500-specific features. This driver only overrides APIs that are - * different to those generic ones in GICv3 driver. - */ -#include "gicv3_private.h" - -void gicv3_distif_pre_save(unsigned int proc_num) -{ - arm_gicv3_distif_pre_save(proc_num); -} - -void gicv3_distif_post_restore(unsigned int proc_num) -{ - arm_gicv3_distif_post_restore(proc_num); -} - diff --git a/drivers/arm/gic/v3/gic600.c b/drivers/arm/gic/v3/gic600.c deleted file mode 100644 index 59652da63..000000000 --- a/drivers/arm/gic/v3/gic600.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -/* - * Driver for GIC-600 specific features. This driver only overrides - * APIs that are different to those generic ones in GICv3 driver. - * - * GIC-600 supports independently power-gating redistributor interface. - */ - -#include <assert.h> - -#include <arch_helpers.h> -#include <drivers/arm/gicv3.h> - -#include "gicv3_private.h" - -/* GIC-600 specific register offsets */ -#define GICR_PWRR 0x24 - -/* GICR_PWRR fields */ -#define PWRR_RDPD_SHIFT 0 -#define PWRR_RDAG_SHIFT 1 -#define PWRR_RDGPD_SHIFT 2 -#define PWRR_RDGPO_SHIFT 3 - -#define PWRR_RDPD (1 << PWRR_RDPD_SHIFT) -#define PWRR_RDAG (1 << PWRR_RDAG_SHIFT) -#define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT) -#define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT) - -/* - * Values to write to GICR_PWRR register to power redistributor - * for operating through the core (GICR_PWRR.RDAG = 0) - */ -#define PWRR_ON (0 << PWRR_RDPD_SHIFT) -#define PWRR_OFF (1 << PWRR_RDPD_SHIFT) - -/* GIC-600 specific accessor functions */ -static void gicr_write_pwrr(uintptr_t base, unsigned int val) -{ - mmio_write_32(base + GICR_PWRR, val); -} - -static uint32_t gicr_read_pwrr(uintptr_t base) -{ - return mmio_read_32(base + GICR_PWRR); -} - -static void gicr_wait_group_not_in_transit(uintptr_t base) -{ - /* Check group not transitioning: RDGPD == RDGPO */ - while (((gicr_read_pwrr(base) & PWRR_RDGPD) >> PWRR_RDGPD_SHIFT) != - ((gicr_read_pwrr(base) & PWRR_RDGPO) >> PWRR_RDGPO_SHIFT)) - ; -} - -static void gic600_pwr_on(uintptr_t base) -{ - do { /* Wait until group not transitioning */ - gicr_wait_group_not_in_transit(base); - - /* Power on redistributor */ - gicr_write_pwrr(base, PWRR_ON); - - /* - * Wait until the power on state is reflected. - * If RDPD == 0 then powered on. - */ - } while ((gicr_read_pwrr(base) & PWRR_RDPD) != PWRR_ON); -} - -static void gic600_pwr_off(uintptr_t base) -{ - /* Wait until group not transitioning */ - gicr_wait_group_not_in_transit(base); - - /* Power off redistributor */ - gicr_write_pwrr(base, PWRR_OFF); - - /* - * If this is the last man, turning this redistributor frame off will - * result in the group itself being powered off and RDGPD = 1. - * In that case, wait as long as it's in transition, or has aborted - * the transition altogether for any reason. - */ - if ((gicr_read_pwrr(base) & PWRR_RDGPD) != 0) { - /* Wait until group not transitioning */ - gicr_wait_group_not_in_transit(base); - } -} - -void gicv3_distif_pre_save(unsigned int proc_num) -{ - arm_gicv3_distif_pre_save(proc_num); -} - -void gicv3_distif_post_restore(unsigned int proc_num) -{ - arm_gicv3_distif_post_restore(proc_num); -} - -/* - * Power off GIC-600 redistributor - */ -void gicv3_rdistif_off(unsigned int proc_num) -{ - uintptr_t gicr_base; - - assert(gicv3_driver_data); - assert(proc_num < gicv3_driver_data->rdistif_num); - assert(gicv3_driver_data->rdistif_base_addrs); - - gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; - assert(gicr_base); - - /* Attempt to power redistributor off */ - gic600_pwr_off(gicr_base); -} - -/* - * Power on GIC-600 redistributor - */ -void gicv3_rdistif_on(unsigned int proc_num) -{ - uintptr_t gicr_base; - - assert(gicv3_driver_data); - assert(proc_num < gicv3_driver_data->rdistif_num); - assert(gicv3_driver_data->rdistif_base_addrs); - - gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; - assert(gicr_base); - - /* Power redistributor on */ - gic600_pwr_on(gicr_base); -} diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h index b0217b6d4..fe4134cba 100644 --- a/drivers/arm/gic/v3/gic600_multichip_private.h +++ b/drivers/arm/gic/v3/gic600_multichip_private.h @@ -24,11 +24,21 @@ /* GIC600 GICD multichip related shifts */ #define GICD_CHIPRx_ADDR_SHIFT 16 -#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 10 -#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 5 #define GICD_CHIPSR_RTS_SHIFT 4 #define GICD_DCHIPR_RT_OWNER_SHIFT 4 +/* + * If GIC v4 extension is enabled, then use SPI macros specific to GIC-Clayton. + * Other shifts and mask remains same between GIC-600 and GIC-Clayton. + */ +#if GIC_ENABLE_V4_EXTN +#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 9 +#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 3 +#else +#define GICD_CHIPRx_SPI_BLOCK_MIN_SHIFT 10 +#define GICD_CHIPRx_SPI_BLOCKS_SHIFT 5 +#endif + #define GICD_CHIPSR_RTS_STATE_DISCONNECTED U(0) #define GICD_CHIPSR_RTS_STATE_UPDATING U(1) #define GICD_CHIPSR_RTS_STATE_CONSISTENT U(2) diff --git a/drivers/arm/gic/v3/gicdv3_helpers.c b/drivers/arm/gic/v3/gicdv3_helpers.c new file mode 100644 index 000000000..987be69e7 --- /dev/null +++ b/drivers/arm/gic/v3/gicdv3_helpers.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include "gicv3_private.h" + +/******************************************************************************* + * GIC Distributor functions for accessing the GIC registers + * corresponding to a single interrupt ID. These functions use bitwise + * operations or appropriate register accesses to modify or return + * the bit-field corresponding the single interrupt ID. + ******************************************************************************/ + +/* + * Accessors to set the bits corresponding to interrupt ID + * in GIC Distributor ICFGR and ICFGRE. + */ +void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg) +{ + /* Interrupt configuration is a 2-bit field */ + unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U; + + /* Clear the field, and insert required configuration */ + mmio_clrsetbits_32(base + GICD_OFFSET(ICFG, id), + (uint32_t)GIC_CFG_MASK << bit_shift, + (cfg & GIC_CFG_MASK) << bit_shift); +} + +/* + * Accessors to get/set/clear the bit corresponding to interrupt ID + * in GIC Distributor IGROUPR and IGROUPRE. + */ +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id) +{ + return GICD_GET_BIT(IGROUP, base, id); +} + +void gicd_set_igroupr(uintptr_t base, unsigned int id) +{ + GICD_SET_BIT(IGROUP, base, id); +} + +void gicd_clr_igroupr(uintptr_t base, unsigned int id) +{ + GICD_CLR_BIT(IGROUP, base, id); +} + +/* + * Accessors to get/set/clear the bit corresponding to interrupt ID + * in GIC Distributor IGRPMODR and IGRPMODRE. + */ +unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id) +{ + return GICD_GET_BIT(IGRPMOD, base, id); +} + +void gicd_set_igrpmodr(uintptr_t base, unsigned int id) +{ + GICD_SET_BIT(IGRPMOD, base, id); +} + +void gicd_clr_igrpmodr(uintptr_t base, unsigned int id) +{ + GICD_CLR_BIT(IGRPMOD, base, id); +} + +/* + * Accessors to set the bit corresponding to interrupt ID + * in GIC Distributor ICENABLER and ICENABLERE. + */ +void gicd_set_icenabler(uintptr_t base, unsigned int id) +{ + GICD_WRITE_BIT(ICENABLE, base, id); +} + +/* + * Accessors to set the bit corresponding to interrupt ID + * in GIC Distributor ICPENDR and ICPENDRE. + */ +void gicd_set_icpendr(uintptr_t base, unsigned int id) +{ + GICD_WRITE_BIT(ICPEND, base, id); +} + +/* + * Accessors to get/set the bit corresponding to interrupt ID + * in GIC Distributor ISACTIVER and ISACTIVERE. + */ +unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id) +{ + return GICD_GET_BIT(ISACTIVE, base, id); +} + +void gicd_set_isactiver(uintptr_t base, unsigned int id) +{ + GICD_WRITE_BIT(ISACTIVE, base, id); +} + +/* + * Accessors to set the bit corresponding to interrupt ID + * in GIC Distributor ISENABLER and ISENABLERE. + */ +void gicd_set_isenabler(uintptr_t base, unsigned int id) +{ + GICD_WRITE_BIT(ISENABLE, base, id); +} + +/* + * Accessors to set the bit corresponding to interrupt ID + * in GIC Distributor ISPENDR and ISPENDRE. + */ +void gicd_set_ispendr(uintptr_t base, unsigned int id) +{ + GICD_WRITE_BIT(ISPEND, base, id); +} + +/* + * Accessors to set the bit corresponding to interrupt ID + * in GIC Distributor IPRIORITYR and IPRIORITYRE. + */ +void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) +{ + GICD_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK)); +} + +/******************************************************************************* + * GIC Distributor interface accessors for reading/writing entire registers + ******************************************************************************/ + +/* + * Accessors to read/write the GIC Distributor ICGFR and ICGFRE + * corresponding to the interrupt ID, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id) +{ + return GICD_READ(ICFG, base, id); +} + +void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(ICFG, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor IGROUPR and IGROUPRE + * corresponding to the interrupt ID, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id) +{ + return GICD_READ(IGROUP, base, id); +} + +void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(IGROUP, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor IGRPMODR and IGRPMODRE + * corresponding to the interrupt ID, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id) +{ + return GICD_READ(IGRPMOD, base, id); +} + +void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(IGRPMOD, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor IPRIORITYR and IPRIORITYRE + * corresponding to the interrupt ID, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id) +{ + return GICD_READ(IPRIORITY, base, id); +} + +void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(IPRIORITY, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor ISACTIVER and ISACTIVERE + * corresponding to the interrupt ID, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id) +{ + return GICD_READ(ISACTIVE, base, id); +} + +void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(ISACTIVE, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor ISENABLER and ISENABLERE + * corresponding to the interrupt ID, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) +{ + return GICD_READ(ISENABLE, base, id); +} + +void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(ISENABLE, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor ISPENDR and ISPENDRE + * corresponding to the interrupt ID, 32 interrupt IDs at a time. + */ +unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id) +{ + return GICD_READ(ISPEND, base, id); +} + +void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(ISPEND, base, id, val); +} + +/* + * Accessors to read/write the GIC Distributor NSACR and NSACRE + * corresponding to the interrupt ID, 16 interrupt IDs at a time. + */ +unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id) +{ + return GICD_READ(NSAC, base, id); +} + +void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICD_WRITE(NSAC, base, id, val); +} diff --git a/drivers/arm/gic/v3/gicrv3_helpers.c b/drivers/arm/gic/v3/gicrv3_helpers.c new file mode 100644 index 000000000..3004054ee --- /dev/null +++ b/drivers/arm/gic/v3/gicrv3_helpers.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2015-2020, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <common/interrupt_props.h> +#include <drivers/arm/gicv3.h> +#include "gicv3_private.h" + +/******************************************************************************* + * GIC Redistributor functions + * Note: The raw register values correspond to multiple interrupt `id`s and + * the number of interrupt `id`s involved depends on the register accessed. + ******************************************************************************/ + +/* + * Accessors to read/write the GIC Redistributor IPRIORITYR and IPRIORITYRE + * register corresponding to the interrupt `id`, 4 interrupts IDs at a time. + */ +unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id) +{ + return GICR_READ(IPRIORITY, base, id); +} + +void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) +{ + GICR_WRITE(IPRIORITY, base, id, val); +} + +/* + * Accessor to set the byte corresponding to interrupt `id` + * in GIC Redistributor IPRIORITYR and IPRIORITYRE. + */ +void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) +{ + GICR_WRITE_8(IPRIORITY, base, id, (uint8_t)(pri & GIC_PRI_MASK)); +} + +/* + * Accessors to get/set/clear the bit corresponding to interrupt `id` + * from GIC Redistributor IGROUPR0 and IGROUPRE + */ +unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id) +{ + return GICR_GET_BIT(IGROUP, base, id); +} + +void gicr_set_igroupr(uintptr_t base, unsigned int id) +{ + GICR_SET_BIT(IGROUP, base, id); +} + +void gicr_clr_igroupr(uintptr_t base, unsigned int id) +{ + GICR_CLR_BIT(IGROUP, base, id); +} + +/* + * Accessors to get/set/clear the bit corresponding to interrupt `id` + * from GIC Redistributor IGRPMODR0 and IGRPMODRE + */ +unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id) +{ + return GICR_GET_BIT(IGRPMOD, base, id); +} + +void gicr_set_igrpmodr(uintptr_t base, unsigned int id) +{ + GICR_SET_BIT(IGRPMOD, base, id); +} + +void gicr_clr_igrpmodr(uintptr_t base, unsigned int id) +{ + GICR_CLR_BIT(IGRPMOD, base, id); +} + +/* + * Accessor to write the bit corresponding to interrupt `id` + * in GIC Redistributor ISENABLER0 and ISENABLERE + */ +void gicr_set_isenabler(uintptr_t base, unsigned int id) +{ + GICR_WRITE_BIT(ISENABLE, base, id); +} + +/* + * Accessor to write the bit corresponding to interrupt `id` + * in GIC Redistributor ICENABLER0 and ICENABLERE + */ +void gicr_set_icenabler(uintptr_t base, unsigned int id) +{ + GICR_WRITE_BIT(ICENABLE, base, id); +} + +/* + * Accessor to get the bit corresponding to interrupt `id` + * in GIC Redistributor ISACTIVER0 and ISACTIVERE + */ +unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id) +{ + return GICR_GET_BIT(ISACTIVE, base, id); +} + +/* + * Accessor to clear the bit corresponding to interrupt `id` + * in GIC Redistributor ICPENDR0 and ICPENDRE + */ +void gicr_set_icpendr(uintptr_t base, unsigned int id) +{ + GICR_WRITE_BIT(ICPEND, base, id); +} + +/* + * Accessor to write the bit corresponding to interrupt `id` + * in GIC Redistributor ISPENDR0 and ISPENDRE + */ +void gicr_set_ispendr(uintptr_t base, unsigned int id) +{ + GICR_WRITE_BIT(ISPEND, base, id); +} + +/* + * Accessor to set the bit fields corresponding to interrupt `id` + * in GIC Redistributor ICFGR0, ICFGR1 and ICFGRE + */ +void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg) +{ + /* Interrupt configuration is a 2-bit field */ + unsigned int bit_shift = BIT_NUM(ICFG, id) << 1U; + + /* Clear the field, and insert required configuration */ + mmio_clrsetbits_32(base + GICR_OFFSET(ICFG, id), + (uint32_t)GIC_CFG_MASK << bit_shift, + (cfg & GIC_CFG_MASK) << bit_shift); +} diff --git a/drivers/arm/gic/v3/gicv3.mk b/drivers/arm/gic/v3/gicv3.mk new file mode 100644 index 000000000..a2fc16f9c --- /dev/null +++ b/drivers/arm/gic/v3/gicv3.mk @@ -0,0 +1,38 @@ +# +# Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Default configuration values +GICV3_SUPPORT_GIC600 ?= 0 +GICV3_IMPL_GIC600_MULTICHIP ?= 0 +GICV3_OVERRIDE_DISTIF_PWR_OPS ?= 0 +GIC_ENABLE_V4_EXTN ?= 0 +GIC_EXT_INTID ?= 0 + +GICV3_SOURCES += drivers/arm/gic/v3/gicv3_main.c \ + drivers/arm/gic/v3/gicv3_helpers.c \ + drivers/arm/gic/v3/gicdv3_helpers.c \ + drivers/arm/gic/v3/gicrv3_helpers.c + +ifeq (${GICV3_OVERRIDE_DISTIF_PWR_OPS}, 0) +GICV3_SOURCES += drivers/arm/gic/v3/arm_gicv3_common.c +endif + +GICV3_SOURCES += drivers/arm/gic/v3/gic-x00.c +ifeq (${GICV3_IMPL_GIC600_MULTICHIP}, 1) +GICV3_SOURCES += drivers/arm/gic/v3/gic600_multichip.c +endif + +# Set GIC-600 support +$(eval $(call assert_boolean,GICV3_SUPPORT_GIC600)) +$(eval $(call add_define,GICV3_SUPPORT_GIC600)) + +# Set GICv4 extension +$(eval $(call assert_boolean,GIC_ENABLE_V4_EXTN)) +$(eval $(call add_define,GIC_ENABLE_V4_EXTN)) + +# Set support for extended PPI and SPI range +$(eval $(call assert_boolean,GIC_EXT_INTID)) +$(eval $(call add_define,GIC_EXT_INTID)) diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c index 710532e3c..ff346f9df 100644 --- a/drivers/arm/gic/v3/gicv3_helpers.c +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -15,263 +15,6 @@ #include "../common/gic_common_private.h" #include "gicv3_private.h" -/* - * Accessor to read the GIC Distributor IGRPMODR corresponding to the - * interrupt `id`, 32 interrupt IDs at a time. - */ -unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id) -{ - unsigned int n = id >> IGRPMODR_SHIFT; - - return mmio_read_32(base + GICD_IGRPMODR + (n << 2)); -} - -/* - * Accessor to write the GIC Distributor IGRPMODR corresponding to the - * interrupt `id`, 32 interrupt IDs at a time. - */ -void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val) -{ - unsigned int n = id >> IGRPMODR_SHIFT; - - mmio_write_32(base + GICD_IGRPMODR + (n << 2), val); -} - -/* - * Accessor to get the bit corresponding to interrupt ID - * in GIC Distributor IGRPMODR. - */ -unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicd_read_igrpmodr(base, id); - - return (reg_val >> bit_num) & 0x1U; -} - -/* - * Accessor to set the bit corresponding to interrupt ID - * in GIC Distributor IGRPMODR. - */ -void gicd_set_igrpmodr(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicd_read_igrpmodr(base, id); - - gicd_write_igrpmodr(base, id, reg_val | (1U << bit_num)); -} - -/* - * Accessor to clear the bit corresponding to interrupt ID - * in GIC Distributor IGRPMODR. - */ -void gicd_clr_igrpmodr(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicd_read_igrpmodr(base, id); - - gicd_write_igrpmodr(base, id, reg_val & ~(1U << bit_num)); -} - -/* - * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the - * interrupt `id`, 4 interrupts IDs at a time. - */ -unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id) -{ - unsigned int n = id >> IPRIORITYR_SHIFT; - - return mmio_read_32(base + GICR_IPRIORITYR + (n << 2)); -} - -/* - * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the - * interrupt `id`, 4 interrupts IDs at a time. - */ -void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) -{ - unsigned int n = id >> IPRIORITYR_SHIFT; - - mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val); -} - -/* - * Accessor to get the bit corresponding to interrupt ID - * from GIC Re-distributor IGROUPR0. - */ -unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igroupr0(base); - - return (reg_val >> bit_num) & 0x1U; -} - -/* - * Accessor to set the bit corresponding to interrupt ID - * in GIC Re-distributor IGROUPR0. - */ -void gicr_set_igroupr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igroupr0(base); - - gicr_write_igroupr0(base, reg_val | (1U << bit_num)); -} - -/* - * Accessor to clear the bit corresponding to interrupt ID - * in GIC Re-distributor IGROUPR0. - */ -void gicr_clr_igroupr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igroupr0(base); - - gicr_write_igroupr0(base, reg_val & ~(1U << bit_num)); -} - -/* - * Accessor to get the bit corresponding to interrupt ID - * from GIC Re-distributor IGRPMODR0. - */ -unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igrpmodr0(base); - - return (reg_val >> bit_num) & 0x1U; -} - -/* - * Accessor to set the bit corresponding to interrupt ID - * in GIC Re-distributor IGRPMODR0. - */ -void gicr_set_igrpmodr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igrpmodr0(base); - - gicr_write_igrpmodr0(base, reg_val | (1U << bit_num)); -} - -/* - * Accessor to clear the bit corresponding to interrupt ID - * in GIC Re-distributor IGRPMODR0. - */ -void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); - unsigned int reg_val = gicr_read_igrpmodr0(base); - - gicr_write_igrpmodr0(base, reg_val & ~(1U << bit_num)); -} - -/* - * Accessor to set the bit corresponding to interrupt ID - * in GIC Re-distributor ISENABLER0. - */ -void gicr_set_isenabler0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U); - - gicr_write_isenabler0(base, (1U << bit_num)); -} - -/* - * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor - * ICENABLER0. - */ -void gicr_set_icenabler0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U); - - gicr_write_icenabler0(base, (1U << bit_num)); -} - -/* - * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor - * ISACTIVER0. - */ -unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); - unsigned int reg_val = gicr_read_isactiver0(base); - - return (reg_val >> bit_num) & 0x1U; -} - -/* - * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor - * ICPENDRR0. - */ -void gicr_set_icpendr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U); - - gicr_write_icpendr0(base, (1U << bit_num)); -} - -/* - * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor - * ISPENDR0. - */ -void gicr_set_ispendr0(uintptr_t base, unsigned int id) -{ - unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U); - - gicr_write_ispendr0(base, (1U << bit_num)); -} - -/* - * Accessor to set the byte corresponding to interrupt ID - * in GIC Re-distributor IPRIORITYR. - */ -void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) -{ - uint8_t val = pri & GIC_PRI_MASK; - - mmio_write_8(base + GICR_IPRIORITYR + id, val); -} - -/* - * Accessor to set the bit fields corresponding to interrupt ID - * in GIC Re-distributor ICFGR0. - */ -void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg) -{ - /* Interrupt configuration is a 2-bit field */ - unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); - unsigned int bit_shift = bit_num << 1U; - - uint32_t reg_val = gicr_read_icfgr0(base); - - /* Clear the field, and insert required configuration */ - reg_val &= ~(GIC_CFG_MASK << bit_shift); - reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); - - gicr_write_icfgr0(base, reg_val); -} - -/* - * Accessor to set the bit fields corresponding to interrupt ID - * in GIC Re-distributor ICFGR1. - */ -void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg) -{ - /* Interrupt configuration is a 2-bit field */ - unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); - unsigned int bit_shift = bit_num << 1U; - - uint32_t reg_val = gicr_read_icfgr1(base); - - /* Clear the field, and insert required configuration */ - reg_val &= ~(GIC_CFG_MASK << bit_shift); - reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); - - gicr_write_icfgr1(base, reg_val); -} - /****************************************************************************** * This function marks the core as awake in the re-distributor and * ensures that the interface is active. @@ -288,11 +31,10 @@ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 0 */ - while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U) - ; + while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U) { + } } - /****************************************************************************** * This function marks the core as asleep in the re-distributor and ensures * that the interface is quiescent. @@ -303,11 +45,10 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base) gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 1 */ - while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) - ; + while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) { + } } - /******************************************************************************* * This function probes the Redistributor frames when the driver is initialised * and saves their base addresses. These base addresses are used later to @@ -342,47 +83,78 @@ void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, TYPER_PROC_NUM_MASK; } - if (proc_num < rdistif_num) + if (proc_num < rdistif_num) { rdistif_base_addrs[proc_num] = rdistif_base; + } rdistif_base += (1U << GICR_PCPUBASE_SHIFT); } while ((typer_val & TYPER_LAST_BIT) == 0U); } /******************************************************************************* - * Helper function to configure the default attributes of SPIs. + * Helper function to configure the default attributes of (E)SPIs. ******************************************************************************/ void gicv3_spis_config_defaults(uintptr_t gicd_base) { - unsigned int index, num_ints; + unsigned int i, num_ints; +#if GIC_EXT_INTID + unsigned int num_eints; +#endif + unsigned int typer_reg = gicd_read_typer(gicd_base); + + /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */ + num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5; + + /* Treat all (E)SPIs as G1NS by default. We do 32 at a time. */ + for (i = MIN_SPI_ID; i < num_ints; i += (1U << IGROUPR_SHIFT)) { + gicd_write_igroupr(gicd_base, i, ~0U); + } - num_ints = gicd_read_typer(gicd_base); - num_ints &= TYPER_IT_LINES_NO_MASK; - num_ints = (num_ints + 1U) << 5; +#if GIC_EXT_INTID + /* Check if extended SPI range is implemented */ + if ((typer_reg & TYPER_ESPI) != 0U) { + /* + * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095 + */ + num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) & + TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID - 1; - /* - * Treat all SPIs as G1NS by default. The number of interrupts is - * calculated as 32 * (IT_LINES + 1). We do 32 at a time. - */ - for (index = MIN_SPI_ID; index < num_ints; index += 32U) - gicd_write_igroupr(gicd_base, index, ~0U); + for (i = MIN_ESPI_ID; i < num_eints; + i += (1U << IGROUPR_SHIFT)) { + gicd_write_igroupr(gicd_base, i, ~0U); + } + } else { + num_eints = 0U; + } +#endif - /* Setup the default SPI priorities doing four at a time */ - for (index = MIN_SPI_ID; index < num_ints; index += 4U) - gicd_write_ipriorityr(gicd_base, - index, - GICD_IPRIORITYR_DEF_VAL); + /* Setup the default (E)SPI priorities doing four at a time */ + for (i = MIN_SPI_ID; i < num_ints; i += (1U << IPRIORITYR_SHIFT)) { + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + } +#if GIC_EXT_INTID + for (i = MIN_ESPI_ID; i < num_eints; + i += (1U << IPRIORITYR_SHIFT)) { + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + } +#endif /* - * Treat all SPIs as level triggered by default, write 16 at - * a time + * Treat all (E)SPIs as level triggered by default, write 16 at a time */ - for (index = MIN_SPI_ID; index < num_ints; index += 16U) - gicd_write_icfgr(gicd_base, index, 0U); + for (i = MIN_SPI_ID; i < num_ints; i += (1U << ICFGR_SHIFT)) { + gicd_write_icfgr(gicd_base, i, 0U); + } + +#if GIC_EXT_INTID + for (i = MIN_ESPI_ID; i < num_eints; i += (1U << ICFGR_SHIFT)) { + gicd_write_icfgr(gicd_base, i, 0U); + } +#endif } /******************************************************************************* - * Helper function to configure properties of secure SPIs + * Helper function to configure properties of secure (E)SPIs ******************************************************************************/ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, @@ -394,80 +166,108 @@ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ - if (interrupt_props_num > 0U) + if (interrupt_props_num > 0U) { assert(interrupt_props != NULL); + } for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; - if (current_prop->intr_num < MIN_SPI_ID) + unsigned int intr_num = current_prop->intr_num; + + /* Skip SGI, (E)PPI and LPI interrupts */ + if (!IS_SPI(intr_num)) { continue; + } /* Configure this interrupt as a secure interrupt */ - gicd_clr_igroupr(gicd_base, current_prop->intr_num); + gicd_clr_igroupr(gicd_base, intr_num); /* Configure this interrupt as G0 or a G1S interrupt */ assert((current_prop->intr_grp == INTR_GROUP0) || (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) { - gicd_set_igrpmodr(gicd_base, current_prop->intr_num); + gicd_set_igrpmodr(gicd_base, intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { - gicd_clr_igrpmodr(gicd_base, current_prop->intr_num); + gicd_clr_igrpmodr(gicd_base, intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set interrupt configuration */ - gicd_set_icfgr(gicd_base, current_prop->intr_num, - current_prop->intr_cfg); + gicd_set_icfgr(gicd_base, intr_num, current_prop->intr_cfg); /* Set the priority of this interrupt */ - gicd_set_ipriorityr(gicd_base, current_prop->intr_num, - current_prop->intr_pri); + gicd_set_ipriorityr(gicd_base, intr_num, + current_prop->intr_pri); - /* Target SPIs to the primary CPU */ + /* Target (E)SPIs to the primary CPU */ gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0U); - gicd_write_irouter(gicd_base, current_prop->intr_num, - gic_affinity_val); + gicd_write_irouter(gicd_base, intr_num, + gic_affinity_val); /* Enable this interrupt */ - gicd_set_isenabler(gicd_base, current_prop->intr_num); + gicd_set_isenabler(gicd_base, intr_num); } return ctlr_enable; } /******************************************************************************* - * Helper function to configure the default attributes of SPIs. + * Helper function to configure the default attributes of (E)SPIs ******************************************************************************/ void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base) { - unsigned int index; - + unsigned int i, ppi_regs_num, regs_num; + +#if GIC_EXT_INTID + /* Calculate number of PPI registers */ + ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >> + TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1; + /* All other values except PPInum [0-2] are reserved */ + if (ppi_regs_num > 3U) { + ppi_regs_num = 1U; + } +#else + ppi_regs_num = 1U; +#endif /* - * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a - * more scalable approach as it avoids clearing the enable bits in the - * GICD_CTLR + * Disable all SGIs (imp. def.)/(E)PPIs before configuring them. + * This is a more scalable approach as it avoids clearing + * the enable bits in the GICD_CTLR. */ - gicr_write_icenabler0(gicr_base, ~0U); + for (i = 0U; i < ppi_regs_num; ++i) { + gicr_write_icenabler(gicr_base, i, ~0U); + } + + /* Wait for pending writes to GICR_ICENABLER */ gicr_wait_for_pending_write(gicr_base); - /* Treat all SGIs/PPIs as G1NS by default. */ - gicr_write_igroupr0(gicr_base, ~0U); + /* 32 interrupt IDs per GICR_IGROUPR register */ + for (i = 0U; i < ppi_regs_num; ++i) { + /* Treat all SGIs/(E)PPIs as G1NS by default */ + gicr_write_igroupr(gicr_base, i, ~0U); + } - /* Setup the default PPI/SGI priorities doing four at a time */ - for (index = 0U; index < MIN_SPI_ID; index += 4U) - gicr_write_ipriorityr(gicr_base, - index, - GICD_IPRIORITYR_DEF_VAL); + /* 4 interrupt IDs per GICR_IPRIORITYR register */ + regs_num = ppi_regs_num << 3; + for (i = 0U; i < regs_num; ++i) { + /* Setup the default (E)PPI/SGI priorities doing 4 at a time */ + gicr_write_ipriorityr(gicr_base, i, GICD_IPRIORITYR_DEF_VAL); + } - /* Configure all PPIs as level triggered by default */ - gicr_write_icfgr1(gicr_base, 0U); + /* 16 interrupt IDs per GICR_ICFGR register */ + regs_num = ppi_regs_num << 1; + for (i = (MIN_PPI_ID >> ICFGR_SHIFT); i < regs_num; ++i) { + /* Configure all (E)PPIs as level triggered by default */ + gicr_write_icfgr(gicr_base, i, 0U); + } } /******************************************************************************* - * Helper function to configure properties of secure G0 and G1S PPIs and SGIs. + * Helper function to configure properties of secure G0 and G1S (E)PPIs and SGIs ******************************************************************************/ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, const interrupt_prop_t *interrupt_props, @@ -478,46 +278,81 @@ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ - if (interrupt_props_num > 0U) + if (interrupt_props_num > 0U) { assert(interrupt_props != NULL); + } for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; - if (current_prop->intr_num >= MIN_SPI_ID) + unsigned int intr_num = current_prop->intr_num; + + /* Skip (E)SPI interrupt */ + if (!IS_SGI_PPI(intr_num)) { continue; + } /* Configure this interrupt as a secure interrupt */ - gicr_clr_igroupr0(gicr_base, current_prop->intr_num); + gicr_clr_igroupr(gicr_base, intr_num); /* Configure this interrupt as G0 or a G1S interrupt */ assert((current_prop->intr_grp == INTR_GROUP0) || - (current_prop->intr_grp == INTR_GROUP1S)); + (current_prop->intr_grp == INTR_GROUP1S)); + if (current_prop->intr_grp == INTR_GROUP1S) { - gicr_set_igrpmodr0(gicr_base, current_prop->intr_num); + gicr_set_igrpmodr(gicr_base, intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { - gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num); + gicr_clr_igrpmodr(gicr_base, intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set the priority of this interrupt */ - gicr_set_ipriorityr(gicr_base, current_prop->intr_num, - current_prop->intr_pri); + gicr_set_ipriorityr(gicr_base, intr_num, + current_prop->intr_pri); /* - * Set interrupt configuration for PPIs. Configuration for SGIs - * are ignored. + * Set interrupt configuration for (E)PPIs. + * Configurations for SGIs 0-15 are ignored. */ - if ((current_prop->intr_num >= MIN_PPI_ID) && - (current_prop->intr_num < MIN_SPI_ID)) { - gicr_set_icfgr1(gicr_base, current_prop->intr_num, + if (intr_num >= MIN_PPI_ID) { + gicr_set_icfgr(gicr_base, intr_num, current_prop->intr_cfg); } /* Enable this interrupt */ - gicr_set_isenabler0(gicr_base, current_prop->intr_num); + gicr_set_isenabler(gicr_base, intr_num); } return ctlr_enable; } + +/** + * gicv3_rdistif_get_number_frames() - determine size of GICv3 GICR region + * @gicr_frame: base address of the GICR region to check + * + * This iterates over the GICR_TYPER registers of multiple GICR frames in + * a GICR region, to find the instance which has the LAST bit set. For most + * systems this corresponds to the number of cores handled by a redistributor, + * but there could be disabled cores among them. + * It assumes that each GICR region is fully accessible (till the LAST bit + * marks the end of the region). + * If a platform has multiple GICR regions, this function would need to be + * called multiple times, providing the respective GICR base address each time. + * + * Return: number of valid GICR frames (at least 1, up to PLATFORM_CORE_COUNT) + ******************************************************************************/ +unsigned int gicv3_rdistif_get_number_frames(const uintptr_t gicr_frame) +{ + uintptr_t rdistif_base = gicr_frame; + unsigned int count; + + for (count = 1; count < PLATFORM_CORE_COUNT; count++) { + if ((gicr_read_typer(rdistif_base) & TYPER_LAST_BIT) != 0U) { + break; + } + rdistif_base += (1U << GICR_PCPUBASE_SHIFT); + } + + return count; +} diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index a672b18f3..22efd458d 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -31,26 +31,62 @@ static spinlock_t gic_lock; #pragma weak gicv3_rdistif_off #pragma weak gicv3_rdistif_on +/* Check interrupt ID for SGI/(E)PPI and (E)SPIs */ +static bool is_sgi_ppi(unsigned int id); + +/* + * Helper macros to save and restore GICR and GICD registers + * corresponding to their numbers to and from the context + */ +#define RESTORE_GICR_REG(base, ctx, name, i) \ + gicr_write_##name((base), (i), (ctx)->gicr_##name[(i)]) + +#define SAVE_GICR_REG(base, ctx, name, i) \ + (ctx)->gicr_##name[(i)] = gicr_read_##name((base), (i)) /* Helper macros to save and restore GICD registers to and from the context */ #define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG) \ do { \ - for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \ - int_id += (1U << REG##_SHIFT)) { \ - gicd_write_##reg(base, int_id, \ - ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \ + for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num);\ + int_id += (1U << REG##R_SHIFT)) { \ + gicd_write_##reg((base), int_id, \ + (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \ + REG##R_SHIFT]); \ } \ } while (false) #define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG) \ do { \ - for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \ - int_id += (1U << REG##_SHIFT)) { \ - ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\ - gicd_read_##reg(base, int_id); \ + for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num);\ + int_id += (1U << REG##R_SHIFT)) { \ + (ctx)->gicd_##reg[(int_id - MIN_SPI_ID) >> \ + REG##R_SHIFT] = gicd_read_##reg((base), int_id); \ } \ } while (false) +#if GIC_EXT_INTID +#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG) \ + do { \ + for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\ + int_id += (1U << REG##R_SHIFT)) { \ + gicd_write_##reg((base), int_id, \ + (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - MIN_SPI_ID))\ + >> REG##R_SHIFT]); \ + } \ + } while (false) + +#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG) \ + do { \ + for (unsigned int int_id = MIN_ESPI_ID; int_id < (intr_num);\ + int_id += (1U << REG##R_SHIFT)) { \ + (ctx)->gicd_##reg[(int_id - (MIN_ESPI_ID - MIN_SPI_ID))\ + >> REG##R_SHIFT] = gicd_read_##reg((base), int_id);\ + } \ + } while (false) +#else +#define SAVE_GICD_EREGS(base, ctx, intr_num, reg, REG) +#define RESTORE_GICD_EREGS(base, ctx, intr_num, reg, REG) +#endif /* GIC_EXT_INTID */ /******************************************************************************* * This function initialises the ARM GICv3 driver in EL3 with provided platform @@ -80,12 +116,20 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U); #endif /* !__aarch64__ */ - /* The GIC version should be 3.0 */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); gic_version >>= PIDR2_ARCH_REV_SHIFT; gic_version &= PIDR2_ARCH_REV_MASK; - assert(gic_version == ARCH_REV_GICV3); + /* Check GIC version */ +#if GIC_ENABLE_V4_EXTN + assert(gic_version == ARCH_REV_GICV4); + + /* GICv4 supports Direct Virtual LPI injection */ + assert((gicd_read_typer(plat_driver_data->gicd_base) + & TYPER_DVIS) != 0); +#else + assert(gic_version == ARCH_REV_GICV3); +#endif /* * Find out whether the GIC supports the GICv2 compatibility mode. * The ARE_S bit resets to 0 if supported @@ -129,11 +173,9 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) flush_dcache_range((uintptr_t)gicv3_driver_data, sizeof(*gicv3_driver_data)); #endif - - INFO("GICv3 with%s legacy support detected." - " ARM GICv3 driver initialized in EL3\n", - (gicv2_compat == 0U) ? "" : "out"); - + INFO("GICv%u with%s legacy support detected.\n", gic_version, + (gicv2_compat == 0U) ? "" : "out"); + INFO("ARM GICv%u driver initialized in EL3\n", gic_version); } /******************************************************************************* @@ -142,7 +184,7 @@ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) ******************************************************************************/ void __init gicv3_distif_init(void) { - unsigned int bitmap = 0; + unsigned int bitmap; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); @@ -164,7 +206,7 @@ void __init gicv3_distif_init(void) gicd_set_ctlr(gicv3_driver_data->gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); - /* Set the default attribute of all SPIs */ + /* Set the default attribute of all (E)SPIs */ gicv3_spis_config_defaults(gicv3_driver_data->gicd_base); bitmap = gicv3_secure_spis_config_props( @@ -172,7 +214,7 @@ void __init gicv3_distif_init(void) gicv3_driver_data->interrupt_props, gicv3_driver_data->interrupt_props_num); - /* Enable the secure SPIs now that they have been configured */ + /* Enable the secure (E)SPIs now that they have been configured */ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); } @@ -184,7 +226,7 @@ void __init gicv3_distif_init(void) void gicv3_rdistif_init(unsigned int proc_num) { uintptr_t gicr_base; - unsigned int bitmap = 0U; + unsigned int bitmap; uint32_t ctlr; assert(gicv3_driver_data != NULL); @@ -203,7 +245,7 @@ void gicv3_rdistif_init(unsigned int proc_num) gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; assert(gicr_base != 0U); - /* Set the default attribute of all SGIs and PPIs */ + /* Set the default attribute of all SGIs and (E)PPIs */ gicv3_ppi_sgi_config_defaults(gicr_base); bitmap = gicv3_secure_ppi_sgi_config_props(gicr_base, @@ -211,8 +253,9 @@ void gicv3_rdistif_init(unsigned int proc_num) gicv3_driver_data->interrupt_props_num); /* Enable interrupt groups as required, if not already */ - if ((ctlr & bitmap) != bitmap) + if ((ctlr & bitmap) != bitmap) { gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); + } } /******************************************************************************* @@ -220,12 +263,10 @@ void gicv3_rdistif_init(unsigned int proc_num) ******************************************************************************/ void gicv3_rdistif_off(unsigned int proc_num) { - return; } void gicv3_rdistif_on(unsigned int proc_num) { - return; } /******************************************************************************* @@ -342,8 +383,9 @@ unsigned int gicv3_get_pending_interrupt_id(void) * If the ID is special identifier corresponding to G1S or G1NS * interrupt, then read the highest pending group 1 interrupt. */ - if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID)) + if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID)) { return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK; + } return id; } @@ -373,8 +415,7 @@ unsigned int gicv3_get_pending_interrupt_type(void) * INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure * interrupt. ******************************************************************************/ -unsigned int gicv3_get_interrupt_type(unsigned int id, - unsigned int proc_num) +unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num) { unsigned int igroup, grpmodr; uintptr_t gicr_base; @@ -387,15 +428,19 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, assert(proc_num < gicv3_driver_data->rdistif_num); /* All LPI interrupts are Group 1 non secure */ - if (id >= MIN_LPI_ID) + if (id >= MIN_LPI_ID) { return INTR_GROUP1NS; + } - if (id < MIN_SPI_ID) { + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */ assert(gicv3_driver_data->rdistif_base_addrs != NULL); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; - igroup = gicr_get_igroupr0(gicr_base, id); - grpmodr = gicr_get_igrpmodr0(gicr_base, id); + igroup = gicr_get_igroupr(gicr_base, id); + grpmodr = gicr_get_igrpmodr(gicr_base, id); } else { + /* SPIs: 32-1019, ESPIs: 4096-5119 */ assert(gicv3_driver_data->gicd_base != 0U); igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id); grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id); @@ -405,12 +450,14 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, * If the IGROUP bit is set, then it is a Group 1 Non secure * interrupt */ - if (igroup != 0U) + if (igroup != 0U) { return INTR_GROUP1NS; + } /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */ - if (grpmodr != 0U) + if (grpmodr != 0U) { return INTR_GROUP1S; + } /* Else it is a Group 0 Secure interrupt */ return INTR_GROUP0; @@ -427,7 +474,8 @@ unsigned int gicv3_get_interrupt_type(unsigned int id, * * This function must be invoked after the GIC CPU interface is disabled. *****************************************************************************/ -void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx) +void gicv3_its_save_disable(uintptr_t gits_base, + gicv3_its_ctx_t * const its_ctx) { unsigned int i; @@ -439,8 +487,7 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx its_ctx->gits_ctlr = gits_read_ctlr(gits_base); /* Disable the ITS */ - gits_write_ctlr(gits_base, its_ctx->gits_ctlr & - (~GITS_CTLR_ENABLED_BIT)); + gits_write_ctlr(gits_base, its_ctx->gits_ctlr & ~GITS_CTLR_ENABLED_BIT); /* Wait for quiescent state */ gits_wait_for_quiescent_bit(gits_base); @@ -448,8 +495,9 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx its_ctx->gits_cbaser = gits_read_cbaser(gits_base); its_ctx->gits_cwriter = gits_read_cwriter(gits_base); - for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) + for (i = 0U; i < ARRAY_SIZE(its_ctx->gits_baser); i++) { its_ctx->gits_baser[i] = gits_read_baser(gits_base, i); + } } /***************************************************************************** @@ -460,7 +508,8 @@ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx * * This must be invoked before the GIC CPU interface is enabled. *****************************************************************************/ -void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx) +void gicv3_its_restore(uintptr_t gits_base, + const gicv3_its_ctx_t * const its_ctx) { unsigned int i; @@ -476,22 +525,23 @@ void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ct gits_write_cbaser(gits_base, its_ctx->gits_cbaser); gits_write_cwriter(gits_base, its_ctx->gits_cwriter); - for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) + for (i = 0U; i < ARRAY_SIZE(its_ctx->gits_baser); i++) { gits_write_baser(gits_base, i, its_ctx->gits_baser[i]); + } /* Restore the ITS CTLR but leave the ITS disabled */ - gits_write_ctlr(gits_base, its_ctx->gits_ctlr & - (~GITS_CTLR_ENABLED_BIT)); + gits_write_ctlr(gits_base, its_ctx->gits_ctlr & ~GITS_CTLR_ENABLED_BIT); } /***************************************************************************** * Function to save the GIC Redistributor register context. This function * must be invoked after CPU interface disable and prior to Distributor save. *****************************************************************************/ -void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx) +void gicv3_rdistif_save(unsigned int proc_num, + gicv3_redist_ctx_t * const rdist_ctx) { uintptr_t gicr_base; - unsigned int int_id; + unsigned int i, ppi_regs_num, regs_num; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); @@ -501,6 +551,17 @@ void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; +#if GIC_EXT_INTID + /* Calculate number of PPI registers */ + ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >> + TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1; + /* All other values except PPInum [0-2] are reserved */ + if (ppi_regs_num > 3U) { + ppi_regs_num = 1U; + } +#else + ppi_regs_num = 1U; +#endif /* * Wait for any write to GICR_CTLR to complete before trying to save any * state. @@ -512,20 +573,29 @@ void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base); rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base); - rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base); - rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base); - rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base); - rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base); - rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base); - rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base); - rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base); - rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base); - for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM; - int_id += (1U << IPRIORITYR_SHIFT)) { - rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] = - gicr_read_ipriorityr(gicr_base, int_id); + /* 32 interrupt IDs per register */ + for (i = 0U; i < ppi_regs_num; ++i) { + SAVE_GICR_REG(gicr_base, rdist_ctx, igroupr, i); + SAVE_GICR_REG(gicr_base, rdist_ctx, isenabler, i); + SAVE_GICR_REG(gicr_base, rdist_ctx, ispendr, i); + SAVE_GICR_REG(gicr_base, rdist_ctx, isactiver, i); + SAVE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i); } + /* 16 interrupt IDs per GICR_ICFGR register */ + regs_num = ppi_regs_num << 1; + for (i = 0U; i < regs_num; ++i) { + SAVE_GICR_REG(gicr_base, rdist_ctx, icfgr, i); + } + + rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base); + + /* 4 interrupt IDs per GICR_IPRIORITYR register */ + regs_num = ppi_regs_num << 3; + for (i = 0U; i < regs_num; ++i) { + rdist_ctx->gicr_ipriorityr[i] = + gicr_ipriorityr_read(gicr_base, i); + } /* * Call the pre-save hook that implements the IMP DEF sequence that may @@ -546,7 +616,7 @@ void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx) { uintptr_t gicr_base; - unsigned int int_id; + unsigned int i, ppi_regs_num, regs_num; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); @@ -556,6 +626,17 @@ void gicv3_rdistif_init_restore(unsigned int proc_num, gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; +#if GIC_EXT_INTID + /* Calculate number of PPI registers */ + ppi_regs_num = (unsigned int)((gicr_read_typer(gicr_base) >> + TYPER_PPI_NUM_SHIFT) & TYPER_PPI_NUM_MASK) + 1; + /* All other values except PPInum [0-2] are reserved */ + if (ppi_regs_num > 3U) { + ppi_regs_num = 1U; + } +#else + ppi_regs_num = 1U; +#endif /* Power on redistributor */ gicv3_rdistif_on(proc_num); @@ -567,11 +648,14 @@ void gicv3_rdistif_init_restore(unsigned int proc_num, gicv3_distif_post_restore(proc_num); /* - * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a - * more scalable approach as it avoids clearing the enable bits in the - * GICD_CTLR + * Disable all SGIs (imp. def.)/(E)PPIs before configuring them. + * This is a more scalable approach as it avoids clearing the enable + * bits in the GICD_CTLR. */ - gicr_write_icenabler0(gicr_base, ~0U); + for (i = 0U; i < ppi_regs_num; ++i) { + gicr_write_icenabler(gicr_base, i, ~0U); + } + /* Wait for pending writes to GICR_ICENABLER */ gicr_wait_for_pending_write(gicr_base); @@ -586,30 +670,45 @@ void gicv3_rdistif_init_restore(unsigned int proc_num, gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser); gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser); - gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0); + /* 32 interrupt IDs per register */ + for (i = 0U; i < ppi_regs_num; ++i) { + RESTORE_GICR_REG(gicr_base, rdist_ctx, igroupr, i); + RESTORE_GICR_REG(gicr_base, rdist_ctx, igrpmodr, i); + } + + /* 4 interrupt IDs per GICR_IPRIORITYR register */ + regs_num = ppi_regs_num << 3; + for (i = 0U; i < regs_num; ++i) { + gicr_ipriorityr_write(gicr_base, i, + rdist_ctx->gicr_ipriorityr[i]); + } - for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM; - int_id += (1U << IPRIORITYR_SHIFT)) { - gicr_write_ipriorityr(gicr_base, int_id, - rdist_ctx->gicr_ipriorityr[ - (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]); + /* 16 interrupt IDs per GICR_ICFGR register */ + regs_num = ppi_regs_num << 1; + for (i = 0U; i < regs_num; ++i) { + RESTORE_GICR_REG(gicr_base, rdist_ctx, icfgr, i); } - gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0); - gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1); - gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0); gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr); - /* Restore after group and priorities are set */ - gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0); - gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0); + /* Restore after group and priorities are set. + * 32 interrupt IDs per register + */ + for (i = 0U; i < ppi_regs_num; ++i) { + RESTORE_GICR_REG(gicr_base, rdist_ctx, ispendr, i); + RESTORE_GICR_REG(gicr_base, rdist_ctx, isactiver, i); + } /* * Wait for all writes to the Distributor to complete before enabling - * the SGI and PPIs. + * the SGI and (E)PPIs. */ gicr_wait_for_upstream_pending_write(gicr_base); - gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0); + + /* 32 interrupt IDs per GICR_ISENABLER register */ + for (i = 0U; i < ppi_regs_num; ++i) { + RESTORE_GICR_REG(gicr_base, rdist_ctx, isenabler, i); + } /* * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case @@ -627,7 +726,10 @@ void gicv3_rdistif_init_restore(unsigned int proc_num, *****************************************************************************/ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) { - unsigned int num_ints; + unsigned int typer_reg, num_ints; +#if GIC_EXT_INTID + unsigned int num_eints; +#endif assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); @@ -636,14 +738,28 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) uintptr_t gicd_base = gicv3_driver_data->gicd_base; - num_ints = gicd_read_typer(gicd_base); - num_ints &= TYPER_IT_LINES_NO_MASK; - num_ints = (num_ints + 1U) << 5; + typer_reg = gicd_read_typer(gicd_base); + + /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */ + num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5; /* Filter out special INTIDs 1020-1023 */ - if (num_ints > (MAX_SPI_ID + 1U)) + if (num_ints > (MAX_SPI_ID + 1U)) { num_ints = MAX_SPI_ID + 1U; + } +#if GIC_EXT_INTID + /* Check if extended SPI range is implemented */ + if ((typer_reg & TYPER_ESPI) != 0U) { + /* + * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095 + */ + num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) & + TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID - 1; + } else { + num_eints = 0U; + } +#endif /* Wait for pending write to complete */ gicd_wait_for_pending_write(gicd_base); @@ -651,31 +767,58 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base); /* Save GICD_IGROUPR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP); + + /* Save GICD_IGROUPRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP); /* Save GICD_ISENABLER for INT_IDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE); + + /* Save GICD_ISENABLERE for INT_IDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE); /* Save GICD_ISPENDR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND); + + /* Save GICD_ISPENDRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND); /* Save GICD_ISACTIVER for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE); + + /* Save GICD_ISACTIVERE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE); /* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY); + + /* Save GICD_IPRIORITYRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY); /* Save GICD_ICFGR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG); + + /* Save GICD_ICFGRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG); /* Save GICD_IGRPMODR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD); + + /* Save GICD_IGRPMODRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD); /* Save GICD_NSACR for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC); + + /* Save GICD_NSACRE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC); /* Save GICD_IROUTER for INTIDs 32 - 1019 */ - SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE); + + /* Save GICD_IROUTERE for INTIDs 4096 - 5119 */ + SAVE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE); /* * GICD_ITARGETSR<n> and GICD_SPENDSGIR<n> are RAZ/WI when @@ -693,7 +836,10 @@ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) *****************************************************************************/ void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx) { - unsigned int num_ints = 0U; + unsigned int typer_reg, num_ints; +#if GIC_EXT_INTID + unsigned int num_eints; +#endif assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); @@ -716,50 +862,90 @@ void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx) /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); - num_ints = gicd_read_typer(gicd_base); - num_ints &= TYPER_IT_LINES_NO_MASK; - num_ints = (num_ints + 1U) << 5; + typer_reg = gicd_read_typer(gicd_base); + + /* Maximum SPI INTID is 32 * (GICD_TYPER.ITLinesNumber + 1) - 1 */ + num_ints = ((typer_reg & TYPER_IT_LINES_NO_MASK) + 1U) << 5; /* Filter out special INTIDs 1020-1023 */ - if (num_ints > (MAX_SPI_ID + 1U)) + if (num_ints > (MAX_SPI_ID + 1U)) { num_ints = MAX_SPI_ID + 1U; + } +#if GIC_EXT_INTID + /* Check if extended SPI range is implemented */ + if ((typer_reg & TYPER_ESPI) != 0U) { + /* + * Maximum ESPI INTID is 32 * (GICD_TYPER.ESPI_range + 1) + 4095 + */ + num_eints = ((((typer_reg >> TYPER_ESPI_RANGE_SHIFT) & + TYPER_ESPI_RANGE_MASK) + 1U) << 5) + MIN_ESPI_ID - 1; + } else { + num_eints = 0U; + } +#endif /* Restore GICD_IGROUPR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUP); + + /* Restore GICD_IGROUPRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igroupr, IGROUP); /* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITY); + + /* Restore GICD_IPRIORITYRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ipriorityr, IPRIORITY); /* Restore GICD_ICFGR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFG); + + /* Restore GICD_ICFGRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, icfgr, ICFG); /* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMOD); + + /* Restore GICD_IGRPMODRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, igrpmodr, IGRPMOD); /* Restore GICD_NSACR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSAC); + + /* Restore GICD_NSACRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, nsacr, NSAC); /* Restore GICD_IROUTER for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTE); + + /* Restore GICD_IROUTERE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, irouter, IROUTE); /* - * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are - * configured. + * Restore ISENABLER(E), ISPENDR(E) and ISACTIVER(E) after + * the interrupts are configured. */ /* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLE); + + /* Restore GICD_ISENABLERE for INT_IDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isenabler, ISENABLE); /* Restore GICD_ISPENDR for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPEND); + + /* Restore GICD_ISPENDRE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, ispendr, ISPEND); /* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */ - RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVE); + + /* Restore GICD_ISACTIVERE for INTIDs 4096 - 5119 */ + RESTORE_GICD_EREGS(gicd_base, dist_ctx, num_eints, isactiver, ISACTIVE); /* Restore the GICD_CTLR */ gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr); gicd_wait_for_pending_write(gicd_base); - } /******************************************************************************* @@ -774,28 +960,25 @@ unsigned int gicv3_get_running_priority(void) /******************************************************************************* * This function checks if the interrupt identified by id is active (whether the * state is either active, or active and pending). The proc_num is used if the - * interrupt is SGI or PPI and programs the corresponding Redistributor + * interrupt is SGI or (E)PPI and programs the corresponding Redistributor * interface. ******************************************************************************/ unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num) { - unsigned int value; - assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); - assert(id <= MAX_SPI_ID); - if (id < MIN_SPI_ID) { - /* For SGIs and PPIs */ - value = gicr_get_isactiver0( - gicv3_driver_data->rdistif_base_addrs[proc_num], id); - } else { - value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id); + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ + return gicr_get_isactiver( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); } - return value; + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ + return gicd_get_isactiver(gicv3_driver_data->gicd_base, id); } /******************************************************************************* @@ -809,19 +992,20 @@ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num) assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); - assert(id <= MAX_SPI_ID); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before enabling interrupt. */ dsbishst(); - if (id < MIN_SPI_ID) { - /* For SGIs and PPIs */ - gicr_set_isenabler0( - gicv3_driver_data->rdistif_base_addrs[proc_num], - id); + + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ + gicr_set_isenabler( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ gicd_set_isenabler(gicv3_driver_data->gicd_base, id); } } @@ -837,22 +1021,23 @@ void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num) assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); - assert(id <= MAX_SPI_ID); /* * Disable interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ - if (id < MIN_SPI_ID) { - /* For SGIs and PPIs */ - gicr_set_icenabler0( - gicv3_driver_data->rdistif_base_addrs[proc_num], - id); + + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ + gicr_set_icenabler( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); /* Write to clear enable requires waiting for pending writes */ gicr_wait_for_pending_write( - gicv3_driver_data->rdistif_base_addrs[proc_num]); + gicv3_driver_data->rdistif_base_addrs[proc_num]); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ gicd_set_icenabler(gicv3_driver_data->gicd_base, id); /* Write to clear enable requires waiting for pending writes */ @@ -875,19 +1060,21 @@ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num, assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); - assert(id <= MAX_SPI_ID); - if (id < MIN_SPI_ID) { + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; gicr_set_ipriorityr(gicr_base, id, priority); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority); } } /******************************************************************************* * This function assigns group for the interrupt identified by id. The proc_num - * is used if the interrupt is SGI or PPI, and programs the corresponding + * is used if the interrupt is SGI or (E)PPI, and programs the corresponding * Redistributor interface. The group can be any of GICV3_INTR_GROUP* ******************************************************************************/ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num, @@ -919,29 +1106,26 @@ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num, break; } - if (id < MIN_SPI_ID) { + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; - if (igroup) - gicr_set_igroupr0(gicr_base, id); - else - gicr_clr_igroupr0(gicr_base, id); - - if (grpmod) - gicr_set_igrpmodr0(gicr_base, id); - else - gicr_clr_igrpmodr0(gicr_base, id); + + igroup ? gicr_set_igroupr(gicr_base, id) : + gicr_clr_igroupr(gicr_base, id); + grpmod ? gicr_set_igrpmodr(gicr_base, id) : + gicr_clr_igrpmodr(gicr_base, id); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ + /* Serialize read-modify-write to Distributor registers */ spin_lock(&gic_lock); - if (igroup) - gicd_set_igroupr(gicv3_driver_data->gicd_base, id); - else - gicd_clr_igroupr(gicv3_driver_data->gicd_base, id); - - if (grpmod) - gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id); - else - gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id); + + igroup ? gicd_set_igroupr(gicv3_driver_data->gicd_base, id) : + gicd_clr_igroupr(gicv3_driver_data->gicd_base, id); + grpmod ? gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id) : + gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id); + spin_unlock(&gic_lock); } } @@ -986,7 +1170,7 @@ void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target) } /******************************************************************************* - * This function sets the interrupt routing for the given SPI interrupt id. + * This function sets the interrupt routing for the given (E)SPI interrupt id. * The interrupt routing is specified in routing mode and mpidr. * * The routing mode can be either of: @@ -1005,7 +1189,8 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr assert(gicv3_driver_data->gicd_base != 0U); assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE)); - assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID)); + + assert(IS_SPI(id)); aff = gicd_irouter_val_from_mpidr(mpidr, irm); gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff); @@ -1025,7 +1210,7 @@ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr /******************************************************************************* * This function clears the pending status of an interrupt identified by id. - * The proc_num is used if the interrupt is SGI or PPI, and programs the + * The proc_num is used if the interrupt is SGI or (E)PPI, and programs the * corresponding Redistributor interface. ******************************************************************************/ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num) @@ -1039,13 +1224,17 @@ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num) * Clear pending interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ - if (id < MIN_SPI_ID) { - /* For SGIs and PPIs */ - gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num], - id); + + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ + gicr_set_icpendr( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ gicd_set_icpendr(gicv3_driver_data->gicd_base, id); } + dsbishst(); } @@ -1066,11 +1255,14 @@ void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num) * interrupt trigger are observed before setting interrupt pending. */ dsbishst(); - if (id < MIN_SPI_ID) { - /* For SGIs and PPIs */ - gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num], - id); + + /* Check interrupt ID */ + if (is_sgi_ppi(id)) { + /* For SGIs: 0-15, PPIs: 16-31 and EPPIs: 1056-1119 */ + gicr_set_ispendr( + gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { + /* For SPIs: 32-1019 and ESPIs: 4096-5119 */ gicd_set_ispendr(gicv3_driver_data->gicd_base, id); } } @@ -1083,7 +1275,7 @@ unsigned int gicv3_set_pmr(unsigned int mask) { unsigned int old_mask; - old_mask = (uint32_t) read_icc_pmr_el1(); + old_mask = (unsigned int)read_icc_pmr_el1(); /* * Order memory updates w.r.t. PMR write, and ensure they're visible @@ -1130,15 +1322,17 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame) mpidr = mpidr_from_gicr_typer(typer_val); proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr); } else { - proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) & - TYPER_PROC_NUM_MASK; + proc_num = (unsigned int)(typer_val >> + TYPER_PROC_NUM_SHIFT) & TYPER_PROC_NUM_MASK; } if (proc_num == proc_self) { /* The base address doesn't need to be initialized on * every warm boot. */ - if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U) + if (gicv3_driver_data->rdistif_base_addrs[proc_num] + != 0U) { return 0; + } gicv3_driver_data->rdistif_base_addrs[proc_num] = rdistif_base; gicr_frame_found = true; @@ -1147,8 +1341,9 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame) rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT); } while ((typer_val & TYPER_LAST_BIT) == 0U); - if (!gicr_frame_found) + if (!gicr_frame_found) { return -1; + } /* * Flush the driver data to ensure coherency. This is @@ -1164,3 +1359,23 @@ int gicv3_rdistif_probe(const uintptr_t gicr_frame) #endif return 0; /* Found matching GICR frame */ } + +/****************************************************************************** + * This function checks the interrupt ID and returns true for SGIs and (E)PPIs + * and false for (E)SPIs IDs. + *****************************************************************************/ +static bool is_sgi_ppi(unsigned int id) +{ + /* SGIs: 0-15, PPIs: 16-31, EPPIs: 1056-1119 */ + if (IS_SGI_PPI(id)) { + return true; + } + + /* SPIs: 32-1019, ESPIs: 4096-5119 */ + if (IS_SPI(id)) { + return false; + } + + assert(false); + panic(); +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index 327a9a149..c5d027da2 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -24,6 +24,144 @@ #define RWP_TRUE U(1) #define RWP_FALSE U(0) +/* Calculate GIC register bit number corresponding to its interrupt ID */ +#define BIT_NUM(REG, id) \ + ((id) & ((1U << REG##R_SHIFT) - 1U)) + +/* + * Calculate 8, 32 and 64-bit GICD register offset + * corresponding to its interrupt ID + */ +#if GIC_EXT_INTID + /* GICv3.1 */ +#define GICD_OFFSET_8(REG, id) \ + (((id) <= MAX_SPI_ID) ? \ + GICD_##REG##R + (uintptr_t)(id) : \ + GICD_##REG##RE + (uintptr_t)(id) - MIN_ESPI_ID) + +#define GICD_OFFSET(REG, id) \ + (((id) <= MAX_SPI_ID) ? \ + GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \ + GICD_##REG##RE + ((((uintptr_t)(id) - MIN_ESPI_ID) >> \ + REG##R_SHIFT) << 2)) + +#define GICD_OFFSET_64(REG, id) \ + (((id) <= MAX_SPI_ID) ? \ + GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3) : \ + GICD_##REG##RE + (((uintptr_t)(id) - MIN_ESPI_ID) << 3)) + +#else /* GICv3 */ +#define GICD_OFFSET_8(REG, id) \ + (GICD_##REG##R + (uintptr_t)(id)) + +#define GICD_OFFSET(REG, id) \ + (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2)) + +#define GICD_OFFSET_64(REG, id) \ + (GICD_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 3)) +#endif /* GIC_EXT_INTID */ + +/* + * Read/Write 8, 32 and 64-bit GIC Distributor register + * corresponding to its interrupt ID + */ +#define GICD_READ(REG, base, id) \ + mmio_read_32((base) + GICD_OFFSET(REG, (id))) + +#define GICD_READ_64(REG, base, id) \ + mmio_read_64((base) + GICD_OFFSET_64(REG, (id))) + +#define GICD_WRITE_8(REG, base, id, val) \ + mmio_write_8((base) + GICD_OFFSET_8(REG, (id)), (val)) + +#define GICD_WRITE(REG, base, id, val) \ + mmio_write_32((base) + GICD_OFFSET(REG, (id)), (val)) + +#define GICD_WRITE_64(REG, base, id, val) \ + mmio_write_64((base) + GICD_OFFSET_64(REG, (id)), (val)) + +/* + * Bit operations on GIC Distributor register corresponding + * to its interrupt ID + */ +/* Get bit in GIC Distributor register */ +#define GICD_GET_BIT(REG, base, id) \ + ((mmio_read_32((base) + GICD_OFFSET(REG, (id))) >> \ + BIT_NUM(REG, (id))) & 1U) + +/* Set bit in GIC Distributor register */ +#define GICD_SET_BIT(REG, base, id) \ + mmio_setbits_32((base) + GICD_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + +/* Clear bit in GIC Distributor register */ +#define GICD_CLR_BIT(REG, base, id) \ + mmio_clrbits_32((base) + GICD_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + +/* Write bit in GIC Distributor register */ +#define GICD_WRITE_BIT(REG, base, id) \ + mmio_write_32((base) + GICD_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + +/* + * Calculate 8 and 32-bit GICR register offset + * corresponding to its interrupt ID + */ +#if GIC_EXT_INTID + /* GICv3.1 */ +#define GICR_OFFSET_8(REG, id) \ + (((id) <= MAX_PPI_ID) ? \ + GICR_##REG##R + (uintptr_t)(id) : \ + GICR_##REG##R + (uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID)) + +#define GICR_OFFSET(REG, id) \ + (((id) <= MAX_PPI_ID) ? \ + GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2) : \ + GICR_##REG##R + ((((uintptr_t)(id) - (MIN_EPPI_ID - MIN_SPI_ID))\ + >> REG##R_SHIFT) << 2)) +#else /* GICv3 */ +#define GICR_OFFSET_8(REG, id) \ + (GICR_##REG##R + (uintptr_t)(id)) + +#define GICR_OFFSET(REG, id) \ + (GICR_##REG##R + (((uintptr_t)(id) >> REG##R_SHIFT) << 2)) +#endif /* GIC_EXT_INTID */ + +/* Read/Write GIC Redistributor register corresponding to its interrupt ID */ +#define GICR_READ(REG, base, id) \ + mmio_read_32((base) + GICR_OFFSET(REG, (id))) + +#define GICR_WRITE_8(REG, base, id, val) \ + mmio_write_8((base) + GICR_OFFSET_8(REG, (id)), (val)) + +#define GICR_WRITE(REG, base, id, val) \ + mmio_write_32((base) + GICR_OFFSET(REG, (id)), (val)) + +/* + * Bit operations on GIC Redistributor register + * corresponding to its interrupt ID + */ +/* Get bit in GIC Redistributor register */ +#define GICR_GET_BIT(REG, base, id) \ + ((mmio_read_32((base) + GICR_OFFSET(REG, (id))) >> \ + BIT_NUM(REG, (id))) & 1U) + +/* Write bit in GIC Redistributor register */ +#define GICR_WRITE_BIT(REG, base, id) \ + mmio_write_32((base) + GICR_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + +/* Set bit in GIC Redistributor register */ +#define GICR_SET_BIT(REG, base, id) \ + mmio_setbits_32((base) + GICR_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + +/* Clear bit in GIC Redistributor register */ +#define GICR_CLR_BIT(REG, base, id) \ + mmio_clrbits_32((base) + GICR_OFFSET(REG, (id)), \ + ((uint32_t)1 << BIT_NUM(REG, (id)))) + /* * Macro to convert an mpidr to a value suitable for programming into a * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant @@ -75,22 +213,21 @@ void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); * the bit-field corresponding the single interrupt ID. ******************************************************************************/ unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id); -unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id); -unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id); -unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id); +unsigned int gicr_get_igrpmodr(uintptr_t base, unsigned int id); +unsigned int gicr_get_igroupr(uintptr_t base, unsigned int id); +unsigned int gicr_get_isactiver(uintptr_t base, unsigned int id); void gicd_set_igrpmodr(uintptr_t base, unsigned int id); -void gicr_set_igrpmodr0(uintptr_t base, unsigned int id); -void gicr_set_isenabler0(uintptr_t base, unsigned int id); -void gicr_set_icenabler0(uintptr_t base, unsigned int id); -void gicr_set_ispendr0(uintptr_t base, unsigned int id); -void gicr_set_icpendr0(uintptr_t base, unsigned int id); -void gicr_set_igroupr0(uintptr_t base, unsigned int id); +void gicr_set_igrpmodr(uintptr_t base, unsigned int id); +void gicr_set_isenabler(uintptr_t base, unsigned int id); +void gicr_set_icenabler(uintptr_t base, unsigned int id); +void gicr_set_ispendr(uintptr_t base, unsigned int id); +void gicr_set_icpendr(uintptr_t base, unsigned int id); +void gicr_set_igroupr(uintptr_t base, unsigned int id); void gicd_clr_igrpmodr(uintptr_t base, unsigned int id); -void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id); -void gicr_clr_igroupr0(uintptr_t base, unsigned int id); +void gicr_clr_igrpmodr(uintptr_t base, unsigned int id); +void gicr_clr_igroupr(uintptr_t base, unsigned int id); void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri); -void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg); -void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg); +void gicr_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg); /******************************************************************************* * Private GICv3 helper function prototypes @@ -114,34 +251,34 @@ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base); * GIC Distributor interface accessors ******************************************************************************/ /* - * Wait for updates to : + * Wait for updates to: * GICD_CTLR[2:0] - the Group Enables - * GICD_CTLR[5:4] - the ARE bits - * GICD_ICENABLERn - the clearing of enable state for SPIs + * GICD_CTLR[7:4] - the ARE bits, E1NWF bit and DS bit + * GICD_ICENABLER<n> - the clearing of enable state for SPIs */ static inline void gicd_wait_for_pending_write(uintptr_t gicd_base) { - while ((gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) != 0U) - ; + while ((gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) != 0U) { + } } -static inline unsigned int gicd_read_pidr2(uintptr_t base) +static inline uint32_t gicd_read_pidr2(uintptr_t base) { return mmio_read_32(base + GICD_PIDR2_GICV3); } -static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id) +static inline uint64_t gicd_read_irouter(uintptr_t base, unsigned int id) { assert(id >= MIN_SPI_ID); - return mmio_read_64(base + GICD_IROUTER + (id << 3)); + return GICD_READ_64(IROUTE, base, id); } static inline void gicd_write_irouter(uintptr_t base, unsigned int id, - unsigned long long affinity) + uint64_t affinity) { assert(id >= MIN_SPI_ID); - mmio_write_64(base + GICD_IROUTER + (id << 3), affinity); + GICD_WRITE_64(IROUTE, base, id, affinity); } static inline void gicd_clr_ctlr(uintptr_t base, @@ -149,8 +286,9 @@ static inline void gicd_clr_ctlr(uintptr_t base, unsigned int rwp) { gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap); - if (rwp != 0U) + if (rwp != 0U) { gicd_wait_for_pending_write(base); + } } static inline void gicd_set_ctlr(uintptr_t base, @@ -158,8 +296,9 @@ static inline void gicd_set_ctlr(uintptr_t base, unsigned int rwp) { gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap); - if (rwp != 0U) + if (rwp != 0U) { gicd_wait_for_pending_write(base); + } } /******************************************************************************* @@ -175,38 +314,39 @@ static inline void gicr_write_ctlr(uintptr_t base, uint32_t val) mmio_write_32(base + GICR_CTLR, val); } -static inline unsigned long long gicr_read_typer(uintptr_t base) +static inline uint64_t gicr_read_typer(uintptr_t base) { return mmio_read_64(base + GICR_TYPER); } -static inline unsigned int gicr_read_waker(uintptr_t base) +static inline uint32_t gicr_read_waker(uintptr_t base) { return mmio_read_32(base + GICR_WAKER); } -static inline void gicr_write_waker(uintptr_t base, unsigned int val) +static inline void gicr_write_waker(uintptr_t base, uint32_t val) { mmio_write_32(base + GICR_WAKER, val); } /* - * Wait for updates to : + * Wait for updates to: * GICR_ICENABLER0 * GICR_CTLR.DPG1S * GICR_CTLR.DPG1NS * GICR_CTLR.DPG0 + * GICR_CTLR, which clears EnableLPIs from 1 to 0 */ static inline void gicr_wait_for_pending_write(uintptr_t gicr_base) { - while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) != 0U) - ; + while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) != 0U) { + } } static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base) { - while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT) != 0U) - ; + while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT) != 0U) { + } } /* Private implementation of Distributor power control hooks */ @@ -214,10 +354,14 @@ void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num); void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num); /******************************************************************************* - * GIC Re-distributor functions for accessing entire registers. + * GIC Redistributor functions for accessing entire registers. * Note: The raw register values correspond to multiple interrupt IDs and * the number of interrupt IDs involved depends on the register accessed. ******************************************************************************/ + +/* + * Accessors to read/write GIC Redistributor ICENABLER0 register + */ static inline unsigned int gicr_read_icenabler0(uintptr_t base) { return mmio_read_32(base + GICR_ICENABLER0); @@ -228,41 +372,110 @@ static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val) mmio_write_32(base + GICR_ICENABLER0, val); } -static inline unsigned int gicr_read_isenabler0(uintptr_t base) +/* + * Accessors to read/write GIC Redistributor ICENABLER0 and ICENABLERE + * register corresponding to its number + */ +static inline unsigned int gicr_read_icenabler(uintptr_t base, + unsigned int reg_num) { - return mmio_read_32(base + GICR_ISENABLER0); + return mmio_read_32(base + GICR_ICENABLER + (reg_num << 2)); +} + +static inline void gicr_write_icenabler(uintptr_t base, unsigned int reg_num, + unsigned int val) +{ + mmio_write_32(base + GICR_ICENABLER + (reg_num << 2), val); } +/* + * Accessors to read/write GIC Redistributor ICFGR0, ICFGR1 registers + */ +static inline unsigned int gicr_read_icfgr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICFGR0); +} + +static inline unsigned int gicr_read_icfgr1(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICFGR1); +} + +static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ICFGR0, val); +} + +static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ICFGR1, val); +} + +/* + * Accessors to read/write GIC Redistributor ICFGR0, ICFGR1 and ICFGRE + * register corresponding to its number + */ +static inline unsigned int gicr_read_icfgr(uintptr_t base, unsigned int reg_num) +{ + return mmio_read_32(base + GICR_ICFGR + (reg_num << 2)); +} + +static inline void gicr_write_icfgr(uintptr_t base, unsigned int reg_num, + unsigned int val) +{ + mmio_write_32(base + GICR_ICFGR + (reg_num << 2), val); +} + +/* + * Accessor to write GIC Redistributor ICPENDR0 register + */ static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ICPENDR0, val); } -static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val) +/* + * Accessor to write GIC Redistributor ICPENDR0 and ICPENDRE + * register corresponding to its number + */ +static inline void gicr_write_icpendr(uintptr_t base, unsigned int reg_num, + unsigned int val) { - mmio_write_32(base + GICR_ISENABLER0, val); + mmio_write_32(base + GICR_ICPENDR + (reg_num << 2), val); } +/* + * Accessors to read/write GIC Redistributor IGROUPR0 register + */ static inline unsigned int gicr_read_igroupr0(uintptr_t base) { return mmio_read_32(base + GICR_IGROUPR0); } -static inline unsigned int gicr_read_ispendr0(uintptr_t base) +static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) { - return mmio_read_32(base + GICR_ISPENDR0); + mmio_write_32(base + GICR_IGROUPR0, val); } -static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val) +/* + * Accessors to read/write GIC Redistributor IGROUPR0 and IGROUPRE + * register corresponding to its number + */ +static inline unsigned int gicr_read_igroupr(uintptr_t base, + unsigned int reg_num) { - mmio_write_32(base + GICR_ISPENDR0, val); + return mmio_read_32(base + GICR_IGROUPR + (reg_num << 2)); } -static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) +static inline void gicr_write_igroupr(uintptr_t base, unsigned int reg_num, + unsigned int val) { - mmio_write_32(base + GICR_IGROUPR0, val); + mmio_write_32(base + GICR_IGROUPR + (reg_num << 2), val); } +/* + * Accessors to read/write GIC Redistributor IGRPMODR0 register + */ static inline unsigned int gicr_read_igrpmodr0(uintptr_t base) { return mmio_read_32(base + GICR_IGRPMODR0); @@ -273,16 +486,41 @@ static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val) mmio_write_32(base + GICR_IGRPMODR0, val); } -static inline unsigned int gicr_read_nsacr(uintptr_t base) +/* + * Accessors to read/write GIC Redistributor IGRPMODR0 and IGRPMODRE + * register corresponding to its number + */ +static inline unsigned int gicr_read_igrpmodr(uintptr_t base, + unsigned int reg_num) { - return mmio_read_32(base + GICR_NSACR); + return mmio_read_32(base + GICR_IGRPMODR + (reg_num << 2)); } -static inline void gicr_write_nsacr(uintptr_t base, unsigned int val) +static inline void gicr_write_igrpmodr(uintptr_t base, unsigned int reg_num, + unsigned int val) { - mmio_write_32(base + GICR_NSACR, val); + mmio_write_32(base + GICR_IGRPMODR + (reg_num << 2), val); +} + +/* + * Accessors to read/write the GIC Redistributor IPRIORITYR(E) register + * corresponding to its number, 4 interrupts IDs at a time. + */ +static inline unsigned int gicr_ipriorityr_read(uintptr_t base, + unsigned int reg_num) +{ + return mmio_read_32(base + GICR_IPRIORITYR + (reg_num << 2)); +} + +static inline void gicr_ipriorityr_write(uintptr_t base, unsigned int reg_num, + unsigned int val) +{ + mmio_write_32(base + GICR_IPRIORITYR + (reg_num << 2), val); } +/* + * Accessors to read/write GIC Redistributor ISACTIVER0 register + */ static inline unsigned int gicr_read_isactiver0(uintptr_t base) { return mmio_read_32(base + GICR_ISACTIVER0); @@ -293,26 +531,96 @@ static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val) mmio_write_32(base + GICR_ISACTIVER0, val); } -static inline unsigned int gicr_read_icfgr0(uintptr_t base) +/* + * Accessors to read/write GIC Redistributor ISACTIVER0 and ISACTIVERE + * register corresponding to its number + */ +static inline unsigned int gicr_read_isactiver(uintptr_t base, + unsigned int reg_num) { - return mmio_read_32(base + GICR_ICFGR0); + return mmio_read_32(base + GICR_ISACTIVER + (reg_num << 2)); } -static inline unsigned int gicr_read_icfgr1(uintptr_t base) +static inline void gicr_write_isactiver(uintptr_t base, unsigned int reg_num, + unsigned int val) { - return mmio_read_32(base + GICR_ICFGR1); + mmio_write_32(base + GICR_ISACTIVER + (reg_num << 2), val); } -static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val) +/* + * Accessors to read/write GIC Redistributor ISENABLER0 register + */ +static inline unsigned int gicr_read_isenabler0(uintptr_t base) { - mmio_write_32(base + GICR_ICFGR0, val); + return mmio_read_32(base + GICR_ISENABLER0); } -static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val) +static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val) { - mmio_write_32(base + GICR_ICFGR1, val); + mmio_write_32(base + GICR_ISENABLER0, val); +} + +/* + * Accessors to read/write GIC Redistributor ISENABLER0 and ISENABLERE + * register corresponding to its number + */ +static inline unsigned int gicr_read_isenabler(uintptr_t base, + unsigned int reg_num) +{ + return mmio_read_32(base + GICR_ISENABLER + (reg_num << 2)); +} + +static inline void gicr_write_isenabler(uintptr_t base, unsigned int reg_num, + unsigned int val) +{ + mmio_write_32(base + GICR_ISENABLER + (reg_num << 2), val); +} + +/* + * Accessors to read/write GIC Redistributor ISPENDR0 register + */ +static inline unsigned int gicr_read_ispendr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ISPENDR0); +} + +static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ISPENDR0, val); +} + +/* + * Accessors to read/write GIC Redistributor ISPENDR0 and ISPENDRE + * register corresponding to its number + */ +static inline unsigned int gicr_read_ispendr(uintptr_t base, + unsigned int reg_num) +{ + return mmio_read_32(base + GICR_ISPENDR + (reg_num << 2)); } +static inline void gicr_write_ispendr(uintptr_t base, unsigned int reg_num, + unsigned int val) +{ + mmio_write_32(base + GICR_ISPENDR + (reg_num << 2), val); +} + +/* + * Accessors to read/write GIC Redistributor NSACR register + */ +static inline unsigned int gicr_read_nsacr(uintptr_t base) +{ + return mmio_read_32(base + GICR_NSACR); +} + +static inline void gicr_write_nsacr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_NSACR, val); +} + +/* + * Accessors to read/write GIC Redistributor PROPBASER register + */ static inline uint64_t gicr_read_propbaser(uintptr_t base) { return mmio_read_64(base + GICR_PROPBASER); @@ -323,6 +631,9 @@ static inline void gicr_write_propbaser(uintptr_t base, uint64_t val) mmio_write_64(base + GICR_PROPBASER, val); } +/* + * Accessors to read/write GIC Redistributor PENDBASER register + */ static inline uint64_t gicr_read_pendbaser(uintptr_t base) { return mmio_read_64(base + GICR_PENDBASER); @@ -341,7 +652,7 @@ static inline uint32_t gits_read_ctlr(uintptr_t base) return mmio_read_32(base + GITS_CTLR); } -static inline void gits_write_ctlr(uintptr_t base, unsigned int val) +static inline void gits_write_ctlr(uintptr_t base, uint32_t val) { mmio_write_32(base + GITS_CTLR, val); } @@ -366,13 +677,15 @@ static inline void gits_write_cwriter(uintptr_t base, uint64_t val) mmio_write_64(base + GITS_CWRITER, val); } -static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id) +static inline uint64_t gits_read_baser(uintptr_t base, + unsigned int its_table_id) { assert(its_table_id < 8U); return mmio_read_64(base + GITS_BASER + (8U * its_table_id)); } -static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val) +static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, + uint64_t val) { assert(its_table_id < 8U); mmio_write_64(base + GITS_BASER + (8U * its_table_id), val); @@ -384,9 +697,8 @@ static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, u static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base) { assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0U); - while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0U) - ; + while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0U) { + } } - #endif /* GICV3_PRIVATE_H */ |