108438e24SVarun Wadekar /* 2a9e0260cSVignesh Radhakrishnan * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. 308438e24SVarun Wadekar * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 508438e24SVarun Wadekar */ 608438e24SVarun Wadekar 708438e24SVarun Wadekar #include <arch_helpers.h> 808438e24SVarun Wadekar #include <assert.h> 908438e24SVarun Wadekar #include <bl_common.h> 10*ee1ebbd1SIsla Mitchell #include <console.h> 1108438e24SVarun Wadekar #include <context.h> 1208438e24SVarun Wadekar #include <context_mgmt.h> 1308438e24SVarun Wadekar #include <debug.h> 1408438e24SVarun Wadekar #include <memctrl.h> 1508438e24SVarun Wadekar #include <mmio.h> 1608438e24SVarun Wadekar #include <platform.h> 1708438e24SVarun Wadekar #include <platform_def.h> 1808438e24SVarun Wadekar #include <pmc.h> 1908438e24SVarun Wadekar #include <psci.h> 2008438e24SVarun Wadekar #include <tegra_def.h> 2108438e24SVarun Wadekar #include <tegra_private.h> 2208438e24SVarun Wadekar 2308438e24SVarun Wadekar extern uint64_t tegra_bl31_phys_base; 2471cb26eaSVarun Wadekar extern uint64_t tegra_sec_entry_point; 255b5928e8SVarun Wadekar extern uint64_t tegra_console_base; 2608438e24SVarun Wadekar 2708438e24SVarun Wadekar /* 28a9e0260cSVignesh Radhakrishnan * tegra_fake_system_suspend acts as a boolean var controlling whether 29a9e0260cSVignesh Radhakrishnan * we are going to take fake system suspend code or normal system suspend code 30a9e0260cSVignesh Radhakrishnan * path. This variable is set inside the sip call handlers,when the kernel 31a9e0260cSVignesh Radhakrishnan * requests a SIP call to set the suspend debug flags. 32a9e0260cSVignesh Radhakrishnan */ 33a9e0260cSVignesh Radhakrishnan uint8_t tegra_fake_system_suspend; 34a9e0260cSVignesh Radhakrishnan 35a9e0260cSVignesh Radhakrishnan /* 3608438e24SVarun Wadekar * The following platform setup functions are weakly defined. They 3708438e24SVarun Wadekar * provide typical implementations that will be overridden by a SoC. 3808438e24SVarun Wadekar */ 3971cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_suspend 4071cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_on 4171cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_off 4271cb26eaSVarun Wadekar #pragma weak tegra_soc_pwr_domain_on_finish 4326c0d9b2SVarun Wadekar #pragma weak tegra_soc_pwr_domain_power_down_wfi 443b40f993SVarun Wadekar #pragma weak tegra_soc_prepare_system_reset 4531a4957cSVarun Wadekar #pragma weak tegra_soc_prepare_system_off 46a7cd0953SVarun Wadekar #pragma weak tegra_soc_get_target_pwr_state 4708438e24SVarun Wadekar 4871cb26eaSVarun Wadekar int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) 4908438e24SVarun Wadekar { 5008438e24SVarun Wadekar return PSCI_E_NOT_SUPPORTED; 5108438e24SVarun Wadekar } 5208438e24SVarun Wadekar 5371cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on(u_register_t mpidr) 5408438e24SVarun Wadekar { 5508438e24SVarun Wadekar return PSCI_E_SUCCESS; 5608438e24SVarun Wadekar } 5708438e24SVarun Wadekar 5871cb26eaSVarun Wadekar int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) 5908438e24SVarun Wadekar { 6008438e24SVarun Wadekar return PSCI_E_SUCCESS; 6108438e24SVarun Wadekar } 6208438e24SVarun Wadekar 6371cb26eaSVarun Wadekar int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) 6408438e24SVarun Wadekar { 6508438e24SVarun Wadekar return PSCI_E_SUCCESS; 6608438e24SVarun Wadekar } 6708438e24SVarun Wadekar 6826c0d9b2SVarun Wadekar int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) 6926c0d9b2SVarun Wadekar { 7026c0d9b2SVarun Wadekar return PSCI_E_SUCCESS; 7126c0d9b2SVarun Wadekar } 7226c0d9b2SVarun Wadekar 733b40f993SVarun Wadekar int tegra_soc_prepare_system_reset(void) 743b40f993SVarun Wadekar { 753b40f993SVarun Wadekar return PSCI_E_SUCCESS; 763b40f993SVarun Wadekar } 773b40f993SVarun Wadekar 7831a4957cSVarun Wadekar __dead2 void tegra_soc_prepare_system_off(void) 7931a4957cSVarun Wadekar { 8031a4957cSVarun Wadekar ERROR("Tegra System Off: operation not handled.\n"); 8131a4957cSVarun Wadekar panic(); 8231a4957cSVarun Wadekar } 8331a4957cSVarun Wadekar 84a7cd0953SVarun Wadekar plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl, 85a7cd0953SVarun Wadekar const plat_local_state_t *states, 86a7cd0953SVarun Wadekar unsigned int ncpu) 87a7cd0953SVarun Wadekar { 888539f45dSVarun Wadekar plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; 89a7cd0953SVarun Wadekar 90a7cd0953SVarun Wadekar assert(ncpu); 91a7cd0953SVarun Wadekar 92a7cd0953SVarun Wadekar do { 93a7cd0953SVarun Wadekar temp = *states++; 948539f45dSVarun Wadekar if ((temp < target)) 95a7cd0953SVarun Wadekar target = temp; 96a7cd0953SVarun Wadekar } while (--ncpu); 97a7cd0953SVarun Wadekar 98a7cd0953SVarun Wadekar return target; 99a7cd0953SVarun Wadekar } 100a7cd0953SVarun Wadekar 10108438e24SVarun Wadekar /******************************************************************************* 10271cb26eaSVarun Wadekar * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` 10371cb26eaSVarun Wadekar * call to get the `power_state` parameter. This allows the platform to encode 10471cb26eaSVarun Wadekar * the appropriate State-ID field within the `power_state` parameter which can 10571cb26eaSVarun Wadekar * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. 10608438e24SVarun Wadekar ******************************************************************************/ 10771cb26eaSVarun Wadekar void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) 10808438e24SVarun Wadekar { 109a7cd0953SVarun Wadekar /* all affinities use system suspend state id */ 1106311f63dSVarun Wadekar for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 111a7cd0953SVarun Wadekar req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; 11208438e24SVarun Wadekar } 11308438e24SVarun Wadekar 11408438e24SVarun Wadekar /******************************************************************************* 11508438e24SVarun Wadekar * Handler called when an affinity instance is about to enter standby. 11608438e24SVarun Wadekar ******************************************************************************/ 11771cb26eaSVarun Wadekar void tegra_cpu_standby(plat_local_state_t cpu_state) 11808438e24SVarun Wadekar { 11908438e24SVarun Wadekar /* 12008438e24SVarun Wadekar * Enter standby state 12108438e24SVarun Wadekar * dsb is good practice before using wfi to enter low power states 12208438e24SVarun Wadekar */ 12308438e24SVarun Wadekar dsb(); 12408438e24SVarun Wadekar wfi(); 12508438e24SVarun Wadekar } 12608438e24SVarun Wadekar 12708438e24SVarun Wadekar /******************************************************************************* 12808438e24SVarun Wadekar * Handler called when an affinity instance is about to be turned on. The 12908438e24SVarun Wadekar * level and mpidr determine the affinity instance. 13008438e24SVarun Wadekar ******************************************************************************/ 13171cb26eaSVarun Wadekar int tegra_pwr_domain_on(u_register_t mpidr) 13208438e24SVarun Wadekar { 13371cb26eaSVarun Wadekar return tegra_soc_pwr_domain_on(mpidr); 13408438e24SVarun Wadekar } 13508438e24SVarun Wadekar 13608438e24SVarun Wadekar /******************************************************************************* 13771cb26eaSVarun Wadekar * Handler called when a power domain is about to be turned off. The 13871cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 13908438e24SVarun Wadekar ******************************************************************************/ 14071cb26eaSVarun Wadekar void tegra_pwr_domain_off(const psci_power_state_t *target_state) 14108438e24SVarun Wadekar { 14271cb26eaSVarun Wadekar tegra_soc_pwr_domain_off(target_state); 14308438e24SVarun Wadekar } 14408438e24SVarun Wadekar 14508438e24SVarun Wadekar /******************************************************************************* 14626c0d9b2SVarun Wadekar * Handler called when a power domain is about to be suspended. The 14771cb26eaSVarun Wadekar * target_state encodes the power state that each level should transition to. 14808438e24SVarun Wadekar ******************************************************************************/ 14971cb26eaSVarun Wadekar void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) 15008438e24SVarun Wadekar { 15171cb26eaSVarun Wadekar tegra_soc_pwr_domain_suspend(target_state); 15208438e24SVarun Wadekar 1535b5928e8SVarun Wadekar /* Disable console if we are entering deep sleep. */ 1545b5928e8SVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 1555b5928e8SVarun Wadekar PSTATE_ID_SOC_POWERDN) 1565b5928e8SVarun Wadekar console_uninit(); 1575b5928e8SVarun Wadekar 15808438e24SVarun Wadekar /* disable GICC */ 15908438e24SVarun Wadekar tegra_gic_cpuif_deactivate(); 16008438e24SVarun Wadekar } 16108438e24SVarun Wadekar 16208438e24SVarun Wadekar /******************************************************************************* 16326c0d9b2SVarun Wadekar * Handler called at the end of the power domain suspend sequence. The 16426c0d9b2SVarun Wadekar * target_state encodes the power state that each level should transition to. 16526c0d9b2SVarun Wadekar ******************************************************************************/ 16626c0d9b2SVarun Wadekar __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t 16726c0d9b2SVarun Wadekar *target_state) 16826c0d9b2SVarun Wadekar { 169a9e0260cSVignesh Radhakrishnan uint8_t pwr_state = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; 170a9e0260cSVignesh Radhakrishnan uint64_t rmr_el3 = 0; 171a9e0260cSVignesh Radhakrishnan 17226c0d9b2SVarun Wadekar /* call the chip's power down handler */ 17326c0d9b2SVarun Wadekar tegra_soc_pwr_domain_power_down_wfi(target_state); 17426c0d9b2SVarun Wadekar 175a9e0260cSVignesh Radhakrishnan /* 176a9e0260cSVignesh Radhakrishnan * If we are in fake system suspend mode, ensure we start doing 177a9e0260cSVignesh Radhakrishnan * procedures that help in looping back towards system suspend exit 178a9e0260cSVignesh Radhakrishnan * instead of calling WFI by requesting a warm reset. 179a9e0260cSVignesh Radhakrishnan * Else, just call WFI to enter low power state. 180a9e0260cSVignesh Radhakrishnan */ 181a9e0260cSVignesh Radhakrishnan if ((tegra_fake_system_suspend != 0U) && 182a9e0260cSVignesh Radhakrishnan (pwr_state == (uint8_t)PSTATE_ID_SOC_POWERDN)) { 183a9e0260cSVignesh Radhakrishnan 184a9e0260cSVignesh Radhakrishnan /* warm reboot */ 185a9e0260cSVignesh Radhakrishnan rmr_el3 = read_rmr_el3(); 186a9e0260cSVignesh Radhakrishnan write_rmr_el3(rmr_el3 | RMR_WARM_RESET_CPU); 187a9e0260cSVignesh Radhakrishnan 188a9e0260cSVignesh Radhakrishnan } else { 18926c0d9b2SVarun Wadekar /* enter power down state */ 19026c0d9b2SVarun Wadekar wfi(); 191a9e0260cSVignesh Radhakrishnan } 19226c0d9b2SVarun Wadekar 19326c0d9b2SVarun Wadekar /* we can never reach here */ 19426c0d9b2SVarun Wadekar panic(); 19526c0d9b2SVarun Wadekar } 19626c0d9b2SVarun Wadekar 19726c0d9b2SVarun Wadekar /******************************************************************************* 19871cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 19971cb26eaSVarun Wadekar * being turned off earlier. The target_state encodes the low power state that 20071cb26eaSVarun Wadekar * each level has woken up from. 20108438e24SVarun Wadekar ******************************************************************************/ 20271cb26eaSVarun Wadekar void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) 20308438e24SVarun Wadekar { 20408438e24SVarun Wadekar plat_params_from_bl2_t *plat_params; 20508438e24SVarun Wadekar 20608438e24SVarun Wadekar /* 20708438e24SVarun Wadekar * Initialize the GIC cpu and distributor interfaces 20808438e24SVarun Wadekar */ 209d3360301SVarun Wadekar plat_gic_setup(); 21008438e24SVarun Wadekar 21108438e24SVarun Wadekar /* 21208438e24SVarun Wadekar * Check if we are exiting from deep sleep. 21308438e24SVarun Wadekar */ 21471cb26eaSVarun Wadekar if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == 21571cb26eaSVarun Wadekar PSTATE_ID_SOC_POWERDN) { 21608438e24SVarun Wadekar 2175b5928e8SVarun Wadekar /* Initialize the runtime console */ 2189b514f83SDamon Duan if (tegra_console_base != (uint64_t)0) { 2195b5928e8SVarun Wadekar console_init(tegra_console_base, TEGRA_BOOT_UART_CLK_IN_HZ, 2205b5928e8SVarun Wadekar TEGRA_CONSOLE_BAUDRATE); 2219b514f83SDamon Duan } 2225b5928e8SVarun Wadekar 22308438e24SVarun Wadekar /* 224102e4087SVarun Wadekar * Restore Memory Controller settings as it loses state 225102e4087SVarun Wadekar * during system suspend. 22608438e24SVarun Wadekar */ 227102e4087SVarun Wadekar tegra_memctrl_restore_settings(); 22808438e24SVarun Wadekar 22908438e24SVarun Wadekar /* 23008438e24SVarun Wadekar * Security configuration to allow DRAM/device access. 23108438e24SVarun Wadekar */ 23208438e24SVarun Wadekar plat_params = bl31_get_plat_params(); 233e0d4158cSVarun Wadekar tegra_memctrl_tzdram_setup(plat_params->tzdram_base, 23408438e24SVarun Wadekar plat_params->tzdram_size); 235207680c6SVarun Wadekar 236207680c6SVarun Wadekar /* 237207680c6SVarun Wadekar * Set up the TZRAM memory aperture to allow only secure world 238207680c6SVarun Wadekar * access 239207680c6SVarun Wadekar */ 240207680c6SVarun Wadekar tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); 24108438e24SVarun Wadekar } 24208438e24SVarun Wadekar 24308438e24SVarun Wadekar /* 24408438e24SVarun Wadekar * Reset hardware settings. 24508438e24SVarun Wadekar */ 24671cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(target_state); 24708438e24SVarun Wadekar } 24808438e24SVarun Wadekar 24908438e24SVarun Wadekar /******************************************************************************* 25071cb26eaSVarun Wadekar * Handler called when a power domain has just been powered on after 25171cb26eaSVarun Wadekar * having been suspended earlier. The target_state encodes the low power state 25271cb26eaSVarun Wadekar * that each level has woken up from. 25308438e24SVarun Wadekar ******************************************************************************/ 25471cb26eaSVarun Wadekar void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 25508438e24SVarun Wadekar { 25671cb26eaSVarun Wadekar tegra_pwr_domain_on_finish(target_state); 25708438e24SVarun Wadekar } 25808438e24SVarun Wadekar 25908438e24SVarun Wadekar /******************************************************************************* 26008438e24SVarun Wadekar * Handler called when the system wants to be powered off 26108438e24SVarun Wadekar ******************************************************************************/ 26208438e24SVarun Wadekar __dead2 void tegra_system_off(void) 26308438e24SVarun Wadekar { 26431a4957cSVarun Wadekar INFO("Powering down system...\n"); 26531a4957cSVarun Wadekar 26631a4957cSVarun Wadekar tegra_soc_prepare_system_off(); 26708438e24SVarun Wadekar } 26808438e24SVarun Wadekar 26908438e24SVarun Wadekar /******************************************************************************* 27008438e24SVarun Wadekar * Handler called when the system wants to be restarted. 27108438e24SVarun Wadekar ******************************************************************************/ 27208438e24SVarun Wadekar __dead2 void tegra_system_reset(void) 27308438e24SVarun Wadekar { 27431a4957cSVarun Wadekar INFO("Restarting system...\n"); 27531a4957cSVarun Wadekar 2763b40f993SVarun Wadekar /* per-SoC system reset handler */ 2773b40f993SVarun Wadekar tegra_soc_prepare_system_reset(); 2783b40f993SVarun Wadekar 27908438e24SVarun Wadekar /* 28008438e24SVarun Wadekar * Program the PMC in order to restart the system. 28108438e24SVarun Wadekar */ 28208438e24SVarun Wadekar tegra_pmc_system_reset(); 28308438e24SVarun Wadekar } 28408438e24SVarun Wadekar 28508438e24SVarun Wadekar /******************************************************************************* 28671cb26eaSVarun Wadekar * Handler called to check the validity of the power state parameter. 28771cb26eaSVarun Wadekar ******************************************************************************/ 28871cb26eaSVarun Wadekar int32_t tegra_validate_power_state(unsigned int power_state, 28971cb26eaSVarun Wadekar psci_power_state_t *req_state) 29071cb26eaSVarun Wadekar { 29171cb26eaSVarun Wadekar assert(req_state); 29271cb26eaSVarun Wadekar 29371cb26eaSVarun Wadekar return tegra_soc_validate_power_state(power_state, req_state); 29471cb26eaSVarun Wadekar } 29571cb26eaSVarun Wadekar 29671cb26eaSVarun Wadekar /******************************************************************************* 29771cb26eaSVarun Wadekar * Platform handler called to check the validity of the non secure entrypoint. 29871cb26eaSVarun Wadekar ******************************************************************************/ 29971cb26eaSVarun Wadekar int tegra_validate_ns_entrypoint(uintptr_t entrypoint) 30071cb26eaSVarun Wadekar { 30171cb26eaSVarun Wadekar /* 30271cb26eaSVarun Wadekar * Check if the non secure entrypoint lies within the non 30371cb26eaSVarun Wadekar * secure DRAM. 30471cb26eaSVarun Wadekar */ 30571cb26eaSVarun Wadekar if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) 30671cb26eaSVarun Wadekar return PSCI_E_SUCCESS; 30771cb26eaSVarun Wadekar 30871cb26eaSVarun Wadekar return PSCI_E_INVALID_ADDRESS; 30971cb26eaSVarun Wadekar } 31071cb26eaSVarun Wadekar 31171cb26eaSVarun Wadekar /******************************************************************************* 31208438e24SVarun Wadekar * Export the platform handlers to enable psci to invoke them 31308438e24SVarun Wadekar ******************************************************************************/ 31471cb26eaSVarun Wadekar static const plat_psci_ops_t tegra_plat_psci_ops = { 31571cb26eaSVarun Wadekar .cpu_standby = tegra_cpu_standby, 31671cb26eaSVarun Wadekar .pwr_domain_on = tegra_pwr_domain_on, 31771cb26eaSVarun Wadekar .pwr_domain_off = tegra_pwr_domain_off, 31871cb26eaSVarun Wadekar .pwr_domain_suspend = tegra_pwr_domain_suspend, 31971cb26eaSVarun Wadekar .pwr_domain_on_finish = tegra_pwr_domain_on_finish, 32071cb26eaSVarun Wadekar .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, 32126c0d9b2SVarun Wadekar .pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi, 32208438e24SVarun Wadekar .system_off = tegra_system_off, 32308438e24SVarun Wadekar .system_reset = tegra_system_reset, 32494c672e7SVarun Wadekar .validate_power_state = tegra_validate_power_state, 32571cb26eaSVarun Wadekar .validate_ns_entrypoint = tegra_validate_ns_entrypoint, 32671cb26eaSVarun Wadekar .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, 32708438e24SVarun Wadekar }; 32808438e24SVarun Wadekar 32908438e24SVarun Wadekar /******************************************************************************* 33071cb26eaSVarun Wadekar * Export the platform specific power ops and initialize Power Controller 33108438e24SVarun Wadekar ******************************************************************************/ 33271cb26eaSVarun Wadekar int plat_setup_psci_ops(uintptr_t sec_entrypoint, 33371cb26eaSVarun Wadekar const plat_psci_ops_t **psci_ops) 33408438e24SVarun Wadekar { 33571cb26eaSVarun Wadekar psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; 33671cb26eaSVarun Wadekar 33771cb26eaSVarun Wadekar /* 33871cb26eaSVarun Wadekar * Flush entrypoint variable to PoC since it will be 33971cb26eaSVarun Wadekar * accessed after a reset with the caches turned off. 34071cb26eaSVarun Wadekar */ 34171cb26eaSVarun Wadekar tegra_sec_entry_point = sec_entrypoint; 34271cb26eaSVarun Wadekar flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); 34371cb26eaSVarun Wadekar 34408438e24SVarun Wadekar /* 34508438e24SVarun Wadekar * Reset hardware settings. 34608438e24SVarun Wadekar */ 34771cb26eaSVarun Wadekar tegra_soc_pwr_domain_on_finish(&target_state); 34808438e24SVarun Wadekar 34908438e24SVarun Wadekar /* 35071cb26eaSVarun Wadekar * Initialize PSCI ops struct 35108438e24SVarun Wadekar */ 35271cb26eaSVarun Wadekar *psci_ops = &tegra_plat_psci_ops; 35308438e24SVarun Wadekar 35408438e24SVarun Wadekar return 0; 35508438e24SVarun Wadekar } 3562693f1dbSVarun Wadekar 3572693f1dbSVarun Wadekar /******************************************************************************* 3582693f1dbSVarun Wadekar * Platform handler to calculate the proper target power level at the 3592693f1dbSVarun Wadekar * specified affinity level 3602693f1dbSVarun Wadekar ******************************************************************************/ 3612693f1dbSVarun Wadekar plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, 3622693f1dbSVarun Wadekar const plat_local_state_t *states, 3632693f1dbSVarun Wadekar unsigned int ncpu) 3642693f1dbSVarun Wadekar { 365a7cd0953SVarun Wadekar return tegra_soc_get_target_pwr_state(lvl, states, ncpu); 3662693f1dbSVarun Wadekar } 367