1c76d4239SHadi Asyrafi /* 2c703d752SSieu Mun Tang * Copyright (c) 2019-2022, ARM Limited and Contributors. All rights reserved. 3c76d4239SHadi Asyrafi * 4c76d4239SHadi Asyrafi * SPDX-License-Identifier: BSD-3-Clause 5c76d4239SHadi Asyrafi */ 6c76d4239SHadi Asyrafi 7c76d4239SHadi Asyrafi #include <arch_helpers.h> 8c76d4239SHadi Asyrafi #include <common/debug.h> 9c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h> 10c76d4239SHadi Asyrafi #include <lib/mmio.h> 11c76d4239SHadi Asyrafi #include <lib/psci/psci.h> 12c76d4239SHadi Asyrafi #include <plat/common/platform.h> 13c76d4239SHadi Asyrafi 14c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 15c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 1632cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 17*7f7a16a6SJit Loon Lim #include "socfpga_system_manager.h" 18c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 19c76d4239SHadi Asyrafi 20c76d4239SHadi Asyrafi 21c76d4239SHadi Asyrafi /******************************************************************************* 22c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 23c76d4239SHadi Asyrafi ******************************************************************************/ 24c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 25c76d4239SHadi Asyrafi { 26c76d4239SHadi Asyrafi /* 27c76d4239SHadi Asyrafi * Enter standby state 28c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 29c76d4239SHadi Asyrafi */ 30c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 31c76d4239SHadi Asyrafi dsb(); 32c76d4239SHadi Asyrafi wfi(); 33c76d4239SHadi Asyrafi } 34c76d4239SHadi Asyrafi 35c76d4239SHadi Asyrafi /******************************************************************************* 36c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 37c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 38c76d4239SHadi Asyrafi ******************************************************************************/ 39c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 40c76d4239SHadi Asyrafi { 41c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 42*7f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 43c76d4239SHadi Asyrafi 44c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 45c76d4239SHadi Asyrafi 46c76d4239SHadi Asyrafi if (cpu_id == -1) 47c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 48c76d4239SHadi Asyrafi 49*7f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 50*7f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 51*7f7a16a6SJit Loon Lim psci_boot |= 0x20000; /* bit 17 */ 52*7f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 53*7f7a16a6SJit Loon Lim } 54*7f7a16a6SJit Loon Lim 55cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 56c76d4239SHadi Asyrafi 57c76d4239SHadi Asyrafi /* release core reset */ 58391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 59c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 60c76d4239SHadi Asyrafi } 61c76d4239SHadi Asyrafi 62c76d4239SHadi Asyrafi /******************************************************************************* 63c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 64c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 65c76d4239SHadi Asyrafi ******************************************************************************/ 66c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 67c76d4239SHadi Asyrafi { 68c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 69c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 70c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 71c76d4239SHadi Asyrafi 72c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 73c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 74c76d4239SHadi Asyrafi } 75c76d4239SHadi Asyrafi 76c76d4239SHadi Asyrafi /******************************************************************************* 77c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 78c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 79c76d4239SHadi Asyrafi ******************************************************************************/ 80c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 81c76d4239SHadi Asyrafi { 82c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 83c76d4239SHadi Asyrafi 84c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 85c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 86c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 8732cf34acSHadi Asyrafi 88c76d4239SHadi Asyrafi /* assert core reset */ 89391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 90c76d4239SHadi Asyrafi 91c76d4239SHadi Asyrafi } 92c76d4239SHadi Asyrafi 93c76d4239SHadi Asyrafi /******************************************************************************* 94c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 95c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 96c76d4239SHadi Asyrafi * each level has woken up from. 97c76d4239SHadi Asyrafi ******************************************************************************/ 98c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 99c76d4239SHadi Asyrafi { 100c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 101c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 102c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 103c76d4239SHadi Asyrafi 104c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 105c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 106c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 107c76d4239SHadi Asyrafi 108c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 109c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 110c76d4239SHadi Asyrafi } 111c76d4239SHadi Asyrafi 112c76d4239SHadi Asyrafi /******************************************************************************* 113c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 114c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 115c76d4239SHadi Asyrafi * that each level has woken up from. 116c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 117c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 118c76d4239SHadi Asyrafi ******************************************************************************/ 119c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 120c76d4239SHadi Asyrafi { 121c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 122c76d4239SHadi Asyrafi 123c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 124c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 125c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 126c76d4239SHadi Asyrafi 127c76d4239SHadi Asyrafi /* release core reset */ 128391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 129c76d4239SHadi Asyrafi } 130c76d4239SHadi Asyrafi 131c76d4239SHadi Asyrafi /******************************************************************************* 132c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 133c76d4239SHadi Asyrafi ******************************************************************************/ 134c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 135c76d4239SHadi Asyrafi { 136c76d4239SHadi Asyrafi wfi(); 137c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 138c76d4239SHadi Asyrafi panic(); 139c76d4239SHadi Asyrafi } 140c76d4239SHadi Asyrafi 141e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 142e1f97d9cSHadi Asyrafi 143c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 144c76d4239SHadi Asyrafi { 145ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 146ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 147ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi memcpy(addr_buf, &intel_rsu_update_address, 148ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi sizeof(intel_rsu_update_address)); 149ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 150e1f97d9cSHadi Asyrafi if (intel_rsu_update_address) 151ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 152e1f97d9cSHadi Asyrafi else 153c76d4239SHadi Asyrafi mailbox_reset_cold(); 154c76d4239SHadi Asyrafi 155c76d4239SHadi Asyrafi while (1) 156c76d4239SHadi Asyrafi wfi(); 157c76d4239SHadi Asyrafi } 158c76d4239SHadi Asyrafi 15932cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 16032cf34acSHadi Asyrafi u_register_t cookie) 16132cf34acSHadi Asyrafi { 162c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 163c703d752SSieu Mun Tang mailbox_reset_cold(); 164c703d752SSieu Mun Tang } 16532cf34acSHadi Asyrafi /* disable cpuif */ 16632cf34acSHadi Asyrafi gicv2_cpuif_disable(); 16732cf34acSHadi Asyrafi 16832cf34acSHadi Asyrafi /* Store magic number */ 16932cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 17032cf34acSHadi Asyrafi 17132cf34acSHadi Asyrafi /* Increase timeout */ 172391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 17332cf34acSHadi Asyrafi 17432cf34acSHadi Asyrafi /* Enable handshakes */ 175391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 17632cf34acSHadi Asyrafi 17732cf34acSHadi Asyrafi /* Reset L2 module */ 178391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 17932cf34acSHadi Asyrafi 18032cf34acSHadi Asyrafi while (1) 18132cf34acSHadi Asyrafi wfi(); 18232cf34acSHadi Asyrafi 18332cf34acSHadi Asyrafi /* Should not reach here */ 18432cf34acSHadi Asyrafi return 0; 18532cf34acSHadi Asyrafi } 18632cf34acSHadi Asyrafi 187c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 188c76d4239SHadi Asyrafi psci_power_state_t *req_state) 189c76d4239SHadi Asyrafi { 190c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 191c76d4239SHadi Asyrafi 192c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 193c76d4239SHadi Asyrafi } 194c76d4239SHadi Asyrafi 195c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 196c76d4239SHadi Asyrafi { 197c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 198c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 199c76d4239SHadi Asyrafi } 200c76d4239SHadi Asyrafi 201c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 202c76d4239SHadi Asyrafi { 203c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 204c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 205c76d4239SHadi Asyrafi } 206c76d4239SHadi Asyrafi 207c76d4239SHadi Asyrafi /******************************************************************************* 208c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 209c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 210c76d4239SHadi Asyrafi ******************************************************************************/ 211c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 212c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 213c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 214c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 215c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 216c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 217c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 218c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 219c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 22032cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 221c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 222c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 223c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 224c76d4239SHadi Asyrafi }; 225c76d4239SHadi Asyrafi 226c76d4239SHadi Asyrafi /******************************************************************************* 227c76d4239SHadi Asyrafi * Export the platform specific power ops. 228c76d4239SHadi Asyrafi ******************************************************************************/ 229c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 230c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 231c76d4239SHadi Asyrafi { 232c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 233cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 234c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 235cf82aff0SHadi Asyrafi 236c76d4239SHadi Asyrafi return 0; 237c76d4239SHadi Asyrafi } 238