diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /drivers/arm/gic/v2/gicv2_helpers.c | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-upstream.tar.xz arm-trusted-firmware-upstream.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/arm/gic/v2/gicv2_helpers.c')
-rw-r--r-- | drivers/arm/gic/v2/gicv2_helpers.c | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/drivers/arm/gic/v2/gicv2_helpers.c b/drivers/arm/gic/v2/gicv2_helpers.c new file mode 100644 index 0000000..751316c --- /dev/null +++ b/drivers/arm/gic/v2/gicv2_helpers.c @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <common/debug.h> +#include <common/interrupt_props.h> +#include <drivers/arm/gic_common.h> +#include <drivers/arm/gicv2.h> + +#include "../common/gic_common_private.h" +#include "gicv2_private.h" + +/* + * Accessor to read the GIC Distributor ITARGETSR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) +{ + unsigned n = id >> ITARGETSR_SHIFT; + return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor CPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) +{ + unsigned n = id >> CPENDSGIR_SHIFT; + return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); +} + +/* + * Accessor to read the GIC Distributor SPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) +{ + unsigned n = id >> SPENDSGIR_SHIFT; + return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); +} + +/* + * Accessor to write the GIC Distributor ITARGETSR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> ITARGETSR_SHIFT; + mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor CPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> CPENDSGIR_SHIFT; + mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); +} + +/* + * Accessor to write the GIC Distributor SPENDSGIR corresponding to the + * interrupt `id`, 4 interrupt IDs at a time. + */ +void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) +{ + unsigned n = id >> SPENDSGIR_SHIFT; + mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); +} + +/******************************************************************************* + * Get the current CPU bit mask from GICD_ITARGETSR0 + ******************************************************************************/ +unsigned int gicv2_get_cpuif_id(uintptr_t base) +{ + unsigned int val; + + val = gicd_read_itargetsr(base, 0); + return val & GIC_TARGET_CPU_MASK; +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv2_spis_configure_defaults(uintptr_t gicd_base) +{ + unsigned int index, num_ints; + + num_ints = gicd_read_typer(gicd_base); + num_ints &= TYPER_IT_LINES_NO_MASK; + num_ints = (num_ints + 1U) << 5; + + /* + * 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); + + /* 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); + + /* Treat all SPIs as level triggered by default, 16 at a time */ + for (index = MIN_SPI_ID; index < num_ints; index += 16U) + gicd_write_icfgr(gicd_base, index, 0U); +} + +/******************************************************************************* + * Helper function to configure properties of secure G0 SPIs. + ******************************************************************************/ +void gicv2_secure_spis_configure_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + if (interrupt_props_num != 0U) + assert(interrupt_props != NULL); + + for (i = 0; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num < MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + gicd_clr_igroupr(gicd_base, prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + + /* Target the secure interrupts to primary CPU */ + gicd_set_itargetsr(gicd_base, prop_desc->intr_num, + gicv2_get_cpuif_id(gicd_base)); + + /* Set interrupt configuration */ + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, prop_desc->intr_num); + } +} + +/******************************************************************************* + * Helper function to configure properties of secure G0 SGIs and PPIs. + ******************************************************************************/ +void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, + const interrupt_prop_t *interrupt_props, + unsigned int interrupt_props_num) +{ + unsigned int i; + uint32_t sec_ppi_sgi_mask = 0; + const interrupt_prop_t *prop_desc; + + /* Make sure there's a valid property array */ + if (interrupt_props_num != 0U) + assert(interrupt_props != NULL); + + /* + * 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. + */ + gicd_write_icenabler(gicd_base, 0U, ~0U); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (i = 0U; i < MIN_SPI_ID; i += 4U) + gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); + + for (i = 0U; i < interrupt_props_num; i++) { + prop_desc = &interrupt_props[i]; + + if (prop_desc->intr_num >= MIN_SPI_ID) + continue; + + /* Configure this interrupt as a secure interrupt */ + assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); + + /* + * Set interrupt configuration for PPIs. Configuration for SGIs + * are ignored. + */ + if ((prop_desc->intr_num >= MIN_PPI_ID) && + (prop_desc->intr_num < MIN_SPI_ID)) { + gicd_set_icfgr(gicd_base, prop_desc->intr_num, + prop_desc->intr_cfg); + } + + /* We have an SGI or a PPI. They are Group0 at reset */ + sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); + + /* Set the priority of this interrupt */ + gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, + prop_desc->intr_pri); + } + + /* + * Invert the bitmask to create a mask for non-secure PPIs and SGIs. + * Program the GICD_IGROUPR0 with this bit mask. + */ + gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); + + /* Enable the Group 0 SGIs and PPIs */ + gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); +} |