Home | History | Annotate | Download | only in fvp
      1 /*
      2  * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 #include <arch_helpers.h>
      8 #include <arm_config.h>
      9 #include <assert.h>
     10 #include <debug.h>
     11 #include <errno.h>
     12 #include <gicv3.h>
     13 #include <mmio.h>
     14 #include <plat_arm.h>
     15 #include <platform.h>
     16 #include <psci.h>
     17 #include <v2m_def.h>
     18 #include "drivers/pwrc/fvp_pwrc.h"
     19 #include "fvp_def.h"
     20 #include "fvp_private.h"
     21 
     22 
     23 #if ARM_RECOM_STATE_ID_ENC
     24 /*
     25  *  The table storing the valid idle power states. Ensure that the
     26  *  array entries are populated in ascending order of state-id to
     27  *  enable us to use binary search during power state validation.
     28  *  The table must be terminated by a NULL entry.
     29  */
     30 const unsigned int arm_pm_idle_states[] = {
     31 	/* State-id - 0x01 */
     32 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET,
     33 			ARM_PWR_LVL0, PSTATE_TYPE_STANDBY),
     34 	/* State-id - 0x02 */
     35 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF,
     36 			ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN),
     37 	/* State-id - 0x22 */
     38 	arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
     39 			ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN),
     40 	/* State-id - 0x222 */
     41 	arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF,
     42 		ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN),
     43 	0,
     44 };
     45 #endif
     46 
     47 /*******************************************************************************
     48  * Function which implements the common FVP specific operations to power down a
     49  * cluster in response to a CPU_OFF or CPU_SUSPEND request.
     50  ******************************************************************************/
     51 static void fvp_cluster_pwrdwn_common(void)
     52 {
     53 	uint64_t mpidr = read_mpidr_el1();
     54 
     55 #if ENABLE_SPE_FOR_LOWER_ELS
     56 	/*
     57 	 * On power down we need to disable statistical profiling extensions
     58 	 * before exiting coherency.
     59 	 */
     60 	arm_disable_spe();
     61 #endif
     62 
     63 	/* Disable coherency if this cluster is to be turned off */
     64 	fvp_interconnect_disable();
     65 
     66 	/* Program the power controller to turn the cluster off */
     67 	fvp_pwrc_write_pcoffr(mpidr);
     68 }
     69 
     70 /*
     71  * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit
     72  * on ARM GICv3 implementations on FVP. This is required, because FVP does not
     73  * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up
     74  * from `fake` system suspend the GIC must not be powered off.
     75  */
     76 void arm_gicv3_distif_pre_save(unsigned int proc_num)
     77 {}
     78 
     79 void arm_gicv3_distif_post_restore(unsigned int proc_num)
     80 {}
     81 
     82 static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
     83 {
     84 	unsigned long mpidr;
     85 
     86 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
     87 					ARM_LOCAL_STATE_OFF);
     88 
     89 	/* Get the mpidr for this cpu */
     90 	mpidr = read_mpidr_el1();
     91 
     92 	/* Perform the common cluster specific operations */
     93 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
     94 					ARM_LOCAL_STATE_OFF) {
     95 		/*
     96 		 * This CPU might have woken up whilst the cluster was
     97 		 * attempting to power down. In this case the FVP power
     98 		 * controller will have a pending cluster power off request
     99 		 * which needs to be cleared by writing to the PPONR register.
    100 		 * This prevents the power controller from interpreting a
    101 		 * subsequent entry of this cpu into a simple wfi as a power
    102 		 * down request.
    103 		 */
    104 		fvp_pwrc_write_pponr(mpidr);
    105 
    106 		/* Enable coherency if this cluster was off */
    107 		fvp_interconnect_enable();
    108 	}
    109 	/* Perform the common system specific operations */
    110 	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
    111 						ARM_LOCAL_STATE_OFF)
    112 		arm_system_pwr_domain_resume();
    113 
    114 	/*
    115 	 * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
    116 	 * with a cpu power down unless the bit is set again
    117 	 */
    118 	fvp_pwrc_clr_wen(mpidr);
    119 }
    120 
    121 
    122 /*******************************************************************************
    123  * FVP handler called when a CPU is about to enter standby.
    124  ******************************************************************************/
    125 void fvp_cpu_standby(plat_local_state_t cpu_state)
    126 {
    127 
    128 	assert(cpu_state == ARM_LOCAL_STATE_RET);
    129 
    130 	/*
    131 	 * Enter standby state
    132 	 * dsb is good practice before using wfi to enter low power states
    133 	 */
    134 	dsb();
    135 	wfi();
    136 }
    137 
    138 /*******************************************************************************
    139  * FVP handler called when a power domain is about to be turned on. The
    140  * mpidr determines the CPU to be turned on.
    141  ******************************************************************************/
    142 int fvp_pwr_domain_on(u_register_t mpidr)
    143 {
    144 	int rc = PSCI_E_SUCCESS;
    145 	unsigned int psysr;
    146 
    147 	/*
    148 	 * Ensure that we do not cancel an inflight power off request for the
    149 	 * target cpu. That would leave it in a zombie wfi. Wait for it to power
    150 	 * off and then program the power controller to turn that CPU on.
    151 	 */
    152 	do {
    153 		psysr = fvp_pwrc_read_psysr(mpidr);
    154 	} while (psysr & PSYSR_AFF_L0);
    155 
    156 	fvp_pwrc_write_pponr(mpidr);
    157 	return rc;
    158 }
    159 
    160 /*******************************************************************************
    161  * FVP handler called when a power domain is about to be turned off. The
    162  * target_state encodes the power state that each level should transition to.
    163  ******************************************************************************/
    164 void fvp_pwr_domain_off(const psci_power_state_t *target_state)
    165 {
    166 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
    167 					ARM_LOCAL_STATE_OFF);
    168 
    169 	/*
    170 	 * If execution reaches this stage then this power domain will be
    171 	 * suspended. Perform at least the cpu specific actions followed
    172 	 * by the cluster specific operations if applicable.
    173 	 */
    174 
    175 	/* Prevent interrupts from spuriously waking up this cpu */
    176 	plat_arm_gic_cpuif_disable();
    177 
    178 	/* Turn redistributor off */
    179 	plat_arm_gic_redistif_off();
    180 
    181 	/* Program the power controller to power off this cpu. */
    182 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
    183 
    184 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
    185 					ARM_LOCAL_STATE_OFF)
    186 		fvp_cluster_pwrdwn_common();
    187 
    188 }
    189 
    190 /*******************************************************************************
    191  * FVP handler called when a power domain is about to be suspended. The
    192  * target_state encodes the power state that each level should transition to.
    193  ******************************************************************************/
    194 void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
    195 {
    196 	unsigned long mpidr;
    197 
    198 	/*
    199 	 * FVP has retention only at cpu level. Just return
    200 	 * as nothing is to be done for retention.
    201 	 */
    202 	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
    203 					ARM_LOCAL_STATE_RET)
    204 		return;
    205 
    206 	assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
    207 					ARM_LOCAL_STATE_OFF);
    208 
    209 	/* Get the mpidr for this cpu */
    210 	mpidr = read_mpidr_el1();
    211 
    212 	/* Program the power controller to enable wakeup interrupts. */
    213 	fvp_pwrc_set_wen(mpidr);
    214 
    215 	/* Prevent interrupts from spuriously waking up this cpu */
    216 	plat_arm_gic_cpuif_disable();
    217 
    218 	/*
    219 	 * The Redistributor is not powered off as it can potentially prevent
    220 	 * wake up events reaching the CPUIF and/or might lead to losing
    221 	 * register context.
    222 	 */
    223 
    224 	/* Perform the common cluster specific operations */
    225 	if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
    226 					ARM_LOCAL_STATE_OFF)
    227 		fvp_cluster_pwrdwn_common();
    228 
    229 	/* Perform the common system specific operations */
    230 	if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
    231 						ARM_LOCAL_STATE_OFF)
    232 		arm_system_pwr_domain_save();
    233 
    234 	/* Program the power controller to power off this cpu. */
    235 	fvp_pwrc_write_ppoffr(read_mpidr_el1());
    236 }
    237 
    238 /*******************************************************************************
    239  * FVP handler called when a power domain has just been powered on after
    240  * being turned off earlier. The target_state encodes the low power state that
    241  * each level has woken up from.
    242  ******************************************************************************/
    243 void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
    244 {
    245 	fvp_power_domain_on_finish_common(target_state);
    246 
    247 	/* Enable the gic cpu interface */
    248 	plat_arm_gic_pcpu_init();
    249 
    250 	/* Program the gic per-cpu distributor or re-distributor interface */
    251 	plat_arm_gic_cpuif_enable();
    252 }
    253 
    254 /*******************************************************************************
    255  * FVP handler called when a power domain has just been powered on after
    256  * having been suspended earlier. The target_state encodes the low power state
    257  * that each level has woken up from.
    258  * TODO: At the moment we reuse the on finisher and reinitialize the secure
    259  * context. Need to implement a separate suspend finisher.
    260  ******************************************************************************/
    261 void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
    262 {
    263 	/*
    264 	 * Nothing to be done on waking up from retention from CPU level.
    265 	 */
    266 	if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
    267 					ARM_LOCAL_STATE_RET)
    268 		return;
    269 
    270 	fvp_power_domain_on_finish_common(target_state);
    271 
    272 	/* Enable the gic cpu interface */
    273 	plat_arm_gic_cpuif_enable();
    274 }
    275 
    276 /*******************************************************************************
    277  * FVP handlers to shutdown/reboot the system
    278  ******************************************************************************/
    279 static void __dead2 fvp_system_off(void)
    280 {
    281 	/* Write the System Configuration Control Register */
    282 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
    283 		V2M_CFGCTRL_START |
    284 		V2M_CFGCTRL_RW |
    285 		V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN));
    286 	wfi();
    287 	ERROR("FVP System Off: operation not handled.\n");
    288 	panic();
    289 }
    290 
    291 static void __dead2 fvp_system_reset(void)
    292 {
    293 	/* Write the System Configuration Control Register */
    294 	mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL,
    295 		V2M_CFGCTRL_START |
    296 		V2M_CFGCTRL_RW |
    297 		V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT));
    298 	wfi();
    299 	ERROR("FVP System Reset: operation not handled.\n");
    300 	panic();
    301 }
    302 
    303 static int fvp_node_hw_state(u_register_t target_cpu,
    304 			     unsigned int power_level)
    305 {
    306 	unsigned int psysr;
    307 	int ret;
    308 
    309 	/*
    310 	 * The format of 'power_level' is implementation-defined, but 0 must
    311 	 * mean a CPU. We also allow 1 to denote the cluster
    312 	 */
    313 	if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1)
    314 		return PSCI_E_INVALID_PARAMS;
    315 
    316 	/*
    317 	 * Read the status of the given MPDIR from FVP power controller. The
    318 	 * power controller only gives us on/off status, so map that to expected
    319 	 * return values of the PSCI call
    320 	 */
    321 	psysr = fvp_pwrc_read_psysr(target_cpu);
    322 	if (psysr == PSYSR_INVALID)
    323 		return PSCI_E_INVALID_PARAMS;
    324 
    325 	switch (power_level) {
    326 	case ARM_PWR_LVL0:
    327 		ret = (psysr & PSYSR_AFF_L0) ? HW_ON : HW_OFF;
    328 		break;
    329 	case ARM_PWR_LVL1:
    330 		ret = (psysr & PSYSR_AFF_L1) ? HW_ON : HW_OFF;
    331 		break;
    332 	}
    333 
    334 	return ret;
    335 }
    336 
    337 /*
    338  * The FVP doesn't truly support power management at SYSTEM power domain. The
    339  * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform
    340  * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver
    341  * save and restore sequences on FVP.
    342  */
    343 void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state)
    344 {
    345 	unsigned int i;
    346 
    347 	for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++)
    348 		req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF;
    349 }
    350 
    351 /*******************************************************************************
    352  * Handler to filter PSCI requests.
    353  ******************************************************************************/
    354 /*
    355  * The system power domain suspend is only supported only via
    356  * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain
    357  * will be downgraded to the lower level.
    358  */
    359 static int fvp_validate_power_state(unsigned int power_state,
    360 			    psci_power_state_t *req_state)
    361 {
    362 	int rc;
    363 	rc = arm_validate_power_state(power_state, req_state);
    364 
    365 	/*
    366 	 * Ensure that the system power domain level is never suspended
    367 	 * via PSCI CPU SUSPEND API. Currently system suspend is only
    368 	 * supported via PSCI SYSTEM SUSPEND API.
    369 	 */
    370 	req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN;
    371 	return rc;
    372 }
    373 
    374 /*
    375  * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the
    376  * `fvp_validate_power_state`, we do not downgrade the system power
    377  * domain level request in `power_state` as it will be used to query the
    378  * PSCI_STAT_COUNT/RESIDENCY at the system power domain level.
    379  */
    380 static int fvp_translate_power_state_by_mpidr(u_register_t mpidr,
    381 		unsigned int power_state,
    382 		psci_power_state_t *output_state)
    383 {
    384 	return arm_validate_power_state(power_state, output_state);
    385 }
    386 
    387 /*******************************************************************************
    388  * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard
    389  * platform layer will take care of registering the handlers with PSCI.
    390  ******************************************************************************/
    391 plat_psci_ops_t plat_arm_psci_pm_ops = {
    392 	.cpu_standby = fvp_cpu_standby,
    393 	.pwr_domain_on = fvp_pwr_domain_on,
    394 	.pwr_domain_off = fvp_pwr_domain_off,
    395 	.pwr_domain_suspend = fvp_pwr_domain_suspend,
    396 	.pwr_domain_on_finish = fvp_pwr_domain_on_finish,
    397 	.pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish,
    398 	.system_off = fvp_system_off,
    399 	.system_reset = fvp_system_reset,
    400 	.validate_power_state = fvp_validate_power_state,
    401 	.validate_ns_entrypoint = arm_validate_ns_entrypoint,
    402 	.translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr,
    403 	.get_node_hw_state = fvp_node_hw_state,
    404 	.get_sys_suspend_power_state = fvp_get_sys_suspend_power_state,
    405 /*
    406  * mem_protect is not supported in RESET_TO_BL31 and RESET_TO_SP_MIN,
    407  * as that would require mapping in all of NS DRAM into BL31 or BL32.
    408  */
    409 #if !RESET_TO_BL31 && !RESET_TO_SP_MIN
    410 	.mem_protect_chk	= arm_psci_mem_protect_chk,
    411 	.read_mem_protect	= arm_psci_read_mem_protect,
    412 	.write_mem_protect	= arm_nor_psci_write_mem_protect,
    413 #endif
    414 };
    415