diff options
author | danh-arm <dan.handley@arm.com> | 2015-12-08 14:02:45 +0000 |
---|---|---|
committer | danh-arm <dan.handley@arm.com> | 2015-12-08 14:02:45 +0000 |
commit | 05a91fb008c31f939a9590318e2914b44cdad165 (patch) | |
tree | 45a9e8b150320531cab2393e64fbe873ed702a36 /plat/nvidia/tegra/common/tegra_pm.c | |
parent | f3974ea5b17b0ec88091a8a8c59e56da0fe507f0 (diff) | |
parent | 71cb26ea5b9908dfd04dc3048894e751ea8f4b99 (diff) |
Merge pull request #452 from vwadekar/tegra-new-platform-apis-v2
Tegra new platform apis v2
Diffstat (limited to 'plat/nvidia/tegra/common/tegra_pm.c')
-rw-r--r-- | plat/nvidia/tegra/common/tegra_pm.c | 256 |
1 files changed, 101 insertions, 155 deletions
diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index c2c73f63..6fb3e9c6 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -44,35 +44,34 @@ #include <tegra_private.h> extern uint64_t tegra_bl31_phys_base; -extern uint64_t sec_entry_point[PLATFORM_CORE_COUNT]; -static int system_suspended; +extern uint64_t tegra_sec_entry_point; /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. */ -#pragma weak tegra_soc_prepare_cpu_suspend -#pragma weak tegra_soc_prepare_cpu_on -#pragma weak tegra_soc_prepare_cpu_off -#pragma weak tegra_soc_prepare_cpu_on_finish +#pragma weak tegra_soc_pwr_domain_suspend +#pragma weak tegra_soc_pwr_domain_on +#pragma weak tegra_soc_pwr_domain_off +#pragma weak tegra_soc_pwr_domain_on_finish #pragma weak tegra_soc_prepare_system_reset -int tegra_soc_prepare_cpu_suspend(unsigned int id, unsigned int afflvl) +int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { return PSCI_E_NOT_SUPPORTED; } -int tegra_soc_prepare_cpu_on(unsigned long mpidr) +int tegra_soc_pwr_domain_on(u_register_t mpidr) { return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_off(unsigned long mpidr) +int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { return PSCI_E_SUCCESS; } -int tegra_soc_prepare_cpu_on_finish(unsigned long mpidr) +int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { return PSCI_E_SUCCESS; } @@ -83,33 +82,25 @@ int tegra_soc_prepare_system_reset(void) } /******************************************************************************* - * Track system suspend entry. - ******************************************************************************/ -void tegra_pm_system_suspend_entry(void) -{ - system_suspended = 1; -} - -/******************************************************************************* - * Track system suspend exit. - ******************************************************************************/ -void tegra_pm_system_suspend_exit(void) + * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` + * call to get the `power_state` parameter. This allows the platform to encode + * the appropriate State-ID field within the `power_state` parameter which can + * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. +******************************************************************************/ +void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { - system_suspended = 0; -} + /* lower affinities use PLAT_MAX_OFF_STATE */ + for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; -/******************************************************************************* - * Get the system suspend state. - ******************************************************************************/ -int tegra_system_suspended(void) -{ - return system_suspended; + /* max affinity uses system suspend state id */ + req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; } /******************************************************************************* * Handler called when an affinity instance is about to enter standby. ******************************************************************************/ -void tegra_affinst_standby(unsigned int power_state) +void tegra_cpu_standby(plat_local_state_t cpu_state) { /* * Enter standby state @@ -120,132 +111,45 @@ void tegra_affinst_standby(unsigned int power_state) } /******************************************************************************* - * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` - * call to get the `power_state` parameter. This allows the platform to encode - * the appropriate State-ID field within the `power_state` parameter which can - * be utilized in `affinst_suspend()` to suspend to system affinity level. -******************************************************************************/ -unsigned int tegra_get_sys_suspend_power_state(void) -{ - unsigned int power_state; - - power_state = psci_make_powerstate(PLAT_SYS_SUSPEND_STATE_ID, - PSTATE_TYPE_POWERDOWN, MPIDR_AFFLVL2); - - return power_state; -} - -/******************************************************************************* - * Handler called to check the validity of the power state parameter. - ******************************************************************************/ -int32_t tegra_validate_power_state(unsigned int power_state) -{ - return tegra_soc_validate_power_state(power_state); -} - -/******************************************************************************* * Handler called when an affinity instance is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ -int tegra_affinst_on(unsigned long mpidr, - unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +int tegra_pwr_domain_on(u_register_t mpidr) { - int cpu = mpidr & MPIDR_CPU_MASK; - - /* - * Support individual CPU power on only. - */ - if (afflvl > MPIDR_AFFLVL0) - return PSCI_E_SUCCESS; - - /* - * Flush entrypoint variable to PoC since it will be - * accessed after a reset with the caches turned off. - */ - sec_entry_point[cpu] = sec_entrypoint; - flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); - - return tegra_soc_prepare_cpu_on(mpidr); + return tegra_soc_pwr_domain_on(mpidr); } /******************************************************************************* - * Handler called when an affinity instance is about to be turned off. The - * level determines the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take apt - * actions. - * - * CAUTION: This function is called with coherent stacks so that caches can be - * turned off, flushed and coherency disabled. There is no guarantee that caches - * will remain turned on across calls to this function as each affinity level is - * dealt with. So do not write & read global variables across calls. It will be - * wise to do flush a write to the global to prevent unpredictable results. + * Handler called when a power domain is about to be turned off. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_off(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_off(const psci_power_state_t *target_state) { - /* - * Support individual CPU power off only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - - tegra_soc_prepare_cpu_off(read_mpidr()); + tegra_soc_pwr_domain_off(target_state); } /******************************************************************************* - * Handler called when an affinity instance is about to be suspended. The - * level and mpidr determine the affinity instance. The 'state' arg. allows the - * platform to decide whether the cluster is being turned off and take apt - * actions. - * - * CAUTION: This function is called with coherent stacks so that caches can be - * turned off, flushed and coherency disabled. There is no guarantee that caches - * will remain turned on across calls to this function as each affinity level is - * dealt with. So do not write & read global variables across calls. It will be - * wise to flush a write to the global variable, to prevent unpredictable - * results. + * Handler called when called when a power domain is about to be suspended. The + * target_state encodes the power state that each level should transition to. ******************************************************************************/ -void tegra_affinst_suspend(unsigned long sec_entrypoint, - unsigned int afflvl, - unsigned int state) +void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) { - int id = psci_get_suspend_stateid(); - int cpu = read_mpidr() & MPIDR_CPU_MASK; - - if (afflvl > PLATFORM_MAX_AFFLVL) - return; - - /* - * Flush entrypoint variable to PoC since it will be - * accessed after a reset with the caches turned off. - */ - sec_entry_point[cpu] = sec_entrypoint; - flush_dcache_range((uint64_t)&sec_entry_point[cpu], sizeof(uint64_t)); - - tegra_soc_prepare_cpu_suspend(id, afflvl); + tegra_soc_pwr_domain_suspend(target_state); /* disable GICC */ tegra_gic_cpuif_deactivate(); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * being turned off earlier. The level determines the affinity instance. - * The 'state' arg. allows the platform to decide whether the cluster was - * turned off prior to wakeup and do what's necessary to set it up. + * Handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. ******************************************************************************/ -void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) { plat_params_from_bl2_t *plat_params; /* - * Support individual CPU power on only. - */ - if (afflvl > MPIDR_AFFLVL0) - return; - - /* * Initialize the GIC cpu and distributor interfaces */ tegra_gic_setup(); @@ -253,7 +157,8 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) /* * Check if we are exiting from deep sleep. */ - if (tegra_system_suspended()) { + if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == + PSTATE_ID_SOC_POWERDN) { /* * Lock scratch registers which hold the CPU vectors. @@ -276,18 +181,17 @@ void tegra_affinst_on_finish(unsigned int afflvl, unsigned int state) /* * Reset hardware settings. */ - tegra_soc_prepare_cpu_on_finish(read_mpidr()); + tegra_soc_pwr_domain_on_finish(target_state); } /******************************************************************************* - * Handler called when an affinity instance has just been powered on after - * having been suspended earlier. The level and mpidr determine the affinity - * instance. + * Handler called when a power domain has just been powered on after + * having been suspended earlier. The target_state encodes the low power state + * that each level has woken up from. ******************************************************************************/ -void tegra_affinst_suspend_finish(unsigned int afflvl, unsigned int state) +void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { - if (afflvl == MPIDR_AFFLVL0) - tegra_affinst_on_finish(afflvl, state); + tegra_pwr_domain_on_finish(target_state); } /******************************************************************************* @@ -314,35 +218,77 @@ __dead2 void tegra_system_reset(void) } /******************************************************************************* + * Handler called to check the validity of the power state parameter. + ******************************************************************************/ +int32_t tegra_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + + assert(req_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + + return tegra_soc_validate_power_state(power_state, req_state); +} + +/******************************************************************************* + * Platform handler called to check the validity of the non secure entrypoint. + ******************************************************************************/ +int tegra_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) + return PSCI_E_SUCCESS; + + return PSCI_E_INVALID_ADDRESS; +} + +/******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ -static const plat_pm_ops_t tegra_plat_pm_ops = { - .affinst_standby = tegra_affinst_standby, - .affinst_on = tegra_affinst_on, - .affinst_off = tegra_affinst_off, - .affinst_suspend = tegra_affinst_suspend, - .affinst_on_finish = tegra_affinst_on_finish, - .affinst_suspend_finish = tegra_affinst_suspend_finish, - .system_off = tegra_system_off, - .system_reset = tegra_system_reset, - .validate_power_state = tegra_validate_power_state, - .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state +static const plat_psci_ops_t tegra_plat_psci_ops = { + .cpu_standby = tegra_cpu_standby, + .pwr_domain_on = tegra_pwr_domain_on, + .pwr_domain_off = tegra_pwr_domain_off, + .pwr_domain_suspend = tegra_pwr_domain_suspend, + .pwr_domain_on_finish = tegra_pwr_domain_on_finish, + .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, + .system_off = tegra_system_off, + .system_reset = tegra_system_reset, + .validate_power_state = tegra_validate_power_state, + .validate_ns_entrypoint = tegra_validate_ns_entrypoint, + .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, }; /******************************************************************************* - * Export the platform specific power ops & initialize the fvp power controller + * Export the platform specific power ops and initialize Power Controller ******************************************************************************/ -int platform_setup_pm(const plat_pm_ops_t **plat_ops) +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) { + psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; + + /* + * Flush entrypoint variable to PoC since it will be + * accessed after a reset with the caches turned off. + */ + tegra_sec_entry_point = sec_entrypoint; + flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); + /* * Reset hardware settings. */ - tegra_soc_prepare_cpu_on_finish(read_mpidr()); + tegra_soc_pwr_domain_on_finish(&target_state); /* - * Initialize PM ops struct + * Initialize PSCI ops struct */ - *plat_ops = &tegra_plat_pm_ops; + *psci_ops = &tegra_plat_psci_ops; return 0; } |