108438e24SVarun Wadekar /* 208438e24SVarun Wadekar * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 308438e24SVarun Wadekar * 408438e24SVarun Wadekar * Redistribution and use in source and binary forms, with or without 508438e24SVarun Wadekar * modification, are permitted provided that the following conditions are met: 608438e24SVarun Wadekar * 708438e24SVarun Wadekar * Redistributions of source code must retain the above copyright notice, this 808438e24SVarun Wadekar * list of conditions and the following disclaimer. 908438e24SVarun Wadekar * 1008438e24SVarun Wadekar * Redistributions in binary form must reproduce the above copyright notice, 1108438e24SVarun Wadekar * this list of conditions and the following disclaimer in the documentation 1208438e24SVarun Wadekar * and/or other materials provided with the distribution. 1308438e24SVarun Wadekar * 1408438e24SVarun Wadekar * Neither the name of ARM nor the names of its contributors may be used 1508438e24SVarun Wadekar * to endorse or promote products derived from this software without specific 1608438e24SVarun Wadekar * prior written permission. 1708438e24SVarun Wadekar * 1808438e24SVarun Wadekar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1908438e24SVarun Wadekar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2008438e24SVarun Wadekar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2108438e24SVarun Wadekar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2208438e24SVarun Wadekar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2308438e24SVarun Wadekar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2408438e24SVarun Wadekar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2508438e24SVarun Wadekar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2608438e24SVarun Wadekar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2708438e24SVarun Wadekar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2808438e24SVarun Wadekar * POSSIBILITY OF SUCH DAMAGE. 2908438e24SVarun Wadekar */ 3008438e24SVarun Wadekar 3108438e24SVarun Wadekar #include <arch_helpers.h> 3208438e24SVarun Wadekar #include <assert.h> 3308438e24SVarun Wadekar #include <bl_common.h> 3408438e24SVarun Wadekar #include <context.h> 3508438e24SVarun Wadekar #include <context_mgmt.h> 3608438e24SVarun Wadekar #include <debug.h> 3708438e24SVarun Wadekar #include <memctrl.h> 3808438e24SVarun Wadekar #include <mmio.h> 3908438e24SVarun Wadekar #include <platform.h> 4008438e24SVarun Wadekar #include <platform_def.h> 4108438e24SVarun Wadekar #include <pmc.h> 4208438e24SVarun Wadekar #include <psci.h> 4308438e24SVarun Wadekar #include <tegra_def.h> 4408438e24SVarun Wadekar #include <tegra_private.h> 4508438e24SVarun Wadekar 4608438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base; 4771cb26eaSVarun Wadekar extern uint64_t tegra_sec_entry_point; 4808438e24SVarun Wadekar 4908438e24SVarun Wadekar /* 5008438e24SVarun Wadekar * The following platform setup functions are weakly defined. They 5108438e24SVarun Wadekar * provide typical implementations that will be overridden by a SoC. 5208438e24SVarun Wadekar */ 5371cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_suspend 5471cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_on 5571cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_off 5671cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_on_finish 573b40f993SVarun Wadekar #pragma weak tegra_soc_prepare_system_reset 5808438e24SVarun Wadekar 5971cb26eaSVarun Wadekar int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 6008438e24SVarun Wadekar { 6108438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6208438e24SVarun Wadekar } 6308438e24SVarun Wadekar 6471cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on(u_register_t mpidr) 6508438e24SVarun Wadekar { 6608438e24SVarun Wadekar return PSCI_E_SUCCESS; 6708438e24SVarun Wadekar } 6808438e24SVarun Wadekar 6971cb26eaSVarun Wadekar int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 7008438e24SVarun Wadekar { 7108438e24SVarun Wadekar return PSCI_E_SUCCESS; 7208438e24SVarun Wadekar } 7308438e24SVarun Wadekar 7471cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 7508438e24SVarun Wadekar { 7608438e24SVarun Wadekar return PSCI_E_SUCCESS; 7708438e24SVarun Wadekar } 7808438e24SVarun Wadekar 793b40f993SVarun Wadekar int tegra_soc_prepare_system_reset(void) 803b40f993SVarun Wadekar { 813b40f993SVarun Wadekar return PSCI_E_SUCCESS; 823b40f993SVarun Wadekar } 833b40f993SVarun Wadekar 8408438e24SVarun Wadekar /******************************************************************************* 8571cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 8671cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 8771cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 8871cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 8908438e24SVarun Wadekar ******************************************************************************/ 9071cb26eaSVarun Wadekar void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 9108438e24SVarun Wadekar { 9271cb26eaSVarun Wadekar /* lower affinities use PLAT_MAX_OFF_STATE */ 9371cb26eaSVarun Wadekar for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 9471cb26eaSVarun Wadekar req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 9508438e24SVarun Wadekar 9671cb26eaSVarun Wadekar /* max affinity uses system suspend state id */ 9771cb26eaSVarun Wadekar req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; 9808438e24SVarun Wadekar } 9908438e24SVarun Wadekar 10008438e24SVarun Wadekar /******************************************************************************* 10108438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 10208438e24SVarun Wadekar ******************************************************************************/ 10371cb26eaSVarun Wadekar void tegra_cpu_standby(plat_local_state_t cpu_state) 10408438e24SVarun Wadekar { 10508438e24SVarun Wadekar /* 10608438e24SVarun Wadekar * Enter standby state 10708438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 10808438e24SVarun Wadekar */ 10908438e24SVarun Wadekar dsb(); 11008438e24SVarun Wadekar wfi(); 11108438e24SVarun Wadekar } 11208438e24SVarun Wadekar 11308438e24SVarun Wadekar /******************************************************************************* 11408438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 11508438e24SVarun Wadekar * level and mpidr determine the affinity instance. 11608438e24SVarun Wadekar ******************************************************************************/ 11771cb26eaSVarun Wadekar int tegra_pwr_domain_on(u_register_t mpidr) 11808438e24SVarun Wadekar { 11971cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 12008438e24SVarun Wadekar } 12108438e24SVarun Wadekar 12208438e24SVarun Wadekar /******************************************************************************* 12371cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 12471cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 12508438e24SVarun Wadekar ******************************************************************************/ 12671cb26eaSVarun Wadekar void tegra_pwr_domain_off(const psci_power_state_t *target_state) 12708438e24SVarun Wadekar { 12871cb26eaSVarun Wadekar tegra_soc_pwr_domain_off(target_state); 12908438e24SVarun Wadekar } 13008438e24SVarun Wadekar 13108438e24SVarun Wadekar /******************************************************************************* 13271cb26eaSVarun Wadekar * Handler called when called when a power domain is about to be suspended. The 13371cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 13408438e24SVarun Wadekar ******************************************************************************/ 13571cb26eaSVarun Wadekar void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 13608438e24SVarun Wadekar { 13771cb26eaSVarun Wadekar tegra_soc_pwr_domain_suspend(target_state); 13808438e24SVarun Wadekar 13908438e24SVarun Wadekar /* disable GICC */ 14008438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 14108438e24SVarun Wadekar } 14208438e24SVarun Wadekar 14308438e24SVarun Wadekar /******************************************************************************* 14471cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 14571cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 14671cb26eaSVarun Wadekar * each level has woken up from. 14708438e24SVarun Wadekar ******************************************************************************/ 14871cb26eaSVarun Wadekar void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 14908438e24SVarun Wadekar { 15008438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 15108438e24SVarun Wadekar 15208438e24SVarun Wadekar /* 15308438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 15408438e24SVarun Wadekar */ 15508438e24SVarun Wadekar tegra_gic_setup(); 15608438e24SVarun Wadekar 15708438e24SVarun Wadekar /* 15808438e24SVarun Wadekar * Check if we are exiting from deep sleep. 15908438e24SVarun Wadekar */ 16071cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 16171cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 16208438e24SVarun Wadekar 16308438e24SVarun Wadekar /* 16408438e24SVarun Wadekar * Lock scratch registers which hold the CPU vectors. 16508438e24SVarun Wadekar */ 16608438e24SVarun Wadekar tegra_pmc_lock_cpu_vectors(); 16708438e24SVarun Wadekar 16808438e24SVarun Wadekar /* 16908438e24SVarun Wadekar * SMMU configuration. 17008438e24SVarun Wadekar */ 17108438e24SVarun Wadekar tegra_memctrl_setup(); 17208438e24SVarun Wadekar 17308438e24SVarun Wadekar /* 17408438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 17508438e24SVarun Wadekar */ 17608438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 177*e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 17808438e24SVarun Wadekar plat_params->tzdram_size); 17908438e24SVarun Wadekar } 18008438e24SVarun Wadekar 18108438e24SVarun Wadekar /* 18208438e24SVarun Wadekar * Reset hardware settings. 18308438e24SVarun Wadekar */ 18471cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(target_state); 18508438e24SVarun Wadekar } 18608438e24SVarun Wadekar 18708438e24SVarun Wadekar /******************************************************************************* 18871cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 18971cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 19071cb26eaSVarun Wadekar * that each level has woken up from. 19108438e24SVarun Wadekar ******************************************************************************/ 19271cb26eaSVarun Wadekar void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 19308438e24SVarun Wadekar { 19471cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 19508438e24SVarun Wadekar } 19608438e24SVarun Wadekar 19708438e24SVarun Wadekar /******************************************************************************* 19808438e24SVarun Wadekar * Handler called when the system wants to be powered off 19908438e24SVarun Wadekar ******************************************************************************/ 20008438e24SVarun Wadekar __dead2 void tegra_system_off(void) 20108438e24SVarun Wadekar { 20208438e24SVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 20308438e24SVarun Wadekar panic(); 20408438e24SVarun Wadekar } 20508438e24SVarun Wadekar 20608438e24SVarun Wadekar /******************************************************************************* 20708438e24SVarun Wadekar * Handler called when the system wants to be restarted. 20808438e24SVarun Wadekar ******************************************************************************/ 20908438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 21008438e24SVarun Wadekar { 2113b40f993SVarun Wadekar /* per-SoC system reset handler */ 2123b40f993SVarun Wadekar tegra_soc_prepare_system_reset(); 2133b40f993SVarun Wadekar 21408438e24SVarun Wadekar /* 21508438e24SVarun Wadekar * Program the PMC in order to restart the system. 21608438e24SVarun Wadekar */ 21708438e24SVarun Wadekar tegra_pmc_system_reset(); 21808438e24SVarun Wadekar } 21908438e24SVarun Wadekar 22008438e24SVarun Wadekar /******************************************************************************* 22171cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 22271cb26eaSVarun Wadekar ******************************************************************************/ 22371cb26eaSVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state, 22471cb26eaSVarun Wadekar psci_power_state_t *req_state) 22571cb26eaSVarun Wadekar { 22671cb26eaSVarun Wadekar int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 22771cb26eaSVarun Wadekar 22871cb26eaSVarun Wadekar assert(req_state); 22971cb26eaSVarun Wadekar 23071cb26eaSVarun Wadekar if (pwr_lvl > PLAT_MAX_PWR_LVL) 23171cb26eaSVarun Wadekar return PSCI_E_INVALID_PARAMS; 23271cb26eaSVarun Wadekar 23371cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 23471cb26eaSVarun Wadekar } 23571cb26eaSVarun Wadekar 23671cb26eaSVarun Wadekar /******************************************************************************* 23771cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 23871cb26eaSVarun Wadekar ******************************************************************************/ 23971cb26eaSVarun Wadekar int tegra_validate_ns_entrypoint(uintptr_t entrypoint) 24071cb26eaSVarun Wadekar { 24171cb26eaSVarun Wadekar /* 24271cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 24371cb26eaSVarun Wadekar * secure DRAM. 24471cb26eaSVarun Wadekar */ 24571cb26eaSVarun Wadekar if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) 24671cb26eaSVarun Wadekar return PSCI_E_SUCCESS; 24771cb26eaSVarun Wadekar 24871cb26eaSVarun Wadekar return PSCI_E_INVALID_ADDRESS; 24971cb26eaSVarun Wadekar } 25071cb26eaSVarun Wadekar 25171cb26eaSVarun Wadekar /******************************************************************************* 25208438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 25308438e24SVarun Wadekar ******************************************************************************/ 25471cb26eaSVarun Wadekar static const plat_psci_ops_t tegra_plat_psci_ops = { 25571cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 25671cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 25771cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 25871cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 25971cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 26071cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 26108438e24SVarun Wadekar .system_off = tegra_system_off, 26208438e24SVarun Wadekar .system_reset = tegra_system_reset, 26394c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 26471cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 26571cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 26608438e24SVarun Wadekar }; 26708438e24SVarun Wadekar 26808438e24SVarun Wadekar /******************************************************************************* 26971cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 27008438e24SVarun Wadekar ******************************************************************************/ 27171cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 27271cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 27308438e24SVarun Wadekar { 27471cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 27571cb26eaSVarun Wadekar 27671cb26eaSVarun Wadekar /* 27771cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 27871cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 27971cb26eaSVarun Wadekar */ 28071cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 28171cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 28271cb26eaSVarun Wadekar 28308438e24SVarun Wadekar /* 28408438e24SVarun Wadekar * Reset hardware settings. 28508438e24SVarun Wadekar */ 28671cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(&target_state); 28708438e24SVarun Wadekar 28808438e24SVarun Wadekar /* 28971cb26eaSVarun Wadekar * Initialize PSCI ops struct 29008438e24SVarun Wadekar */ 29171cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 29208438e24SVarun Wadekar 29308438e24SVarun Wadekar return 0; 29408438e24SVarun Wadekar } 295