diff --git a/drivers/arm/gic/v3/arm_gicv3_common.c b/drivers/arm/gic/v3/arm_gicv3_common.c new file mode 100644 index 0000000..8d552ca --- /dev/null +++ b/drivers/arm/gic/v3/arm_gicv3_common.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* + * Driver for implementation defined features that are identical in ARM GICv3 +* implementations (GIC-500 and GIC-600 for now). This driver only overrides +* APIs that are different to those generic ones in GICv3 driver. + */ + +#include +#include +#include + +#include "gicv3_private.h" +#include "arm_gicv3_common.h" + +/* + * Flush the internal GIC cache of the LPIs pending tables to memory before + * saving the state of the Redistributor. This is required before powering off + * the GIC when the pending status must be preserved. + * `rdist_proc_num` is the processor number corresponding to the Redistributor of the + * current CPU. + */ +void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num) +{ + uintptr_t gicr_base = 0; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->rdistif_base_addrs); + + /* + * The GICR_WAKER.Sleep bit should be set only when both + * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on + * all the Redistributors. + */ + for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) { + gicr_base = gicv3_driver_data->rdistif_base_addrs[i]; + assert(gicr_base); + assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT); + assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT); + } + + gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num]; + /* + * According to the TRM, there is only one instance of the + * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed + * through any of the Redistributor. + */ + + /* + * Set GICR_WAKER.Sleep + * After this point, the system must be configured so that the + * wake_request signals for the right cores are asserted when a wakeup + * interrupt is detected. The GIC will not be able to do that anymore + * when the GICR_WAKER.Sleep bit is set to 1. + */ + gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT); + + /* Wait until the GICR_WAKER.Quiescent bit is set */ + while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT)) + ; +} + +/* + * Allow the LPIs pending state to be read back from the tables in memory after + * having restored the state of the GIC Redistributor. + */ +void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num) +{ + uintptr_t gicr_base; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->rdistif_base_addrs); + + /* + * According to the TRM, there is only one instance of the + * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed + * through any of the Redistributor. + */ + gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num]; + assert(gicr_base); + + /* + * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent + * bit is not set. We should be alright on power on path, therefore + * coming out of sleep and Quiescent should be set, but we assert in + * case. + */ + assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT); + + /* Clear GICR_WAKER.Sleep */ + gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT); + + /* + * We don't know if the effects of setting GICR_WAKER.Sleep bit is + * instantaneous, so we wait until the interface is not Quiescent + * anymore. + */ + while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT) + ; +} + diff --git a/drivers/arm/gic/v3/gic500.c b/drivers/arm/gic/v3/gic500.c new file mode 100644 index 0000000..f03e33f --- /dev/null +++ b/drivers/arm/gic/v3/gic500.c @@ -0,0 +1,22 @@ +/* + * 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 index 217c08f..eb4fc54 100644 --- a/drivers/arm/gic/v3/gic600.c +++ b/drivers/arm/gic/v3/gic600.c @@ -32,9 +32,6 @@ #define PWRR_ON (0 << PWRR_RDPD_SHIFT) #define PWRR_OFF (1 << PWRR_RDPD_SHIFT) -/* Generic GICv3 resources */ -extern const gicv3_driver_data_t *gicv3_driver_data; - /* GIC600-specific accessor functions */ static void gicr_write_pwrr(uintptr_t base, unsigned int val) { @@ -82,6 +79,16 @@ } } +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 GIC600 redistributor */ diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index b68d998..83bf430 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -21,6 +21,27 @@ #pragma weak gicv3_rdistif_off #pragma weak gicv3_rdistif_on + +/* 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 += (1 << REG##_SHIFT)) { \ + gicd_write_##reg(base, int_id, \ + ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \ + } \ + } while (0) + +#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 += (1 << REG##_SHIFT)) { \ + ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\ + gicd_read_##reg(base, int_id); \ + } \ + } while (0) + + /******************************************************************************* * This function initialises the ARM GICv3 driver in EL3 with provided platform * inputs. @@ -406,3 +427,277 @@ /* Else it is a Group 0 Secure interrupt */ return INTR_GROUP0; } + +/***************************************************************************** + * 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) +{ + uintptr_t gicr_base; + unsigned int int_id; + + assert(gicv3_driver_data); + assert(proc_num < gicv3_driver_data->rdistif_num); + assert(gicv3_driver_data->rdistif_base_addrs); + assert(IS_IN_EL3()); + assert(rdist_ctx); + + gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + + /* + * Wait for any write to GICR_CTLR to complete before trying to save any + * state. + */ + gicr_wait_for_pending_write(gicr_base); + + rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base); + + 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 += (1 << IPRIORITYR_SHIFT)) { + rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] = + gicr_read_ipriorityr(gicr_base, int_id); + } + + + /* + * Call the pre-save hook that implements the IMP DEF sequence that may + * be required on some GIC implementations. As this may need to access + * the Redistributor registers, we pass it proc_num. + */ + gicv3_distif_pre_save(proc_num); +} + +/***************************************************************************** + * Function to restore the GIC Redistributor register context. We disable + * LPI and per-cpu interrupts before we start restore of the Redistributor. + * This function must be invoked after Distributor restore but prior to + * CPU interface enable. The pending and active interrupts are restored + * after the interrupts are fully configured and enabled. + *****************************************************************************/ +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; + + assert(gicv3_driver_data); + assert(proc_num < gicv3_driver_data->rdistif_num); + assert(gicv3_driver_data->rdistif_base_addrs); + assert(IS_IN_EL3()); + assert(rdist_ctx); + + gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; + + /* Power on redistributor */ + gicv3_rdistif_on(proc_num); + + /* + * Call the post-restore hook that implements the IMP DEF sequence that + * may be required on some GIC implementations. As this may need to + * access the Redistributor registers, we pass it 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 + */ + gicr_write_icenabler0(gicr_base, ~0); + /* Wait for pending writes to GICR_ICENABLER */ + gicr_wait_for_pending_write(gicr_base); + + /* + * Disable the LPIs to avoid unpredictable behavior when writing to + * GICR_PROPBASER and GICR_PENDBASER. + */ + gicr_write_ctlr(gicr_base, + rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT)); + + /* Restore registers' content */ + 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); + + for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM; + int_id += (1 << IPRIORITYR_SHIFT)) { + gicr_write_ipriorityr(gicr_base, int_id, + rdist_ctx->gicr_ipriorityr[ + (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]); + } + + 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); + + /* + * Wait for all writes to the Distributor to complete before enabling + * the SGI and PPIs. + */ + gicr_wait_for_upstream_pending_write(gicr_base); + gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0); + + /* + * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case + * the first write to GICR_CTLR was still in flight (this write only + * restores GICR_CTLR.Enable_LPIs and no waiting is required for this + * bit). + */ + gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr); + gicr_wait_for_pending_write(gicr_base); +} + +/***************************************************************************** + * Function to save the GIC Distributor register context. This function + * must be invoked after CPU interface disable and Redistributor save. + *****************************************************************************/ +void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) +{ + unsigned int num_ints; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->gicd_base); + assert(IS_IN_EL3()); + assert(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 + 1) << 5; + + assert(num_ints <= MAX_SPI_ID + 1); + + /* Wait for pending write to complete */ + gicd_wait_for_pending_write(gicd_base); + + /* Save the GICD_CTLR */ + dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base); + + /* Save GICD_IGROUPR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); + + /* Save GICD_ISENABLER for INT_IDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); + + /* Save GICD_ISPENDR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); + + /* Save GICD_ISACTIVER for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); + + /* Save GICD_IPRIORITYR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); + + /* Save GICD_ICFGR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); + + /* Save GICD_IGRPMODR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); + + /* Save GICD_NSACR for INTIDs 32 - 1020 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); + + /* Save GICD_IROUTER for INTIDs 32 - 1024 */ + SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); + + /* + * GICD_ITARGETSR and GICD_SPENDSGIR are RAZ/WI when + * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3 + * driver. + */ +} + +/***************************************************************************** + * Function to restore the GIC Distributor register context. We disable G0, G1S + * and G1NS interrupt groups before we start restore of the Distributor. This + * function must be invoked prior to Redistributor restore and CPU interface + * enable. The pending and active interrupts are restored after the interrupts + * are fully configured and enabled. + *****************************************************************************/ +void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx) +{ + unsigned int num_ints = 0; + + assert(gicv3_driver_data); + assert(gicv3_driver_data->gicd_base); + assert(IS_IN_EL3()); + assert(dist_ctx); + + uintptr_t gicd_base = gicv3_driver_data->gicd_base; + + /* + * 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(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(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 + 1) << 5; + + assert(num_ints <= MAX_SPI_ID + 1); + + /* Restore GICD_IGROUPR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); + + /* Restore GICD_IPRIORITYR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); + + /* Restore GICD_ICFGR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); + + /* Restore GICD_IGRPMODR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); + + /* Restore GICD_NSACR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); + + /* Restore GICD_IROUTER for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); + + /* + * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are + * configured. + */ + + /* Restore GICD_ISENABLER for INT_IDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); + + /* Restore GICD_ISPENDR for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); + + /* Restore GICD_ISACTIVER for INTIDs 32 - 1020 */ + RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); + + /* Restore the GICD_CTLR */ + gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr); + gicd_wait_for_pending_write(gicd_base); + +} diff --git a/drivers/arm/gic/v3/gicv3_private.h b/drivers/arm/gic/v3/gicv3_private.h index da4bcbf..7224e06 100644 --- a/drivers/arm/gic/v3/gicv3_private.h +++ b/drivers/arm/gic/v3/gicv3_private.h @@ -7,6 +7,7 @@ #ifndef __GICV3_PRIVATE_H__ #define __GICV3_PRIVATE_H__ +#include #include #include #include @@ -43,6 +44,11 @@ #endif /******************************************************************************* + * GICv3 private global variables declarations + ******************************************************************************/ +extern const gicv3_driver_data_t *gicv3_driver_data; + +/******************************************************************************* * Private GICv3 function prototypes 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. @@ -150,6 +156,11 @@ return mmio_read_64(base + GICR_CTLR); } +static inline void gicr_write_ctlr(uintptr_t base, uint64_t val) +{ + mmio_write_64(base + GICR_CTLR, val); +} + static inline unsigned long long gicr_read_typer(uintptr_t base) { return mmio_read_64(base + GICR_TYPER); @@ -178,6 +189,16 @@ ; } +static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base) +{ + while (gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT) + ; +} + +/* Private implementation of Distributor power control hooks */ +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. * Note: The raw register values correspond to multiple interrupt IDs and @@ -208,6 +229,16 @@ return mmio_read_32(base + GICR_IGROUPR0); } +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); +} + static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_IGROUPR0, val); @@ -223,14 +254,64 @@ mmio_write_32(base + GICR_IGRPMODR0, val); } +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); +} + +static inline unsigned int gicr_read_isactiver0(uintptr_t base) +{ + return mmio_read_32(base + GICR_ISACTIVER0); +} + +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) +{ + 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); } +static inline unsigned int gicr_read_propbaser(uintptr_t base) +{ + return mmio_read_32(base + GICR_PROPBASER); +} + +static inline void gicr_write_propbaser(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_PROPBASER, val); +} + +static inline unsigned int gicr_read_pendbaser(uintptr_t base) +{ + return mmio_read_32(base + GICR_PENDBASER); +} + +static inline void gicr_write_pendbaser(uintptr_t base, unsigned int val) +{ + mmio_write_32(base + GICR_PENDBASER, val); +} + #endif /* __GICV3_PRIVATE_H__ */ diff --git a/include/drivers/arm/arm_gicv3_common.h b/include/drivers/arm/arm_gicv3_common.h new file mode 100644 index 0000000..8970e3f --- /dev/null +++ b/include/drivers/arm/arm_gicv3_common.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef __ARM_GICV3_COMMON_H__ +#define __ARM_GICV3_COMMON_H__ + +/******************************************************************************* + * GIC500/GIC600 Re-distributor interface registers & constants + ******************************************************************************/ + +/* GICR_WAKER implementation-defined bit definitions */ +#define WAKER_SL_SHIFT 0 +#define WAKER_QSC_SHIFT 31 + +#define WAKER_SL_BIT (1U << WAKER_SL_SHIFT) +#define WAKER_QSC_BIT (1U << WAKER_QSC_SHIFT) + +#endif /* __ARM_GICV3_COMMON_H__ */ diff --git a/include/drivers/arm/gic_common.h b/include/drivers/arm/gic_common.h index 7e097ad..b9cae80 100644 --- a/include/drivers/arm/gic_common.h +++ b/include/drivers/arm/gic_common.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -14,6 +14,10 @@ #define MIN_SGI_ID 0 #define MIN_PPI_ID 16 #define MIN_SPI_ID 32 +#define MAX_SPI_ID 1019 + +#define TOTAL_SPI_INTR_NUM (MAX_SPI_ID - MIN_SPI_ID + 1) +#define TOTAL_PCPU_INTR_NUM (MIN_SPI_ID - MIN_SGI_ID) /* Mask for the priority field common to all GIC interfaces */ #define GIC_PRI_MASK 0xff diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index 8d9981a..d20421d 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -7,6 +7,8 @@ #ifndef __GICV3_H__ #define __GICV3_H__ +#include "utils_def.h" + /******************************************************************************* * GICv3 miscellaneous definitions ******************************************************************************/ @@ -66,9 +68,12 @@ #define GICD_CTLR_RWP_BIT (1 << GICD_CTLR_RWP_SHIFT) /* GICD_IROUTER shifts and masks */ +#define IROUTER_SHIFT 0 #define IROUTER_IRM_SHIFT 31 #define IROUTER_IRM_MASK 0x1 +#define NUM_OF_DIST_REGS 30 + /******************************************************************************* * GICv3 Re-distributor interface registers & constants ******************************************************************************/ @@ -77,18 +82,29 @@ #define GICR_CTLR 0x0 #define GICR_TYPER 0x08 #define GICR_WAKER 0x14 +#define GICR_PROPBASER 0x70 +#define GICR_PENDBASER 0x78 #define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + 0x80) #define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + 0x100) #define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + 0x180) +#define GICR_ISPENDR0 (GICR_SGIBASE_OFFSET + 0x200) +#define GICR_ICPENDR0 (GICR_SGIBASE_OFFSET + 0x280) +#define GICR_ISACTIVER0 (GICR_SGIBASE_OFFSET + 0x300) +#define GICR_ICACTIVER0 (GICR_SGIBASE_OFFSET + 0x380) #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) +#define GICR_NSACR (GICR_SGIBASE_OFFSET + 0xe00) /* GICR_CTLR bit definitions */ +#define GICR_CTLR_UWP_SHIFT 31 +#define GICR_CTLR_UWP_MASK 0x1 +#define GICR_CTLR_UWP_BIT (1U << GICR_CTLR_UWP_SHIFT) #define GICR_CTLR_RWP_SHIFT 3 #define GICR_CTLR_RWP_MASK 0x1 -#define GICR_CTLR_RWP_BIT (1 << GICR_CTLR_RWP_SHIFT) +#define GICR_CTLR_RWP_BIT (1U << GICR_CTLR_RWP_SHIFT) +#define GICR_CTLR_EN_LPIS_BIT (1U << 0) /* GICR_WAKER bit definitions */ #define WAKER_CA_SHIFT 2 @@ -111,6 +127,8 @@ #define TYPER_LAST_BIT (1 << TYPER_LAST_SHIFT) +#define NUM_OF_REDIST_REGS 30 + /******************************************************************************* * GICv3 CPU interface registers & constants ******************************************************************************/ @@ -149,8 +167,10 @@ #ifndef __ASSEMBLY__ +#include #include #include +#include #define gicv3_is_intr_id_special_identifier(id) \ (((id) >= PENDING_G1S_INTID) && ((id) <= GIC_SPURIOUS_INTERRUPT)) @@ -172,6 +192,16 @@ IAR0_EL1_INTID_MASK #define gicv3_end_of_interrupt(id) write_icc_eoir0_el1(id) +/* + * This macro returns the total number of GICD registers corresponding to + * the name. + */ +#define GICD_NUM_REGS(reg_name) \ + DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT)) + +#define GICR_NUM_REGS(reg_name) \ + DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT)) + /******************************************************************************* * 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 @@ -229,6 +259,40 @@ mpidr_hash_fn mpidr_to_core_pos; } gicv3_driver_data_t; +typedef struct gicv3_redist_ctx { + /* 64 bits registers */ + uint64_t gicr_propbaser; + uint64_t gicr_pendbaser; + + /* 32 bits registers */ + uint32_t gicr_ctlr; + uint32_t gicr_igroupr0; + uint32_t gicr_isenabler0; + uint32_t gicr_ispendr0; + uint32_t gicr_isactiver0; + uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)]; + uint32_t gicr_icfgr0; + uint32_t gicr_icfgr1; + uint32_t gicr_igrpmodr0; + uint32_t gicr_nsacr; +} gicv3_redist_ctx_t; + +typedef struct gicv3_dist_ctx { + /* 64 bits registers */ + uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM]; + + /* 32 bits registers */ + uint32_t gicd_ctlr; + uint32_t gicd_igroupr[GICD_NUM_REGS(IGROUPR)]; + uint32_t gicd_isenabler[GICD_NUM_REGS(ISENABLER)]; + uint32_t gicd_ispendr[GICD_NUM_REGS(ISPENDR)]; + uint32_t gicd_isactiver[GICD_NUM_REGS(ISACTIVER)]; + uint32_t gicd_ipriorityr[GICD_NUM_REGS(IPRIORITYR)]; + uint32_t gicd_icfgr[GICD_NUM_REGS(ICFGR)]; + uint32_t gicd_igrpmodr[GICD_NUM_REGS(IGRPMODR)]; + uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)]; +} gicv3_dist_ctx_t; + /******************************************************************************* * GICv3 EL3 driver API ******************************************************************************/ @@ -243,7 +307,18 @@ unsigned int gicv3_get_pending_interrupt_id(void); unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num); - +void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx); +void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx); +/* + * gicv3_distif_post_restore and gicv3_distif_pre_save must be implemented if + * gicv3_distif_save and gicv3_rdistif_init_restore are used. If no + * implementation-defined sequence is needed at these steps, an empty function + * can be provided. + */ +void gicv3_distif_post_restore(unsigned int proc_num); +void gicv3_distif_pre_save(unsigned int proc_num); +void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx); +void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx); #endif /* __ASSEMBLY__ */ #endif /* __GICV3_H__ */ diff --git a/include/lib/utils_def.h b/include/lib/utils_def.h index b397e30..185a1c1 100644 --- a/include/lib/utils_def.h +++ b/include/lib/utils_def.h @@ -18,6 +18,12 @@ #define BIT(nr) (1ULL << (nr)) +/* + * This variant of div_round_up can be used in macro definition but should not + * be used in C code as the `div` parameter is evaluated twice. + */ +#define DIV_ROUND_UP_2EVAL(n, d) (((n) + (d) - 1) / (d)) + #define MIN(x, y) __extension__ ({ \ __typeof__(x) _x = (x); \ __typeof__(y) _y = (y); \ @@ -49,6 +55,11 @@ #define round_down(value, boundary) \ ((value) & ~round_boundary(value, boundary)) +#define div_round_up(val, div) __extension__ ({ \ + __typeof__(div) _div = (div); \ + round_up((val), _div)/_div; \ +}) + /* * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise. * Both arguments must be unsigned pointer values (i.e. uintptr_t). diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk index 6d8aa5f..29da12e 100644 --- a/plat/arm/board/fvp/platform.mk +++ b/plat/arm/board/fvp/platform.mk @@ -48,7 +48,8 @@ # Choose the GIC sources depending upon the how the FVP will be invoked ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3) -FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} +FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \ + drivers/arm/gic/v3/gic500.c else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600) FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \ drivers/arm/gic/v3/gic600.c