diff --git a/drivers/arm/gic/common/gic_common.c b/drivers/arm/gic/common/gic_common.c new file mode 100644 index 0000000..17be61d --- /dev/null +++ b/drivers/arm/gic/common/gic_common.c @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +/******************************************************************************* + * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 n = id >> NSACR_SHIFT; + mmio_write_32(base + GICD_NSACR + (n << 2), val); +} + +/******************************************************************************* + * GIC Distributor interface accessors for individual interrupt manipulation + ******************************************************************************/ +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + return (reg_val >> bit_num) & 0x1; +} + +void gicd_set_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val | (1 << bit_num)); +} + +void gicd_clr_igroupr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igroupr(base, id); + + gicd_write_igroupr(base, id, reg_val & ~(1 << bit_num)); +} + +void gicd_set_isenabler(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISENABLER_SHIFT) - 1); + + gicd_write_isenabler(base, id, (1 << bit_num)); +} + +void gicd_set_icenabler(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICENABLER_SHIFT) - 1); + + gicd_write_icenabler(base, id, (1 << bit_num)); +} + +void gicd_set_ispendr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISPENDR_SHIFT) - 1); + + gicd_write_ispendr(base, id, (1 << bit_num)); +} + +void gicd_set_icpendr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICPENDR_SHIFT) - 1); + + gicd_write_icpendr(base, id, (1 << bit_num)); +} + +void gicd_set_isactiver(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ISACTIVER_SHIFT) - 1); + + gicd_write_isactiver(base, id, (1 << bit_num)); +} + +void gicd_set_icactiver(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << ICACTIVER_SHIFT) - 1); + + gicd_write_icactiver(base, id, (1 << bit_num)); +} diff --git a/drivers/arm/gic/v3/gicv3_helpers.c b/drivers/arm/gic/v3/gicv3_helpers.c new file mode 100644 index 0000000..6e8251d --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_helpers.c @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#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 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 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 bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * Accessor to set the bit corresponding to interrupt ID + * in GIC Distributor IGRPMODR. + */ +void gicd_set_igrpmodr(uintptr_t base, unsigned int id) +{ + unsigned bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + gicd_write_igrpmodr(base, id, reg_val | (1 << 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 bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicd_read_igrpmodr(base, id); + + gicd_write_igrpmodr(base, id, reg_val & ~(1 << 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 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 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 bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * 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 bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + gicr_write_igroupr0(base, reg_val | (1 << 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 bit_num = id & ((1 << IGROUPR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igroupr0(base); + + gicr_write_igroupr0(base, reg_val & ~(1 << 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 bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + return (reg_val >> bit_num) & 0x1; +} + +/* + * 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 bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + gicr_write_igrpmodr0(base, reg_val | (1 << 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 bit_num = id & ((1 << IGRPMODR_SHIFT) - 1); + unsigned int reg_val = gicr_read_igrpmodr0(base); + + gicr_write_igrpmodr0(base, reg_val & ~(1 << 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 bit_num = id & ((1 << ISENABLER_SHIFT) - 1); + + gicr_write_isenabler0(base, (1 << bit_num)); +} + +/****************************************************************************** + * This function marks the core as awake in the re-distributor and + * ensures that the interface is active. + *****************************************************************************/ +void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) +{ + /* + * The WAKER_PS_BIT should be changed to 0 + * only when WAKER_CA_BIT is 1. + */ + assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT); + + /* Mark the connected core as awake */ + 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) + ; +} + + +/****************************************************************************** + * This function marks the core as asleep in the re-distributor and ensures + * that the interface is quiescent. + *****************************************************************************/ +void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base) +{ + /* Mark the connected core as asleep */ + 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)) + ; +} + + +/******************************************************************************* + * This function probes the Redistributor frames when the driver is initialised + * and saves their base addresses. These base addresses are used later to + * initialise each Redistributor interface. + ******************************************************************************/ +void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, + unsigned int rdistif_num, + uintptr_t gicr_base, + mpidr_hash_fn mpidr_to_core_pos) +{ + unsigned long mpidr; + unsigned int proc_num; + unsigned long long typer_val; + uintptr_t rdistif_base = gicr_base; + + assert(rdistif_base_addrs); + + /* + * Iterate over the Redistributor frames. Store the base address of each + * frame in the platform provided array. Use the "Processor Number" + * field to index into the array if the platform has not provided a hash + * function to convert an MPIDR (obtained from the "Affinity Value" + * field into a linear index. + */ + do { + typer_val = gicr_read_typer(rdistif_base); + if (mpidr_to_core_pos) { + mpidr = mpidr_from_gicr_typer(typer_val); + proc_num = mpidr_to_core_pos(mpidr); + } else { + proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) & + TYPER_PROC_NUM_MASK; + } + assert(proc_num < rdistif_num); + rdistif_base_addrs[proc_num] = rdistif_base; + rdistif_base += (1 << GICR_PCPUBASE_SHIFT); + } while (!(typer_val & TYPER_LAST_BIT)); +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv3_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 + 1) << 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 += 32) + 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 += 4) + gicd_write_ipriorityr(gicd_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + /* + * Treat all SPIs as level triggered by default, write 16 at + * a time + */ + for (index = MIN_SPI_ID; index < num_ints; index += 16) + gicd_write_icfgr(gicd_base, index, 0); +} + +/******************************************************************************* + * Helper function to configure secure G0 and G1S SPIs. + ******************************************************************************/ +void gicv3_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp) +{ + unsigned int index, irq_num; + uint64_t gic_affinity_val; + + assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num >= MIN_SPI_ID) { + + /* Configure this interrupt as a secure interrupt */ + gicd_clr_igroupr(gicd_base, irq_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + if (int_grp == INT_TYPE_G1S) + gicd_set_igrpmodr(gicd_base, irq_num); + else + gicd_clr_igrpmodr(gicd_base, irq_num); + + /* Set the priority of this interrupt */ + gicd_write_ipriorityr(gicd_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + + /* Target SPIs to the primary CPU */ + gic_affinity_val = + gicd_irouter_val_from_mpidr(read_mpidr(), 0); + gicd_write_irouter(gicd_base, + irq_num, + gic_affinity_val); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, irq_num); + } + } + +} + +/******************************************************************************* + * Helper function to configure the default attributes of SPIs. + ******************************************************************************/ +void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base) +{ + unsigned int index; + + /* + * 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 + */ + gicr_write_icenabler0(gicr_base, ~0); + gicr_wait_for_pending_write(gicr_base); + + /* Treat all SGIs/PPIs as G1NS by default. */ + gicr_write_igroupr0(gicr_base, ~0U); + + /* Setup the default PPI/SGI priorities doing four at a time */ + for (index = 0; index < MIN_SPI_ID; index += 4) + gicr_write_ipriorityr(gicr_base, + index, + GICD_IPRIORITYR_DEF_VAL); + + /* Configure all PPIs as level triggered by default */ + gicr_write_icfgr1(gicr_base, 0); +} + +/******************************************************************************* + * Helper function to configure secure G0 and G1S SPIs. + ******************************************************************************/ +void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp) +{ + unsigned int index, irq_num; + + assert((int_grp == INT_TYPE_G1S) || (int_grp == INT_TYPE_G0)); + /* If `num_ints` is not 0, ensure that `sec_intr_list` is not NULL */ + assert(num_ints ? (uintptr_t)sec_intr_list : 1); + + for (index = 0; index < num_ints; index++) { + irq_num = sec_intr_list[index]; + if (irq_num < MIN_SPI_ID) { + + /* Configure this interrupt as a secure interrupt */ + gicr_clr_igroupr0(gicr_base, irq_num); + + /* Configure this interrupt as G0 or a G1S interrupt */ + if (int_grp == INT_TYPE_G1S) + gicr_set_igrpmodr0(gicr_base, irq_num); + else + gicr_clr_igrpmodr0(gicr_base, irq_num); + + /* Set the priority of this interrupt */ + gicr_write_ipriorityr(gicr_base, + irq_num, + GIC_HIGHEST_SEC_PRIORITY); + + /* Enable this interrupt */ + gicr_set_isenabler0(gicr_base, irq_num); + } + } +} diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c new file mode 100644 index 0000000..06311e3 --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "gicv3_private.h" + +static const gicv3_driver_data_t *driver_data; +static unsigned int gicv2_compat; + +/******************************************************************************* + * This function initialises the ARM GICv3 driver in EL3 with provided platform + * inputs. + ******************************************************************************/ +void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) +{ + unsigned int gic_version; + + assert(plat_driver_data); + assert(plat_driver_data->gicd_base); + assert(plat_driver_data->gicr_base); + assert(plat_driver_data->rdistif_num); + assert(plat_driver_data->rdistif_base_addrs); + + assert(IS_IN_EL3()); + + /* + * The platform should provide a list of at least one type of + * interrupts + */ + assert(plat_driver_data->g0_interrupt_array || + plat_driver_data->g1s_interrupt_array); + + /* + * If there are no interrupts of a particular type, then the number of + * interrupts of that type should be 0 and vice-versa. + */ + assert(plat_driver_data->g0_interrupt_array ? + plat_driver_data->g0_interrupt_num : + plat_driver_data->g0_interrupt_num == 0); + assert(plat_driver_data->g1s_interrupt_array ? + plat_driver_data->g1s_interrupt_num : + plat_driver_data->g1s_interrupt_num == 0); + + /* Check for system register support */ + assert(read_id_aa64pfr0_el1() & + (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)); + + /* 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); + + /* + * Find out whether the GIC supports the GICv2 compatibility mode. The + * ARE_S bit resets to 0 if supported + */ + gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base); + gicv2_compat >>= CTLR_ARE_S_SHIFT; + gicv2_compat = !(gicv2_compat & CTLR_ARE_S_MASK); + + /* + * Find the base address of each implemented Redistributor interface. + * The number of interfaces should be equal to the number of CPUs in the + * system. The memory for saving these addresses has to be allocated by + * the platform port + */ + gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs, + plat_driver_data->rdistif_num, + plat_driver_data->gicr_base, + plat_driver_data->mpidr_to_core_pos); + + driver_data = plat_driver_data; + + INFO("GICv3 %s legacy support detected." + " ARM GICV3 driver initialized in EL3\n", + gicv2_compat ? "with" : "without"); +} + +/******************************************************************************* + * This function initialises the GIC distributor interface based upon the data + * provided by the platform while initialising the driver. + ******************************************************************************/ +void gicv3_distif_init(void) +{ + assert(driver_data); + assert(driver_data->gicd_base); + assert(driver_data->g1s_interrupt_array); + assert(driver_data->g0_interrupt_array); + + assert(IS_IN_EL3()); + + /* + * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring + * the ARE_S bit. The Distributor might generate a system error + * otherwise. + */ + gicd_clr_ctlr(driver_data->gicd_base, + CTLR_ENABLE_G0_BIT | + CTLR_ENABLE_G1S_BIT | + CTLR_ENABLE_G1NS_BIT, + RWP_TRUE); + + /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ + gicd_set_ctlr(driver_data->gicd_base, + CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); + + /* Set the default attribute of all SPIs */ + gicv3_spis_configure_defaults(driver_data->gicd_base); + + /* Configure the G1S SPIs */ + gicv3_secure_spis_configure(driver_data->gicd_base, + driver_data->g1s_interrupt_num, + driver_data->g1s_interrupt_array, + INT_TYPE_G1S); + + /* Configure the G0 SPIs */ + gicv3_secure_spis_configure(driver_data->gicd_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array, + INT_TYPE_G0); + + /* Enable the secure SPIs now that they have been configured */ + gicd_set_ctlr(driver_data->gicd_base, + CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G0_BIT, + RWP_TRUE); +} + +/******************************************************************************* + * This function initialises the GIC Redistributor interface of the calling CPU + * (identified by the 'proc_num' parameter) based upon the data provided by the + * platform while initialising the driver. + ******************************************************************************/ +void gicv3_rdistif_init(unsigned int proc_num) +{ + uintptr_t gicr_base; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + assert(driver_data->gicd_base); + assert(gicd_read_ctlr(driver_data->gicd_base) & CTLR_ARE_S_BIT); + assert(driver_data->g1s_interrupt_array); + assert(driver_data->g0_interrupt_array); + + assert(IS_IN_EL3()); + + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + + /* Set the default attribute of all SGIs and PPIs */ + gicv3_ppi_sgi_configure_defaults(gicr_base); + + /* Configure the G1S SGIs/PPIs */ + gicv3_secure_ppi_sgi_configure(gicr_base, + driver_data->g1s_interrupt_num, + driver_data->g1s_interrupt_array, + INT_TYPE_G1S); + + /* Configure the G0 SGIs/PPIs */ + gicv3_secure_ppi_sgi_configure(gicr_base, + driver_data->g0_interrupt_num, + driver_data->g0_interrupt_array, + INT_TYPE_G0); +} + +/******************************************************************************* + * This function enables the GIC CPU interface of the calling CPU using only + * system register accesses. + ******************************************************************************/ +void gicv3_cpuif_enable(unsigned int proc_num) +{ + uintptr_t gicr_base; + unsigned int scr_el3; + unsigned int icc_sre_el3; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + assert(IS_IN_EL3()); + + /* Mark the connected core as awake */ + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + gicv3_rdistif_mark_core_awake(gicr_base); + + /* Disable the legacy interrupt bypass */ + icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT; + + /* + * Enable system register access for EL3 and allow lower exception + * levels to configure the same for themselves. If the legacy mode is + * not supported, the SRE bit is RAO/WI + */ + icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT); + write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3); + + scr_el3 = read_scr_el3(); + + /* + * Switch to NS state to write Non secure ICC_SRE_EL1 and + * ICC_SRE_EL2 registers. + */ + write_scr_el3(scr_el3 | SCR_NS_BIT); + isb(); + + write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3); + write_icc_sre_el1(ICC_SRE_SRE_BIT); + isb(); + + /* Switch to secure state. */ + write_scr_el3(scr_el3 & (~SCR_NS_BIT)); + isb(); + + /* Program the idle priority in the PMR */ + write_icc_pmr_el1(GIC_PRI_MASK); + + /* Enable Group0 interrupts */ + write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT); + + /* Enable Group1 Secure interrupts */ + write_icc_igrpen1_el3(read_icc_igrpen1_el3() | + IGRPEN1_EL3_ENABLE_G1S_BIT); + + /* Write the secure ICC_SRE_EL1 register */ + write_icc_sre_el1(ICC_SRE_SRE_BIT); + isb(); +} + +/******************************************************************************* + * This function disables the GIC CPU interface of the calling CPU using + * only system register accesses. + ******************************************************************************/ +void gicv3_cpuif_disable(unsigned int proc_num) +{ + uintptr_t gicr_base; + + assert(driver_data); + assert(proc_num < driver_data->rdistif_num); + assert(driver_data->rdistif_base_addrs); + + assert(IS_IN_EL3()); + + /* Disable legacy interrupt bypass */ + write_icc_sre_el3(read_icc_sre_el3() | + (ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)); + + /* Disable Group0 interrupts */ + write_icc_igrpen0_el1(read_icc_igrpen0_el1() & + ~IGRPEN1_EL1_ENABLE_G0_BIT); + + /* Disable Group1 Secure interrupts */ + write_icc_igrpen1_el3(read_icc_igrpen1_el3() & + ~IGRPEN1_EL3_ENABLE_G1S_BIT); + + /* Synchronise accesses to group enable registers */ + isb(); + + /* Mark the connected core as asleep */ + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + gicv3_rdistif_mark_core_asleep(gicr_base); +} + +/******************************************************************************* + * This function returns the id of the highest priority pending interrupt at + * the GIC cpu interface. + ******************************************************************************/ +unsigned int gicv3_get_pending_interrupt_id(void) +{ + unsigned int id; + + assert(IS_IN_EL3()); + id = read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; + + /* + * 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)) + return read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK; + + return id; +} + +/******************************************************************************* + * This function returns the type of the highest priority pending interrupt at + * the GIC cpu interface. The return values can be one of the following : + * PENDING_G1S_INTID : The interrupt type is secure Group 1. + * PENDING_G1NS_INTID : The interrupt type is non secure Group 1. + * 0 - 1019 : The interrupt type is secure Group 0. + * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with + * sufficient priority to be signaled + ******************************************************************************/ +unsigned int gicv3_get_pending_interrupt_type(void) +{ + assert(IS_IN_EL3()); + return read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; +} + +/******************************************************************************* + * This function returns the type of the interrupt id depending upon the group + * this interrupt has been configured under by the interrupt controller i.e. + * group0 or group1 Secure / Non Secure. The return value can be one of the + * following : + * INT_TYPE_G0 : The interrupt type is a Secure Group 0 interrupt + * INT_TYPE_G1S : The interrupt type is a Secure Group 1 secure interrupt + * INT_TYPE_G1NS: 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 igroup, grpmodr; + uintptr_t gicr_base; + + assert(IS_IN_EL3()); + assert(driver_data); + + /* Ensure the parameters are valid */ + assert(id < PENDING_G1S_INTID || id >= MIN_LPI_ID); + assert(proc_num < driver_data->rdistif_num); + + /* All LPI interrupts are Group 1 non secure */ + if (id >= MIN_LPI_ID) + return INT_TYPE_G1NS; + + if (id < MIN_SPI_ID) { + assert(driver_data->rdistif_base_addrs); + gicr_base = driver_data->rdistif_base_addrs[proc_num]; + igroup = gicr_get_igroupr0(gicr_base, id); + grpmodr = gicr_get_igrpmodr0(gicr_base, id); + } else { + assert(driver_data->gicd_base); + igroup = gicd_get_igroupr(driver_data->gicd_base, id); + grpmodr = gicd_get_igrpmodr(driver_data->gicd_base, id); + } + + /* + * If the IGROUP bit is set, then it is a Group 1 Non secure + * interrupt + */ + if (igroup) + return INT_TYPE_G1NS; + + /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */ + if (grpmodr) + return INT_TYPE_G1S; + + /* Else it is a Group 0 Secure interrupt */ + return INT_TYPE_G0; +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h new file mode 100644 index 0000000..c8b311a --- /dev/null +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV3_PRIVATE_H__ +#define __GICV3_PRIVATE_H__ + +#include +#include +#include + +/******************************************************************************* + * GICv3 private macro definitions + ******************************************************************************/ + +/* Constants to indicate the status of the RWP bit */ +#define RWP_TRUE 1 +#define RWP_FALSE 0 + +/* + * Macro 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 + */ +#define gicd_wait_for_pending_write(gicd_base) \ + do { \ + ; \ + } while (gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) + +/* + * 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 + * to GICv3. + */ +#define gicd_irouter_val_from_mpidr(mpidr, irm) \ + ((mpidr & ~(0xff << 24)) | \ + (irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT) + +/* + * Macro to wait for updates to : + * GICR_ICENABLER0 + * GICR_CTLR.DPG1S + * GICR_CTLR.DPG1NS + * GICR_CTLR.DPG0 + */ +#define gicr_wait_for_pending_write(gicr_base) \ + do { \ + ; \ + } while (gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) + +/* + * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24] + * are zeroes. + */ +#define mpidr_from_gicr_typer(typer_val) \ + ((((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) | \ + ((typer_val >> 32) & 0xffffff)) + +/******************************************************************************* + * Private function prototypes + ******************************************************************************/ +unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id); +unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int 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 gicv3_get_pending_grp1_interrupt_id(unsigned int pending_grp); +void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val); +void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); +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_igroupr0(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 gicv3_spis_configure_defaults(uintptr_t gicd_base); +void gicv3_ppi_sgi_configure_defaults(uintptr_t gicr_base); +void gicv3_secure_spis_configure(uintptr_t gicd_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp); +void gicv3_secure_ppi_sgi_configure(uintptr_t gicr_base, + unsigned int num_ints, + const unsigned int *sec_intr_list, + unsigned int int_grp); +void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, + unsigned int rdistif_num, + uintptr_t gicr_base, + mpidr_hash_fn mpidr_to_core_pos); +void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base); +void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base); + +/******************************************************************************* + * GIC Distributor interface accessors + ******************************************************************************/ +static inline unsigned int 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) +{ + return mmio_read_64(base + GICD_IROUTER + (id << 3)); +} + +static inline void gicd_write_irouter(uintptr_t base, + unsigned int id, + unsigned long long affinity) +{ + mmio_write_64(base + GICD_IROUTER + (id << 3), affinity); +} + +static inline void gicd_clr_ctlr(uintptr_t base, + unsigned int bitmap, + unsigned int rwp) +{ + gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap); + if (rwp) + gicd_wait_for_pending_write(base); +} + +static inline void gicd_set_ctlr(uintptr_t base, + unsigned int bitmap, + unsigned int rwp) +{ + gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap); + if (rwp) + gicd_wait_for_pending_write(base); +} + +/******************************************************************************* + * GIC Redistributor interface accessors + ******************************************************************************/ +static inline unsigned long long gicr_read_ctlr(uintptr_t base) +{ + return mmio_read_64(base + GICR_CTLR); +} + +static inline unsigned long long gicr_read_typer(uintptr_t base) +{ + return mmio_read_64(base + GICR_TYPER); +} + +static inline unsigned int 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) +{ + mmio_write_32(base + GICR_WAKER, val); +} + +static inline unsigned int gicr_read_icenabler0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICENABLER0); +} + +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) +{ + return mmio_read_32(base + GICR_ISENABLER0); +} + +static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ISENABLER0, val); +} + +static inline unsigned int gicr_read_igroupr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_IGROUPR0); +} + +static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_IGROUPR0, val); +} + +static inline unsigned int gicr_read_igrpmodr0(uintptr_t base) +{ + return mmio_read_32(base + GICR_IGRPMODR0); +} + +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_icfgr1(uintptr_t base) +{ + return mmio_read_32(base + GICR_ICFGR1); +} + +static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_ICFGR1, val); +} + +#endif /* __GICV3_PRIVATE_H__ */ diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h new file mode 100644 index 0000000..6a322a2 --- /dev/null +++ b/include/drivers/arm/gic_common.h @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GIC_COMMON_H__ +#define __GIC_COMMON_H__ + +/******************************************************************************* + * GIC Distributor interface general definitions + ******************************************************************************/ +/* Constants to categorise interrupts */ +#define MIN_SGI_ID 0 +#define MIN_PPI_ID 16 +#define MIN_SPI_ID 32 + +/* Mask for the priority field common to all GIC interfaces */ +#define GIC_PRI_MASK 0xff + +/* Constant to indicate a spurious interrupt in all GIC versions */ +#define GIC_SPURIOUS_INTERRUPT 1023 + +/* Constants to categorise priorities */ +#define GIC_HIGHEST_SEC_PRIORITY 0 +#define GIC_LOWEST_SEC_PRIORITY 127 +#define GIC_HIGHEST_NS_PRIORITY 128 +#define GIC_LOWEST_NS_PRIORITY 254 /* 255 would disable an interrupt */ + +/******************************************************************************* + * GIC Distributor interface register offsets that are common to GICv3 & GICv2 + ******************************************************************************/ +#define GICD_CTLR 0x0 +#define GICD_TYPER 0x4 +#define GICD_IIDR 0x8 +#define GICD_IGROUPR 0x80 +#define GICD_ISENABLER 0x100 +#define GICD_ICENABLER 0x180 +#define GICD_ISPENDR 0x200 +#define GICD_ICPENDR 0x280 +#define GICD_ISACTIVER 0x300 +#define GICD_ICACTIVER 0x380 +#define GICD_IPRIORITYR 0x400 +#define GICD_ICFGR 0xc00 +#define GICD_NSACR 0xe00 + +/* GICD_CTLR bit definitions */ +#define CTLR_ENABLE_G0_SHIFT 0 +#define CTLR_ENABLE_G0_MASK 0x1 +#define CTLR_ENABLE_G0_BIT (1 << CTLR_ENABLE_G0_SHIFT) + + +/******************************************************************************* + * GIC Distributor interface register constants that are common to GICv3 & GICv2 + ******************************************************************************/ +#define PIDR2_ARCH_REV_SHIFT 4 +#define PIDR2_ARCH_REV_MASK 0xf + +/* GICv3 revision as reported by the PIDR2 register */ +#define ARCH_REV_GICV3 0x3 +/* GICv2 revision as reported by the PIDR2 register */ +#define ARCH_REV_GICV2 0x2 + +#define IGROUPR_SHIFT 5 +#define ISENABLER_SHIFT 5 +#define ICENABLER_SHIFT ISENABLER_SHIFT +#define ISPENDR_SHIFT 5 +#define ICPENDR_SHIFT ISPENDR_SHIFT +#define ISACTIVER_SHIFT 5 +#define ICACTIVER_SHIFT ISACTIVER_SHIFT +#define IPRIORITYR_SHIFT 2 +#define ICFGR_SHIFT 4 +#define NSACR_SHIFT 4 + +/* GICD_TYPER shifts and masks */ +#define TYPER_IT_LINES_NO_SHIFT 0 +#define TYPER_IT_LINES_NO_MASK 0x1f + +/* Value used to initialize Normal world interrupt priorities four at a time */ +#define GICD_IPRIORITYR_DEF_VAL \ + (GIC_HIGHEST_NS_PRIORITY | \ + (GIC_HIGHEST_NS_PRIORITY << 8) | \ + (GIC_HIGHEST_NS_PRIORITY << 16) | \ + (GIC_HIGHEST_NS_PRIORITY << 24)) + +#ifndef __ASSEMBLY__ + +#include +#include + +/******************************************************************************* + * GIC Distributor interface register accessors that are common to GICv3 & GICv2 + ******************************************************************************/ +static inline unsigned int gicd_read_ctlr(uintptr_t base) +{ + return mmio_read_32(base + GICD_CTLR); +} + +static inline unsigned int gicd_read_typer(uintptr_t base) +{ + return mmio_read_32(base + GICD_TYPER); +} + +static inline unsigned int gicd_read_iidr(uintptr_t base) +{ + return mmio_read_32(base + GICD_IIDR); +} + +static inline void gicd_write_ctlr(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICD_CTLR, val); +} + +/******************************************************************************* + * GIC Distributor function prototypes + ******************************************************************************/ +unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id); +unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id); +unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id); +unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id); +unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id); +unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id); +unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id); +unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id); +unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id); +unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id); +void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val); +void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val); +unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id); +void gicd_set_igroupr(uintptr_t base, unsigned int id); +void gicd_clr_igroupr(uintptr_t base, unsigned int id); +void gicd_set_isenabler(uintptr_t base, unsigned int id); +void gicd_set_icenabler(uintptr_t base, unsigned int id); +void gicd_set_ispendr(uintptr_t base, unsigned int id); +void gicd_set_icpendr(uintptr_t base, unsigned int id); +void gicd_set_isactiver(uintptr_t base, unsigned int id); +void gicd_set_icactiver(uintptr_t base, unsigned int id); + + +#endif /* __ASSEMBLY__ */ +#endif /* __GIC_COMMON_H__ */ diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h new file mode 100644 index 0000000..e874f5c --- /dev/null +++ b/include/drivers/arm/gicv3.h @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __GICV3_H__ +#define __GICV3_H__ + +/******************************************************************************* + * GICv3 miscellaneous definitions + ******************************************************************************/ +/* Interrupt group definitions */ +#define INT_TYPE_G1S 0 +#define INT_TYPE_G0 1 +#define INT_TYPE_G1NS 2 + +/* Interrupt IDs reported by the HPPIR and IAR registers */ +#define PENDING_G1S_INTID 1020 +#define PENDING_G1NS_INTID 1021 + +/* Constant to categorize LPI interrupt */ +#define MIN_LPI_ID 8192 + +/******************************************************************************* + * GICv3 specific Distributor interface register offsets and constants. + ******************************************************************************/ +#define GICD_STATUSR 0x10 +#define GICD_SETSPI_NSR 0x40 +#define GICD_CLRSPI_NSR 0x48 +#define GICD_SETSPI_SR 0x50 +#define GICD_CLRSPI_SR 0x50 +#define GICD_IGRPMODR 0xd00 +#define GICD_IROUTER 0x6100 +#define GICD_PIDR2_GICV3 0xffe8 + +#define IGRPMODR_SHIFT 5 + +/* GICD_CTLR bit definitions */ +#define CTLR_ENABLE_G1NS_SHIFT 1 +#define CTLR_ENABLE_G1S_SHIFT 2 +#define CTLR_ARE_S_SHIFT 4 +#define CTLR_ARE_NS_SHIFT 5 +#define CTLR_DS_SHIFT 6 +#define CTLR_E1NWF_SHIFT 7 +#define GICD_CTLR_RWP_SHIFT 31 + +#define CTLR_ENABLE_G1NS_MASK 0x1 +#define CTLR_ENABLE_G1S_MASK 0x1 +#define CTLR_ARE_S_MASK 0x1 +#define CTLR_ARE_NS_MASK 0x1 +#define CTLR_DS_MASK 0x1 +#define CTLR_E1NWF_MASK 0x1 +#define GICD_CTLR_RWP_MASK 0x1 + +#define CTLR_ENABLE_G1NS_BIT (1 << CTLR_ENABLE_G1NS_SHIFT) +#define CTLR_ENABLE_G1S_BIT (1 << CTLR_ENABLE_G1S_SHIFT) +#define CTLR_ARE_S_BIT (1 << CTLR_ARE_S_SHIFT) +#define CTLR_ARE_NS_BIT (1 << CTLR_ARE_NS_SHIFT) +#define CTLR_DS_BIT (1 << CTLR_DS_SHIFT) +#define CTLR_E1NWF_BIT (1 << CTLR_E1NWF_SHIFT) +#define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT) + +/* GICD_IROUTER shifts and masks */ +#define IROUTER_IRM_SHIFT 31 +#define IROUTER_IRM_MASK 0x1 + +/******************************************************************************* + * GICv3 Re-distributor interface registers & constants + ******************************************************************************/ +#define GICR_PCPUBASE_SHIFT 0x11 +#define GICR_SGIBASE_OFFSET (1 << 0x10) /* 64 KB */ +#define GICR_CTLR 0x0 +#define GICR_TYPER 0x08 +#define GICR_WAKER 0x14 +#define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80) +#define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100) +#define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180) +#define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + 0x400) +#define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + 0xc00) +#define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + 0xc04) +#define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + 0xd00) + +/* GICR_CTLR bit definitions */ +#define GICR_CTLR_RWP_SHIFT 3 +#define GICR_CTLR_RWP_MASK 0x1 +#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT) + +/* GICR_WAKER bit definitions */ +#define WAKER_CA_SHIFT 2 +#define WAKER_PS_SHIFT 1 + +#define WAKER_CA_MASK 0x1 +#define WAKER_PS_MASK 0x1 + +#define WAKER_CA_BIT (1 << WAKER_CA_SHIFT) +#define WAKER_PS_BIT (1 << WAKER_PS_SHIFT) + +/* GICR_TYPER bit definitions */ +#define TYPER_AFF_VAL_SHIFT 32 +#define TYPER_PROC_NUM_SHIFT 8 +#define TYPER_LAST_SHIFT 4 + +#define TYPER_AFF_VAL_MASK 0xffffffff +#define TYPER_PROC_NUM_MASK 0xffff +#define TYPER_LAST_MASK 0x1 + +#define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT) + +/******************************************************************************* + * GICv3 CPU interface registers & constants + ******************************************************************************/ +/* ICC_SRE bit definitions*/ +#define ICC_SRE_EN_BIT (1 << 3) +#define ICC_SRE_DIB_BIT (1 << 2) +#define ICC_SRE_DFB_BIT (1 << 1) +#define ICC_SRE_SRE_BIT (1 << 0) + +/* ICC_IGRPEN1_EL3 bit definitions */ +#define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0 +#define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1 + +#define IGRPEN1_EL3_ENABLE_G1NS_BIT (1 << IGRPEN1_EL3_ENABLE_G1NS_SHIFT) +#define IGRPEN1_EL3_ENABLE_G1S_BIT (1 << IGRPEN1_EL3_ENABLE_G1S_SHIFT) + +/* ICC_IGRPEN0_EL1 bit definitions */ +#define IGRPEN1_EL1_ENABLE_G0_SHIFT 0 +#define IGRPEN1_EL1_ENABLE_G0_BIT (1 << IGRPEN1_EL1_ENABLE_G0_SHIFT) + +/* ICC_HPPIR0_EL1 bit definitions */ +#define HPPIR0_EL1_INTID_SHIFT 0 +#define HPPIR0_EL1_INTID_MASK 0xffffff + +/* ICC_HPPIR1_EL1 bit definitions */ +#define HPPIR1_EL1_INTID_SHIFT 0 +#define HPPIR1_EL1_INTID_MASK 0xffffff + +/* ICC_IAR0_EL1 bit definitions */ +#define IAR0_EL1_INTID_SHIFT 0 +#define IAR0_EL1_INTID_MASK 0xffffff + +/* ICC_IAR1_EL1 bit definitions */ +#define IAR1_EL1_INTID_SHIFT 0 +#define IAR1_EL1_INTID_MASK 0xffffff + +#ifndef __ASSEMBLY__ + +#include + +#define gicv3_is_intr_id_special_identifier(id) \ + (((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT)) + +/******************************************************************************* + * Helper GICv3 macros for SEL1 + ******************************************************************************/ +#define gicv3_acknowledge_interrupt_sel1() read_icc_iar1_el1() &\ + IAR1_EL1_INTID_MASK +#define gicv3_get_pending_interrupt_id_sel1() read_icc_hppir1_el1() &\ + HPPIR1_EL1_INTID_MASK +#define gicv3_end_of_interrupt_sel1(id) write_icc_eoir1_el1(id) + + +/******************************************************************************* + * Helper GICv3 macros for EL3 + ******************************************************************************/ +#define gicv3_acknowledge_interrupt() read_icc_iar0_el1() &\ + IAR0_EL1_INTID_MASK +#define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id) + +/******************************************************************************* + * This structure describes some of the implementation defined attributes of the + * GICv3 IP. It is used by the platform port to specify these attributes in order + * to initialise the GICV3 driver. The attributes are described below. + * + * 1. The 'gicd_base' field contains the base address of the Distributor + * interface programmer's view. + * + * 2. The 'gicr_base' field contains the base address of the Re-distributor + * interface programmer's view. + * + * 3. The 'g0_interrupt_array' field is a ponter to an array in which each + * entry corresponds to an ID of a Group 0 interrupt. + * + * 4. The 'g0_interrupt_num' field contains the number of entries in the + * 'g0_interrupt_array'. + * + * 5. The 'g1s_interrupt_array' field is a ponter to an array in which each + * entry corresponds to an ID of a Group 1 interrupt. + * + * 6. The 'g1s_interrupt_num' field contains the number of entries in the + * 'g1s_interrupt_array'. + * + * 7. The 'rdistif_num' field contains the number of Redistributor interfaces + * the GIC implements. This is equal to the number of CPUs or CPU interfaces + * instantiated in the GIC. + * + * 8. The 'rdistif_base_addrs' field is a pointer to an array that has an entry + * for storing the base address of the Redistributor interface frame of each + * CPU in the system. The size of the array = 'rdistif_num'. The base + * addresses are detected during driver initialisation. + * + * 9. The 'mpidr_to_core_pos' field is a pointer to a hash function which the + * driver will use to convert an MPIDR value to a linear core index. This + * index will be used for accessing the 'rdistif_base_addrs' array. This is + * an optional field. A GICv3 implementation maps each MPIDR to a linear core + * index as well. This mapping can be found by reading the "Affinity Value" + * and "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the + * "Processor Numbers" are suitable to index into an array to access core + * specific information. If this not the case, the platform port must provide + * a hash function. Otherwise, the "Processor Number" field will be used to + * access the array elements. + ******************************************************************************/ +typedef unsigned int (*mpidr_hash_fn)(unsigned long mpidr); + +typedef struct gicv3_driver_data { + uintptr_t gicd_base; + uintptr_t gicr_base; + unsigned int g0_interrupt_num; + unsigned int g1s_interrupt_num; + const unsigned int *g0_interrupt_array; + const unsigned int *g1s_interrupt_array; + unsigned int rdistif_num; + uintptr_t *rdistif_base_addrs; + mpidr_hash_fn mpidr_to_core_pos; +} gicv3_driver_data_t; + +/******************************************************************************* + * GICv3 EL3 driver API + ******************************************************************************/ +void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data); +void gicv3_distif_init(void); +void gicv3_rdistif_init(unsigned int proc_num); +void gicv3_cpuif_enable(unsigned int proc_num); +void gicv3_cpuif_disable(unsigned int proc_num); +unsigned int gicv3_get_pending_interrupt_type(void); +unsigned int gicv3_get_pending_interrupt_id(void); +unsigned int gicv3_get_interrupt_type(unsigned int id, + unsigned int proc_num); + + +#endif /* __ASSEMBLY__ */ +#endif /* __GICV3_H__ */ diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h index 9aea2c9..49efafc 100644 --- a/include/lib/aarch64/arch.h +++ b/include/lib/aarch64/arch.h @@ -88,6 +88,14 @@ #define ICC_CTLR_EL1 S3_0_C12_C12_4 #define ICC_CTLR_EL3 S3_6_C12_C12_4 #define ICC_PMR_EL1 S3_0_C4_C6_0 +#define ICC_IGRPEN1_EL3 S3_6_c12_c12_7 +#define ICC_IGRPEN0_EL1 S3_0_c12_c12_6 +#define ICC_HPPIR0_EL1 S3_0_c12_c8_2 +#define ICC_HPPIR1_EL1 S3_0_c12_c12_2 +#define ICC_IAR0_EL1 S3_0_c12_c8_0 +#define ICC_IAR1_EL1 S3_0_c12_c12_0 +#define ICC_EOIR0_EL1 S3_0_c12_c8_1 +#define ICC_EOIR1_EL1 S3_0_c12_c12_1 /******************************************************************************* * Generic timer memory mapped registers & offsets @@ -122,6 +130,10 @@ #define ID_AA64PFR0_EL3_SHIFT 12 #define ID_AA64PFR0_ELX_MASK 0xf +#define ID_AA64PFR0_GIC_SHIFT 24 +#define ID_AA64PFR0_GIC_WIDTH 4 +#define ID_AA64PFR0_GIC_MASK ((1 << ID_AA64PFR0_GIC_WIDTH) - 1) + /* ID_PFR1_EL1 definitions */ #define ID_PFR1_VIRTEXT_SHIFT 12 #define ID_PFR1_VIRTEXT_MASK 0xf diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h index d01ea31..43c6917 100644 --- a/include/lib/aarch64/arch_helpers.h +++ b/include/lib/aarch64/arch_helpers.h @@ -74,6 +74,14 @@ _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) +/* Define read function for renamed system register */ +#define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \ + _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) + +/* Define write function for renamed system register */ +#define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \ + _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) + /* Define write function for special system registers */ #define DEFINE_SYSREG_WRITE_CONST_FUNC(_name) \ _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _name) @@ -284,12 +292,18 @@ DEFINE_SYSREG_READ_FUNC(ctr_el0) -/* GICv3 System Registers */ - DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3) +DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1) +DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1) +DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1) +DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1) #define IS_IN_EL(x) \