diff options
-rw-r--r-- | drivers/arm/gic/v3/gicv3_main.c | 23 | ||||
-rw-r--r-- | include/drivers/arm/gicv3.h | 2 | ||||
-rw-r--r-- | include/plat/arm/common/plat_arm.h | 2 | ||||
-rw-r--r-- | plat/arm/board/fvp/fvp_pm.c | 36 | ||||
-rw-r--r-- | plat/arm/common/arm_gicv2.c | 14 | ||||
-rw-r--r-- | plat/arm/common/arm_gicv3.c | 15 | ||||
-rw-r--r-- | plat/arm/common/arm_gicv3_legacy.c | 14 |
7 files changed, 90 insertions, 16 deletions
diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index ac433725..5abaa1ce 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 */ @@ -211,6 +221,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 b7ad7785..0f6034c0 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 bc32e40f..c167aa2c 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 139f7131..fde476ad 100644 --- a/plat/arm/board/fvp/fvp_pm.c +++ b/plat/arm/board/fvp/fvp_pm.c @@ -66,19 +66,6 @@ const unsigned int arm_pm_idle_states[] = { /******************************************************************************* * 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. ******************************************************************************/ static void fvp_cluster_pwrdwn_common(void) @@ -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 2636d1c9..1017c9e0 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 ac309f2b..6d68bfbe 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 8396b600..cbf11fb5 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; +} |