diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index ac433725f71026400adb5df45a9750a5fbd78f78..5abaa1ce36914ca818d6dd38e37f87e5dbbd6c3e 100644 --- a/drivers/arm/gic/v3/gicv3_main.c +++ b/drivers/arm/gic/v3/gicv3_main.c @@ -40,6 +40,13 @@ static const gicv3_driver_data_t *driver_data; static unsigned int gicv2_compat; +/* + * Redistributor power operations are weakly bound so that they can be + * overridden + */ +#pragma weak gicv3_rdistif_off +#pragma weak gicv3_rdistif_on + /******************************************************************************* * This function initialises the ARM GICv3 driver in EL3 with provided platform * inputs. @@ -188,6 +195,9 @@ void gicv3_rdistif_init(unsigned int proc_num) assert(IS_IN_EL3()); + /* Power on redistributor */ + gicv3_rdistif_on(proc_num); + gicr_base = driver_data->rdistif_base_addrs[proc_num]; /* Set the default attribute of all SGIs and PPIs */ @@ -210,6 +220,19 @@ void gicv3_rdistif_init(unsigned int proc_num) } } +/******************************************************************************* + * Functions to perform power operations on GIC Redistributor + ******************************************************************************/ +void gicv3_rdistif_off(unsigned int proc_num) +{ + return; +} + +void gicv3_rdistif_on(unsigned int proc_num) +{ + return; +} + /******************************************************************************* * This function enables the GIC CPU interface of the calling CPU using only * system register accesses. diff --git a/include/drivers/arm/gicv3.h b/include/drivers/arm/gicv3.h index b7ad7785bdee74e2621c76592ad2b85c0db8b5f8..0f6034c0bd7b7e621d7731aeb184689dd3e8be07 100644 --- a/include/drivers/arm/gicv3.h +++ b/include/drivers/arm/gicv3.h @@ -259,6 +259,8 @@ typedef struct gicv3_driver_data { 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_rdistif_on(unsigned int proc_num); +void gicv3_rdistif_off(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); diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index bc32e40fabc84a9699e29b3586a493cf6b37306c..c167aa2c0f6f1aa27e148446ee62958760d0bc4f 100644 --- a/include/plat/arm/common/plat_arm.h +++ b/include/plat/arm/common/plat_arm.h @@ -194,6 +194,8 @@ void plat_arm_gic_driver_init(void); void plat_arm_gic_init(void); void plat_arm_gic_cpuif_enable(void); void plat_arm_gic_cpuif_disable(void); +void plat_arm_gic_redistif_on(void); +void plat_arm_gic_redistif_off(void); void plat_arm_gic_pcpu_init(void); void plat_arm_security_setup(void); void plat_arm_pwrc_setup(void); diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 139f71312231b6844d2fd56ac70b559abe336512..fde476ada61b165cdfc32b8cb1a7437d1ced5324 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -64,19 +64,6 @@ const unsigned int arm_pm_idle_states[] = { }; #endif -/******************************************************************************* - * Function which implements the common FVP specific operations to power down a - * cpu in response to a CPU_OFF or CPU_SUSPEND request. - ******************************************************************************/ -static void fvp_cpu_pwrdwn_common(void) -{ - /* Prevent interrupts from spuriously waking up this cpu */ - plat_arm_gic_cpuif_disable(); - - /* Program the power controller to power off this cpu. */ - fvp_pwrc_write_ppoffr(read_mpidr_el1()); -} - /******************************************************************************* * Function which implements the common FVP specific operations to power down a * cluster in response to a CPU_OFF or CPU_SUSPEND request. @@ -180,7 +167,15 @@ void fvp_pwr_domain_off(const psci_power_state_t *target_state) * suspended. Perform at least the cpu specific actions followed * by the cluster specific operations if applicable. */ - fvp_cpu_pwrdwn_common(); + + /* Prevent interrupts from spuriously waking up this cpu */ + plat_arm_gic_cpuif_disable(); + + /* Turn redistributor off */ + plat_arm_gic_redistif_off(); + + /* Program the power controller to power off this cpu. */ + fvp_pwrc_write_ppoffr(read_mpidr_el1()); if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) @@ -213,8 +208,17 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) /* Program the power controller to enable wakeup interrupts. */ fvp_pwrc_set_wen(mpidr); - /* Perform the common cpu specific operations */ - fvp_cpu_pwrdwn_common(); + /* Prevent interrupts from spuriously waking up this cpu */ + plat_arm_gic_cpuif_disable(); + + /* + * The Redistributor is not powered off as it can potentially prevent + * wake up events reaching the CPUIF and/or might lead to losing + * register context. + */ + + /* Program the power controller to power off this cpu. */ + fvp_pwrc_write_ppoffr(read_mpidr_el1()); /* Perform the common cluster specific operations */ if (target_state->pwr_domain_state[ARM_PWR_LVL1] == diff --git a/plat/arm/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c index 2636d1c908ba66c327a33cda561ca8c4456618ea..1017c9e0c5989fe3842e494e27135e05b48a5f70 100644 --- a/plat/arm/common/arm_gicv2.c +++ b/plat/arm/common/arm_gicv2.c @@ -97,3 +97,17 @@ void plat_arm_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); } + +/****************************************************************************** + * Stubs for Redistributor power management. Although GICv2 doesn't have + * Redistributor interface, these are provided for the sake of uniform GIC API + *****************************************************************************/ +void plat_arm_gic_redistif_on(void) +{ + return; +} + +void plat_arm_gic_redistif_off(void) +{ + return; +} diff --git a/plat/arm/common/arm_gicv3.c b/plat/arm/common/arm_gicv3.c index ac309f2b62bbbbac574c234f100c0cbd5d893272..6d68bfbe0250cb724b1c99acc8711abf83d7e634 100644 --- a/plat/arm/common/arm_gicv3.c +++ b/plat/arm/common/arm_gicv3.c @@ -43,6 +43,8 @@ #pragma weak plat_arm_gic_cpuif_enable #pragma weak plat_arm_gic_cpuif_disable #pragma weak plat_arm_gic_pcpu_init +#pragma weak plat_arm_gic_redistif_on +#pragma weak plat_arm_gic_redistif_off /* The GICv3 driver only needs to be initialized in EL3 */ static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; @@ -115,3 +117,16 @@ void plat_arm_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } + +/****************************************************************************** + * ARM common helpers to power GIC redistributor interface + *****************************************************************************/ +void plat_arm_gic_redistif_on(void) +{ + gicv3_rdistif_on(plat_my_core_pos()); +} + +void plat_arm_gic_redistif_off(void) +{ + gicv3_rdistif_off(plat_my_core_pos()); +} diff --git a/plat/arm/common/arm_gicv3_legacy.c b/plat/arm/common/arm_gicv3_legacy.c index 8396b600ebc6668bd08eb28452f56010479991de..cbf11fb55059bb0a80897ab26c6cfd753380af52 100644 --- a/plat/arm/common/arm_gicv3_legacy.c +++ b/plat/arm/common/arm_gicv3_legacy.c @@ -94,3 +94,17 @@ void plat_arm_gic_pcpu_init(void) { arm_gic_pcpu_distif_setup(); } + +/****************************************************************************** + * Stubs for Redistributor power management. Although legacy configuration isn't + * supported, these are provided for the sake of uniform GIC API + *****************************************************************************/ +void plat_arm_gic_redistif_on(void) +{ + return; +} + +void plat_arm_gic_redistif_off(void) +{ + return; +}