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 57*26c0d9b2SVarun 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 6008438e24SVarun Wadekar 6171cb26eaSVarun Wadekar int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 6208438e24SVarun Wadekar { 6308438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 6408438e24SVarun Wadekar } 6508438e24SVarun Wadekar 6671cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on(u_register_t mpidr) 6708438e24SVarun Wadekar { 6808438e24SVarun Wadekar return PSCI_E_SUCCESS; 6908438e24SVarun Wadekar } 7008438e24SVarun Wadekar 7171cb26eaSVarun Wadekar int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 7208438e24SVarun Wadekar { 7308438e24SVarun Wadekar return PSCI_E_SUCCESS; 7408438e24SVarun Wadekar } 7508438e24SVarun Wadekar 7671cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 7708438e24SVarun Wadekar { 7808438e24SVarun Wadekar return PSCI_E_SUCCESS; 7908438e24SVarun Wadekar } 8008438e24SVarun Wadekar 81*26c0d9b2SVarun Wadekar int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) 82*26c0d9b2SVarun Wadekar { 83*26c0d9b2SVarun Wadekar return PSCI_E_SUCCESS; 84*26c0d9b2SVarun Wadekar } 85*26c0d9b2SVarun Wadekar 863b40f993SVarun Wadekar int tegra_soc_prepare_system_reset(void) 873b40f993SVarun Wadekar { 883b40f993SVarun Wadekar return PSCI_E_SUCCESS; 893b40f993SVarun Wadekar } 903b40f993SVarun Wadekar 9131a4957cSVarun Wadekar __dead2 void tegra_soc_prepare_system_off(void) 9231a4957cSVarun Wadekar { 9331a4957cSVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 9431a4957cSVarun Wadekar panic(); 9531a4957cSVarun Wadekar } 9631a4957cSVarun Wadekar 9708438e24SVarun Wadekar /******************************************************************************* 9871cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 9971cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 10071cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 10171cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 10208438e24SVarun Wadekar ******************************************************************************/ 10371cb26eaSVarun Wadekar void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 10408438e24SVarun Wadekar { 10571cb26eaSVarun Wadekar /* lower affinities use PLAT_MAX_OFF_STATE */ 10671cb26eaSVarun Wadekar for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) 10771cb26eaSVarun Wadekar req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 10808438e24SVarun Wadekar 10971cb26eaSVarun Wadekar /* max affinity uses system suspend state id */ 11071cb26eaSVarun Wadekar req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; 11108438e24SVarun Wadekar } 11208438e24SVarun Wadekar 11308438e24SVarun Wadekar /******************************************************************************* 11408438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 11508438e24SVarun Wadekar ******************************************************************************/ 11671cb26eaSVarun Wadekar void tegra_cpu_standby(plat_local_state_t cpu_state) 11708438e24SVarun Wadekar { 11808438e24SVarun Wadekar /* 11908438e24SVarun Wadekar * Enter standby state 12008438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 12108438e24SVarun Wadekar */ 12208438e24SVarun Wadekar dsb(); 12308438e24SVarun Wadekar wfi(); 12408438e24SVarun Wadekar } 12508438e24SVarun Wadekar 12608438e24SVarun Wadekar /******************************************************************************* 12708438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 12808438e24SVarun Wadekar * level and mpidr determine the affinity instance. 12908438e24SVarun Wadekar ******************************************************************************/ 13071cb26eaSVarun Wadekar int tegra_pwr_domain_on(u_register_t mpidr) 13108438e24SVarun Wadekar { 13271cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 13308438e24SVarun Wadekar } 13408438e24SVarun Wadekar 13508438e24SVarun Wadekar /******************************************************************************* 13671cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 13771cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 13808438e24SVarun Wadekar ******************************************************************************/ 13971cb26eaSVarun Wadekar void tegra_pwr_domain_off(const psci_power_state_t *target_state) 14008438e24SVarun Wadekar { 14171cb26eaSVarun Wadekar tegra_soc_pwr_domain_off(target_state); 14208438e24SVarun Wadekar } 14308438e24SVarun Wadekar 14408438e24SVarun Wadekar /******************************************************************************* 145*26c0d9b2SVarun Wadekar * Handler called when a power domain is about to be suspended. The 14671cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 14708438e24SVarun Wadekar ******************************************************************************/ 14871cb26eaSVarun Wadekar void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 14908438e24SVarun Wadekar { 15071cb26eaSVarun Wadekar tegra_soc_pwr_domain_suspend(target_state); 15108438e24SVarun Wadekar 15208438e24SVarun Wadekar /* disable GICC */ 15308438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 15408438e24SVarun Wadekar } 15508438e24SVarun Wadekar 15608438e24SVarun Wadekar /******************************************************************************* 157*26c0d9b2SVarun Wadekar * Handler called at the end of the power domain suspend sequence. The 158*26c0d9b2SVarun Wadekar * target_state encodes the power state that each level should transition to. 159*26c0d9b2SVarun Wadekar ******************************************************************************/ 160*26c0d9b2SVarun Wadekar __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t 161*26c0d9b2SVarun Wadekar *target_state) 162*26c0d9b2SVarun Wadekar { 163*26c0d9b2SVarun Wadekar /* call the chip's power down handler */ 164*26c0d9b2SVarun Wadekar tegra_soc_pwr_domain_power_down_wfi(target_state); 165*26c0d9b2SVarun Wadekar 166*26c0d9b2SVarun Wadekar /* enter power down state */ 167*26c0d9b2SVarun Wadekar wfi(); 168*26c0d9b2SVarun Wadekar 169*26c0d9b2SVarun Wadekar /* we can never reach here */ 170*26c0d9b2SVarun Wadekar ERROR("%s: operation not handled.\n", __func__); 171*26c0d9b2SVarun Wadekar panic(); 172*26c0d9b2SVarun Wadekar } 173*26c0d9b2SVarun Wadekar 174*26c0d9b2SVarun Wadekar /******************************************************************************* 17571cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 17671cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 17771cb26eaSVarun Wadekar * each level has woken up from. 17808438e24SVarun Wadekar ******************************************************************************/ 17971cb26eaSVarun Wadekar void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 18008438e24SVarun Wadekar { 18108438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 18208438e24SVarun Wadekar 18308438e24SVarun Wadekar /* 18408438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 18508438e24SVarun Wadekar */ 18608438e24SVarun Wadekar tegra_gic_setup(); 18708438e24SVarun Wadekar 18808438e24SVarun Wadekar /* 18908438e24SVarun Wadekar * Check if we are exiting from deep sleep. 19008438e24SVarun Wadekar */ 19171cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 19271cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 19308438e24SVarun Wadekar 19408438e24SVarun Wadekar /* 195102e4087SVarun Wadekar * Restore Memory Controller settings as it loses state 196102e4087SVarun Wadekar * during system suspend. 19708438e24SVarun Wadekar */ 198102e4087SVarun Wadekar tegra_memctrl_restore_settings(); 19908438e24SVarun Wadekar 20008438e24SVarun Wadekar /* 20108438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 20208438e24SVarun Wadekar */ 20308438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 204e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 20508438e24SVarun Wadekar plat_params->tzdram_size); 20608438e24SVarun Wadekar } 20708438e24SVarun Wadekar 20808438e24SVarun Wadekar /* 20908438e24SVarun Wadekar * Reset hardware settings. 21008438e24SVarun Wadekar */ 21171cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(target_state); 21208438e24SVarun Wadekar } 21308438e24SVarun Wadekar 21408438e24SVarun Wadekar /******************************************************************************* 21571cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 21671cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 21771cb26eaSVarun Wadekar * that each level has woken up from. 21808438e24SVarun Wadekar ******************************************************************************/ 21971cb26eaSVarun Wadekar void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 22008438e24SVarun Wadekar { 22171cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 22208438e24SVarun Wadekar } 22308438e24SVarun Wadekar 22408438e24SVarun Wadekar /******************************************************************************* 22508438e24SVarun Wadekar * Handler called when the system wants to be powered off 22608438e24SVarun Wadekar ******************************************************************************/ 22708438e24SVarun Wadekar __dead2 void tegra_system_off(void) 22808438e24SVarun Wadekar { 22931a4957cSVarun Wadekar INFO("Powering down system...\n"); 23031a4957cSVarun Wadekar 23131a4957cSVarun Wadekar tegra_soc_prepare_system_off(); 23208438e24SVarun Wadekar } 23308438e24SVarun Wadekar 23408438e24SVarun Wadekar /******************************************************************************* 23508438e24SVarun Wadekar * Handler called when the system wants to be restarted. 23608438e24SVarun Wadekar ******************************************************************************/ 23708438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 23808438e24SVarun Wadekar { 23931a4957cSVarun Wadekar INFO("Restarting system...\n"); 24031a4957cSVarun Wadekar 2413b40f993SVarun Wadekar /* per-SoC system reset handler */ 2423b40f993SVarun Wadekar tegra_soc_prepare_system_reset(); 2433b40f993SVarun Wadekar 24408438e24SVarun Wadekar /* 24508438e24SVarun Wadekar * Program the PMC in order to restart the system. 24608438e24SVarun Wadekar */ 24708438e24SVarun Wadekar tegra_pmc_system_reset(); 24808438e24SVarun Wadekar } 24908438e24SVarun Wadekar 25008438e24SVarun Wadekar /******************************************************************************* 25171cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 25271cb26eaSVarun Wadekar ******************************************************************************/ 25371cb26eaSVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state, 25471cb26eaSVarun Wadekar psci_power_state_t *req_state) 25571cb26eaSVarun Wadekar { 25671cb26eaSVarun Wadekar assert(req_state); 25771cb26eaSVarun Wadekar 25871cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 25971cb26eaSVarun Wadekar } 26071cb26eaSVarun Wadekar 26171cb26eaSVarun Wadekar /******************************************************************************* 26271cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 26371cb26eaSVarun Wadekar ******************************************************************************/ 26471cb26eaSVarun Wadekar int tegra_validate_ns_entrypoint(uintptr_t entrypoint) 26571cb26eaSVarun Wadekar { 26671cb26eaSVarun Wadekar /* 26771cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 26871cb26eaSVarun Wadekar * secure DRAM. 26971cb26eaSVarun Wadekar */ 27071cb26eaSVarun Wadekar if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) 27171cb26eaSVarun Wadekar return PSCI_E_SUCCESS; 27271cb26eaSVarun Wadekar 27371cb26eaSVarun Wadekar return PSCI_E_INVALID_ADDRESS; 27471cb26eaSVarun Wadekar } 27571cb26eaSVarun Wadekar 27671cb26eaSVarun Wadekar /******************************************************************************* 27708438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 27808438e24SVarun Wadekar ******************************************************************************/ 27971cb26eaSVarun Wadekar static const plat_psci_ops_t tegra_plat_psci_ops = { 28071cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 28171cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 28271cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 28371cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 28471cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 28571cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 286*26c0d9b2SVarun Wadekar .pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi, 28708438e24SVarun Wadekar .system_off = tegra_system_off, 28808438e24SVarun Wadekar .system_reset = tegra_system_reset, 28994c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 29071cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 29171cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 29208438e24SVarun Wadekar }; 29308438e24SVarun Wadekar 29408438e24SVarun Wadekar /******************************************************************************* 29571cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 29608438e24SVarun Wadekar ******************************************************************************/ 29771cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 29871cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 29908438e24SVarun Wadekar { 30071cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 30171cb26eaSVarun Wadekar 30271cb26eaSVarun Wadekar /* 30371cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 30471cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 30571cb26eaSVarun Wadekar */ 30671cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 30771cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 30871cb26eaSVarun Wadekar 30908438e24SVarun Wadekar /* 31008438e24SVarun Wadekar * Reset hardware settings. 31108438e24SVarun Wadekar */ 31271cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(&target_state); 31308438e24SVarun Wadekar 31408438e24SVarun Wadekar /* 31571cb26eaSVarun Wadekar * Initialize PSCI ops struct 31608438e24SVarun Wadekar */ 31771cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 31808438e24SVarun Wadekar 31908438e24SVarun Wadekar return 0; 32008438e24SVarun Wadekar } 321