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 5726c0d9b2SVarun Wadekar #pragma weak tegra_soc_pwr_domain_power_down_wfi 583b40f993SVarun Wadekar #pragma weak tegra_soc_prepare_system_reset 5931a4957cSVarun Wadekar #pragma weak tegra_soc_prepare_system_off 60*a7cd0953SVarun Wadekar #pragma weak tegra_soc_get_target_pwr_state 6108438e24SVarun Wadekar 6271cb26eaSVarun Wadekar int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 6308438e24SVarun Wadekar { 6408438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6508438e24SVarun Wadekar } 6608438e24SVarun Wadekar 6771cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on(u_register_t mpidr) 6808438e24SVarun Wadekar { 6908438e24SVarun Wadekar return PSCI_E_SUCCESS; 7008438e24SVarun Wadekar } 7108438e24SVarun Wadekar 7271cb26eaSVarun Wadekar int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 7308438e24SVarun Wadekar { 7408438e24SVarun Wadekar return PSCI_E_SUCCESS; 7508438e24SVarun Wadekar } 7608438e24SVarun Wadekar 7771cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 7808438e24SVarun Wadekar { 7908438e24SVarun Wadekar return PSCI_E_SUCCESS; 8008438e24SVarun Wadekar } 8108438e24SVarun Wadekar 8226c0d9b2SVarun Wadekar int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) 8326c0d9b2SVarun Wadekar { 8426c0d9b2SVarun Wadekar return PSCI_E_SUCCESS; 8526c0d9b2SVarun Wadekar } 8626c0d9b2SVarun Wadekar 873b40f993SVarun Wadekar int tegra_soc_prepare_system_reset(void) 883b40f993SVarun Wadekar { 893b40f993SVarun Wadekar return PSCI_E_SUCCESS; 903b40f993SVarun Wadekar } 913b40f993SVarun Wadekar 9231a4957cSVarun Wadekar __dead2 void tegra_soc_prepare_system_off(void) 9331a4957cSVarun Wadekar { 9431a4957cSVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 9531a4957cSVarun Wadekar panic(); 9631a4957cSVarun Wadekar } 9731a4957cSVarun Wadekar 98*a7cd0953SVarun Wadekar plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl, 99*a7cd0953SVarun Wadekar const plat_local_state_t *states, 100*a7cd0953SVarun Wadekar unsigned int ncpu) 101*a7cd0953SVarun Wadekar { 102*a7cd0953SVarun Wadekar plat_local_state_t target = PLAT_MAX_RET_STATE, temp; 103*a7cd0953SVarun Wadekar 104*a7cd0953SVarun Wadekar assert(ncpu); 105*a7cd0953SVarun Wadekar 106*a7cd0953SVarun Wadekar do { 107*a7cd0953SVarun Wadekar temp = *states++; 108*a7cd0953SVarun Wadekar if ((temp > target) && (temp != PLAT_MAX_OFF_STATE)) 109*a7cd0953SVarun Wadekar target = temp; 110*a7cd0953SVarun Wadekar } while (--ncpu); 111*a7cd0953SVarun Wadekar 112*a7cd0953SVarun Wadekar return target; 113*a7cd0953SVarun Wadekar } 114*a7cd0953SVarun Wadekar 11508438e24SVarun Wadekar /******************************************************************************* 11671cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 11771cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 11871cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 11971cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 12008438e24SVarun Wadekar ******************************************************************************/ 12171cb26eaSVarun Wadekar void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 12208438e24SVarun Wadekar { 123*a7cd0953SVarun Wadekar /* all affinities use system suspend state id */ 124*a7cd0953SVarun Wadekar for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 125*a7cd0953SVarun Wadekar req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; 12608438e24SVarun Wadekar } 12708438e24SVarun Wadekar 12808438e24SVarun Wadekar /******************************************************************************* 12908438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 13008438e24SVarun Wadekar ******************************************************************************/ 13171cb26eaSVarun Wadekar void tegra_cpu_standby(plat_local_state_t cpu_state) 13208438e24SVarun Wadekar { 13308438e24SVarun Wadekar /* 13408438e24SVarun Wadekar * Enter standby state 13508438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 13608438e24SVarun Wadekar */ 13708438e24SVarun Wadekar dsb(); 13808438e24SVarun Wadekar wfi(); 13908438e24SVarun Wadekar } 14008438e24SVarun Wadekar 14108438e24SVarun Wadekar /******************************************************************************* 14208438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 14308438e24SVarun Wadekar * level and mpidr determine the affinity instance. 14408438e24SVarun Wadekar ******************************************************************************/ 14571cb26eaSVarun Wadekar int tegra_pwr_domain_on(u_register_t mpidr) 14608438e24SVarun Wadekar { 14771cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 14808438e24SVarun Wadekar } 14908438e24SVarun Wadekar 15008438e24SVarun Wadekar /******************************************************************************* 15171cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 15271cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 15308438e24SVarun Wadekar ******************************************************************************/ 15471cb26eaSVarun Wadekar void tegra_pwr_domain_off(const psci_power_state_t *target_state) 15508438e24SVarun Wadekar { 15671cb26eaSVarun Wadekar tegra_soc_pwr_domain_off(target_state); 15708438e24SVarun Wadekar } 15808438e24SVarun Wadekar 15908438e24SVarun Wadekar /******************************************************************************* 16026c0d9b2SVarun Wadekar * Handler called when a power domain is about to be suspended. The 16171cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 16208438e24SVarun Wadekar ******************************************************************************/ 16371cb26eaSVarun Wadekar void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 16408438e24SVarun Wadekar { 16571cb26eaSVarun Wadekar tegra_soc_pwr_domain_suspend(target_state); 16608438e24SVarun Wadekar 16708438e24SVarun Wadekar /* disable GICC */ 16808438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 16908438e24SVarun Wadekar } 17008438e24SVarun Wadekar 17108438e24SVarun Wadekar /******************************************************************************* 17226c0d9b2SVarun Wadekar * Handler called at the end of the power domain suspend sequence. The 17326c0d9b2SVarun Wadekar * target_state encodes the power state that each level should transition to. 17426c0d9b2SVarun Wadekar ******************************************************************************/ 17526c0d9b2SVarun Wadekar __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t 17626c0d9b2SVarun Wadekar *target_state) 17726c0d9b2SVarun Wadekar { 17826c0d9b2SVarun Wadekar /* call the chip's power down handler */ 17926c0d9b2SVarun Wadekar tegra_soc_pwr_domain_power_down_wfi(target_state); 18026c0d9b2SVarun Wadekar 18126c0d9b2SVarun Wadekar /* enter power down state */ 18226c0d9b2SVarun Wadekar wfi(); 18326c0d9b2SVarun Wadekar 18426c0d9b2SVarun Wadekar /* we can never reach here */ 18526c0d9b2SVarun Wadekar ERROR("%s: operation not handled.\n", __func__); 18626c0d9b2SVarun Wadekar panic(); 18726c0d9b2SVarun Wadekar } 18826c0d9b2SVarun Wadekar 18926c0d9b2SVarun Wadekar /******************************************************************************* 19071cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 19171cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 19271cb26eaSVarun Wadekar * each level has woken up from. 19308438e24SVarun Wadekar ******************************************************************************/ 19471cb26eaSVarun Wadekar void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 19508438e24SVarun Wadekar { 19608438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 19708438e24SVarun Wadekar 19808438e24SVarun Wadekar /* 19908438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 20008438e24SVarun Wadekar */ 201d3360301SVarun Wadekar plat_gic_setup(); 20208438e24SVarun Wadekar 20308438e24SVarun Wadekar /* 20408438e24SVarun Wadekar * Check if we are exiting from deep sleep. 20508438e24SVarun Wadekar */ 20671cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 20771cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 20808438e24SVarun Wadekar 20908438e24SVarun Wadekar /* 210102e4087SVarun Wadekar * Restore Memory Controller settings as it loses state 211102e4087SVarun Wadekar * during system suspend. 21208438e24SVarun Wadekar */ 213102e4087SVarun Wadekar tegra_memctrl_restore_settings(); 21408438e24SVarun Wadekar 21508438e24SVarun Wadekar /* 21608438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 21708438e24SVarun Wadekar */ 21808438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 219e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 22008438e24SVarun Wadekar plat_params->tzdram_size); 221207680c6SVarun Wadekar 222207680c6SVarun Wadekar /* 223207680c6SVarun Wadekar * Set up the TZRAM memory aperture to allow only secure world 224207680c6SVarun Wadekar * access 225207680c6SVarun Wadekar */ 226207680c6SVarun Wadekar tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); 22708438e24SVarun Wadekar } 22808438e24SVarun Wadekar 22908438e24SVarun Wadekar /* 23008438e24SVarun Wadekar * Reset hardware settings. 23108438e24SVarun Wadekar */ 23271cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(target_state); 23308438e24SVarun Wadekar } 23408438e24SVarun Wadekar 23508438e24SVarun Wadekar /******************************************************************************* 23671cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 23771cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 23871cb26eaSVarun Wadekar * that each level has woken up from. 23908438e24SVarun Wadekar ******************************************************************************/ 24071cb26eaSVarun Wadekar void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 24108438e24SVarun Wadekar { 24271cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 24308438e24SVarun Wadekar } 24408438e24SVarun Wadekar 24508438e24SVarun Wadekar /******************************************************************************* 24608438e24SVarun Wadekar * Handler called when the system wants to be powered off 24708438e24SVarun Wadekar ******************************************************************************/ 24808438e24SVarun Wadekar __dead2 void tegra_system_off(void) 24908438e24SVarun Wadekar { 25031a4957cSVarun Wadekar INFO("Powering down system...\n"); 25131a4957cSVarun Wadekar 25231a4957cSVarun Wadekar tegra_soc_prepare_system_off(); 25308438e24SVarun Wadekar } 25408438e24SVarun Wadekar 25508438e24SVarun Wadekar /******************************************************************************* 25608438e24SVarun Wadekar * Handler called when the system wants to be restarted. 25708438e24SVarun Wadekar ******************************************************************************/ 25808438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 25908438e24SVarun Wadekar { 26031a4957cSVarun Wadekar INFO("Restarting system...\n"); 26131a4957cSVarun Wadekar 2623b40f993SVarun Wadekar /* per-SoC system reset handler */ 2633b40f993SVarun Wadekar tegra_soc_prepare_system_reset(); 2643b40f993SVarun Wadekar 26508438e24SVarun Wadekar /* 26608438e24SVarun Wadekar * Program the PMC in order to restart the system. 26708438e24SVarun Wadekar */ 26808438e24SVarun Wadekar tegra_pmc_system_reset(); 26908438e24SVarun Wadekar } 27008438e24SVarun Wadekar 27108438e24SVarun Wadekar /******************************************************************************* 27271cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 27371cb26eaSVarun Wadekar ******************************************************************************/ 27471cb26eaSVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state, 27571cb26eaSVarun Wadekar psci_power_state_t *req_state) 27671cb26eaSVarun Wadekar { 27771cb26eaSVarun Wadekar assert(req_state); 27871cb26eaSVarun Wadekar 27971cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 28071cb26eaSVarun Wadekar } 28171cb26eaSVarun Wadekar 28271cb26eaSVarun Wadekar /******************************************************************************* 28371cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 28471cb26eaSVarun Wadekar ******************************************************************************/ 28571cb26eaSVarun Wadekar int tegra_validate_ns_entrypoint(uintptr_t entrypoint) 28671cb26eaSVarun Wadekar { 28771cb26eaSVarun Wadekar /* 28871cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 28971cb26eaSVarun Wadekar * secure DRAM. 29071cb26eaSVarun Wadekar */ 29171cb26eaSVarun Wadekar if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) 29271cb26eaSVarun Wadekar return PSCI_E_SUCCESS; 29371cb26eaSVarun Wadekar 29471cb26eaSVarun Wadekar return PSCI_E_INVALID_ADDRESS; 29571cb26eaSVarun Wadekar } 29671cb26eaSVarun Wadekar 29771cb26eaSVarun Wadekar /******************************************************************************* 29808438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 29908438e24SVarun Wadekar ******************************************************************************/ 30071cb26eaSVarun Wadekar static const plat_psci_ops_t tegra_plat_psci_ops = { 30171cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 30271cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 30371cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 30471cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 30571cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 30671cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 30726c0d9b2SVarun Wadekar .pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi, 30808438e24SVarun Wadekar .system_off = tegra_system_off, 30908438e24SVarun Wadekar .system_reset = tegra_system_reset, 31094c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 31171cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 31271cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 31308438e24SVarun Wadekar }; 31408438e24SVarun Wadekar 31508438e24SVarun Wadekar /******************************************************************************* 31671cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 31708438e24SVarun Wadekar ******************************************************************************/ 31871cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 31971cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 32008438e24SVarun Wadekar { 32171cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 32271cb26eaSVarun Wadekar 32371cb26eaSVarun Wadekar /* 32471cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 32571cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 32671cb26eaSVarun Wadekar */ 32771cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 32871cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 32971cb26eaSVarun Wadekar 33008438e24SVarun Wadekar /* 33108438e24SVarun Wadekar * Reset hardware settings. 33208438e24SVarun Wadekar */ 33371cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(&target_state); 33408438e24SVarun Wadekar 33508438e24SVarun Wadekar /* 33671cb26eaSVarun Wadekar * Initialize PSCI ops struct 33708438e24SVarun Wadekar */ 33871cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 33908438e24SVarun Wadekar 34008438e24SVarun Wadekar return 0; 34108438e24SVarun Wadekar } 3422693f1dbSVarun Wadekar 3432693f1dbSVarun Wadekar /******************************************************************************* 3442693f1dbSVarun Wadekar * Platform handler to calculate the proper target power level at the 3452693f1dbSVarun Wadekar * specified affinity level 3462693f1dbSVarun Wadekar ******************************************************************************/ 3472693f1dbSVarun Wadekar plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, 3482693f1dbSVarun Wadekar const plat_local_state_t *states, 3492693f1dbSVarun Wadekar unsigned int ncpu) 3502693f1dbSVarun Wadekar { 351*a7cd0953SVarun Wadekar return tegra_soc_get_target_pwr_state(lvl, states, ncpu); 3522693f1dbSVarun Wadekar } 353