From d780699b5e70337c411bc38e470de4eab03af4b6 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 9 Dec 2016 11:03:15 +0000 Subject: [PATCH 1/3] GICv3: Introduce power management APIs for Redistributor Some GICv3 implementations have provision for power management operations at Redistributor level. This patch introduces and provides place-holders for Redistributor power management. The default implementations are empty stubs, but are weakly bound so as to enable implementation-specific drivers to override them. Change-Id: I4fec1358693d3603ca5dce242a2f7f0e730516d8 Signed-off-by: Jeenu Viswambharan --- drivers/arm/gic/v3/gicv3_main.c | 23 +++++++++++++++++++++++ include/drivers/arm/gicv3.h | 2 ++ 2 files changed, 25 insertions(+) diff --git a/drivers/arm/gic/v3/gicv3_main.c b/drivers/arm/gic/v3/gicv3_main.c index ac433725f7..5abaa1ce36 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 b7ad7785bd..0f6034c0bd 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); From d17b953ab39f7915391843a71893264874ba436e Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 9 Dec 2016 11:12:34 +0000 Subject: [PATCH 2/3] Introduce ARM platform APIs for GICv3 Redistributor As with other ARM platform GIC APIs, these directly invoke the GICv3 driver APIs for Redistributor power management. For the sake of uniform GIC API, empty stubs are placed for those GIC drivers that lack Redistributor component. Change-Id: Iad0d760d4dbca790998f7768cda621ff3b15a864 Signed-off-by: Jeenu Viswambharan --- include/plat/arm/common/plat_arm.h | 2 ++ plat/arm/common/arm_gicv2.c | 14 ++++++++++++++ plat/arm/common/arm_gicv3.c | 15 +++++++++++++++ plat/arm/common/arm_gicv3_legacy.c | 14 ++++++++++++++ 4 files changed, 45 insertions(+) diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h index bc32e40fab..c167aa2c0f 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/common/arm_gicv2.c b/plat/arm/common/arm_gicv2.c index 2636d1c908..1017c9e0c5 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 ac309f2b62..6d68bfbe02 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 8396b600eb..cbf11fb550 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; +} From 74a9578c209fc96eaed4ffdd26fd0e5fe94e21a9 Mon Sep 17 00:00:00 2001 From: Jeenu Viswambharan Date: Fri, 9 Dec 2016 11:14:34 +0000 Subject: [PATCH 3/3] FVP: Avail GIC Redistributor power management Earlier patches introduced GIC Redistributor power management for ARM platforms. This patch modifies FVP power management to power down Redistributor during CPU power on/off. Change-Id: I2adb9c50a7dd750019fe3b4e576b5d5fc364bffb Signed-off-by: Jeenu Viswambharan --- plat/arm/board/fvp/fvp_pm.c | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/plat/arm/board/fvp/fvp_pm.c b/plat/arm/board/fvp/fvp_pm.c index 139f713122..fde476ada6 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] ==