108438e24SVarun Wadekar /* 2990c1e01SVarun Wadekar * Copyright (c) 2015-2016, 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 5831a4957cSVarun Wadekar #pragma weak tegra_soc_prepare_system_off 5908438e24SVarun Wadekar 6071cb26eaSVarun Wadekar int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 6108438e24SVarun Wadekar { 6208438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6308438e24SVarun Wadekar } 6408438e24SVarun Wadekar 6571cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on(u_register_t mpidr) 6608438e24SVarun Wadekar { 6708438e24SVarun Wadekar return PSCI_E_SUCCESS; 6808438e24SVarun Wadekar } 6908438e24SVarun Wadekar 7071cb26eaSVarun Wadekar int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 7108438e24SVarun Wadekar { 7208438e24SVarun Wadekar return PSCI_E_SUCCESS; 7308438e24SVarun Wadekar } 7408438e24SVarun Wadekar 7571cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 7608438e24SVarun Wadekar { 7708438e24SVarun Wadekar return PSCI_E_SUCCESS; 7808438e24SVarun Wadekar } 7908438e24SVarun Wadekar 803b40f993SVarun Wadekar int tegra_soc_prepare_system_reset(void) 813b40f993SVarun Wadekar { 823b40f993SVarun Wadekar return PSCI_E_SUCCESS; 833b40f993SVarun Wadekar } 843b40f993SVarun Wadekar 8531a4957cSVarun Wadekar __dead2 void tegra_soc_prepare_system_off(void) 8631a4957cSVarun Wadekar { 8731a4957cSVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 8831a4957cSVarun Wadekar panic(); 8931a4957cSVarun Wadekar } 9031a4957cSVarun Wadekar 9108438e24SVarun Wadekar /******************************************************************************* 9271cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 9371cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 9471cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 9571cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 9608438e24SVarun Wadekar ******************************************************************************/ 9771cb26eaSVarun Wadekar void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 9808438e24SVarun Wadekar { 9971cb26eaSVarun Wadekar /* lower affinities use PLAT_MAX_OFF_STATE */ 10071cb26eaSVarun Wadekar for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 10171cb26eaSVarun Wadekar req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 10208438e24SVarun Wadekar 10371cb26eaSVarun Wadekar /* max affinity uses system suspend state id */ 10471cb26eaSVarun Wadekar req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; 10508438e24SVarun Wadekar } 10608438e24SVarun Wadekar 10708438e24SVarun Wadekar /******************************************************************************* 10808438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 10908438e24SVarun Wadekar ******************************************************************************/ 11071cb26eaSVarun Wadekar void tegra_cpu_standby(plat_local_state_t cpu_state) 11108438e24SVarun Wadekar { 11208438e24SVarun Wadekar /* 11308438e24SVarun Wadekar * Enter standby state 11408438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 11508438e24SVarun Wadekar */ 11608438e24SVarun Wadekar dsb(); 11708438e24SVarun Wadekar wfi(); 11808438e24SVarun Wadekar } 11908438e24SVarun Wadekar 12008438e24SVarun Wadekar /******************************************************************************* 12108438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 12208438e24SVarun Wadekar * level and mpidr determine the affinity instance. 12308438e24SVarun Wadekar ******************************************************************************/ 12471cb26eaSVarun Wadekar int tegra_pwr_domain_on(u_register_t mpidr) 12508438e24SVarun Wadekar { 12671cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 12708438e24SVarun Wadekar } 12808438e24SVarun Wadekar 12908438e24SVarun Wadekar /******************************************************************************* 13071cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 13171cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 13208438e24SVarun Wadekar ******************************************************************************/ 13371cb26eaSVarun Wadekar void tegra_pwr_domain_off(const psci_power_state_t *target_state) 13408438e24SVarun Wadekar { 13571cb26eaSVarun Wadekar tegra_soc_pwr_domain_off(target_state); 13608438e24SVarun Wadekar } 13708438e24SVarun Wadekar 13808438e24SVarun Wadekar /******************************************************************************* 13971cb26eaSVarun Wadekar * Handler called when called when a power domain is about to be suspended. The 14071cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 14108438e24SVarun Wadekar ******************************************************************************/ 14271cb26eaSVarun Wadekar void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 14308438e24SVarun Wadekar { 14471cb26eaSVarun Wadekar tegra_soc_pwr_domain_suspend(target_state); 14508438e24SVarun Wadekar 14608438e24SVarun Wadekar /* disable GICC */ 14708438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 14808438e24SVarun Wadekar } 14908438e24SVarun Wadekar 15008438e24SVarun Wadekar /******************************************************************************* 15171cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 15271cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 15371cb26eaSVarun Wadekar * each level has woken up from. 15408438e24SVarun Wadekar ******************************************************************************/ 15571cb26eaSVarun Wadekar void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 15608438e24SVarun Wadekar { 15708438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 15808438e24SVarun Wadekar 15908438e24SVarun Wadekar /* 16008438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 16108438e24SVarun Wadekar */ 16208438e24SVarun Wadekar tegra_gic_setup(); 16308438e24SVarun Wadekar 16408438e24SVarun Wadekar /* 16508438e24SVarun Wadekar * Check if we are exiting from deep sleep. 16608438e24SVarun Wadekar */ 16771cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 16871cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 16908438e24SVarun Wadekar 17008438e24SVarun Wadekar /* 171*102e4087SVarun Wadekar * Restore Memory Controller settings as it loses state 172*102e4087SVarun Wadekar * during system suspend. 17308438e24SVarun Wadekar */ 174*102e4087SVarun Wadekar tegra_memctrl_restore_settings(); 17508438e24SVarun Wadekar 17608438e24SVarun Wadekar /* 17708438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 17808438e24SVarun Wadekar */ 17908438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 180e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 18108438e24SVarun Wadekar plat_params->tzdram_size); 18208438e24SVarun Wadekar } 18308438e24SVarun Wadekar 18408438e24SVarun Wadekar /* 18508438e24SVarun Wadekar * Reset hardware settings. 18608438e24SVarun Wadekar */ 18771cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(target_state); 18808438e24SVarun Wadekar } 18908438e24SVarun Wadekar 19008438e24SVarun Wadekar /******************************************************************************* 19171cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 19271cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 19371cb26eaSVarun Wadekar * that each level has woken up from. 19408438e24SVarun Wadekar ******************************************************************************/ 19571cb26eaSVarun Wadekar void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 19608438e24SVarun Wadekar { 19771cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 19808438e24SVarun Wadekar } 19908438e24SVarun Wadekar 20008438e24SVarun Wadekar /******************************************************************************* 20108438e24SVarun Wadekar * Handler called when the system wants to be powered off 20208438e24SVarun Wadekar ******************************************************************************/ 20308438e24SVarun Wadekar __dead2 void tegra_system_off(void) 20408438e24SVarun Wadekar { 20531a4957cSVarun Wadekar INFO("Powering down system...\n"); 20631a4957cSVarun Wadekar 20731a4957cSVarun Wadekar tegra_soc_prepare_system_off(); 20808438e24SVarun Wadekar } 20908438e24SVarun Wadekar 21008438e24SVarun Wadekar /******************************************************************************* 21108438e24SVarun Wadekar * Handler called when the system wants to be restarted. 21208438e24SVarun Wadekar ******************************************************************************/ 21308438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 21408438e24SVarun Wadekar { 21531a4957cSVarun Wadekar INFO("Restarting system...\n"); 21631a4957cSVarun Wadekar 2173b40f993SVarun Wadekar /* per-SoC system reset handler */ 2183b40f993SVarun Wadekar tegra_soc_prepare_system_reset(); 2193b40f993SVarun Wadekar 22008438e24SVarun Wadekar /* 22108438e24SVarun Wadekar * Program the PMC in order to restart the system. 22208438e24SVarun Wadekar */ 22308438e24SVarun Wadekar tegra_pmc_system_reset(); 22408438e24SVarun Wadekar } 22508438e24SVarun Wadekar 22608438e24SVarun Wadekar /******************************************************************************* 22771cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 22871cb26eaSVarun Wadekar ******************************************************************************/ 22971cb26eaSVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state, 23071cb26eaSVarun Wadekar psci_power_state_t *req_state) 23171cb26eaSVarun Wadekar { 23271cb26eaSVarun Wadekar assert(req_state); 23371cb26eaSVarun Wadekar 23471cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 23571cb26eaSVarun Wadekar } 23671cb26eaSVarun Wadekar 23771cb26eaSVarun Wadekar /******************************************************************************* 23871cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 23971cb26eaSVarun Wadekar ******************************************************************************/ 24071cb26eaSVarun Wadekar int tegra_validate_ns_entrypoint(uintptr_t entrypoint) 24171cb26eaSVarun Wadekar { 24271cb26eaSVarun Wadekar /* 24371cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 24471cb26eaSVarun Wadekar * secure DRAM. 24571cb26eaSVarun Wadekar */ 24671cb26eaSVarun Wadekar if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) 24771cb26eaSVarun Wadekar return PSCI_E_SUCCESS; 24871cb26eaSVarun Wadekar 24971cb26eaSVarun Wadekar return PSCI_E_INVALID_ADDRESS; 25071cb26eaSVarun Wadekar } 25171cb26eaSVarun Wadekar 25271cb26eaSVarun Wadekar /******************************************************************************* 25308438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 25408438e24SVarun Wadekar ******************************************************************************/ 25571cb26eaSVarun Wadekar static const plat_psci_ops_t tegra_plat_psci_ops = { 25671cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 25771cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 25871cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 25971cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 26071cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 26171cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 26208438e24SVarun Wadekar .system_off = tegra_system_off, 26308438e24SVarun Wadekar .system_reset = tegra_system_reset, 26494c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 26571cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 26671cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 26708438e24SVarun Wadekar }; 26808438e24SVarun Wadekar 26908438e24SVarun Wadekar /******************************************************************************* 27071cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 27108438e24SVarun Wadekar ******************************************************************************/ 27271cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 27371cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 27408438e24SVarun Wadekar { 27571cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 27671cb26eaSVarun Wadekar 27771cb26eaSVarun Wadekar /* 27871cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 27971cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 28071cb26eaSVarun Wadekar */ 28171cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 28271cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 28371cb26eaSVarun Wadekar 28408438e24SVarun Wadekar /* 28508438e24SVarun Wadekar * Reset hardware settings. 28608438e24SVarun Wadekar */ 28771cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(&target_state); 28808438e24SVarun Wadekar 28908438e24SVarun Wadekar /* 29071cb26eaSVarun Wadekar * Initialize PSCI ops struct 29108438e24SVarun Wadekar */ 29271cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 29308438e24SVarun Wadekar 29408438e24SVarun Wadekar return 0; 29508438e24SVarun Wadekar } 296