1 /* 2 * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch_helpers.h> 8 #include <assert.h> 9 #include <common/debug.h> 10 #include <drivers/arm/gicv2.h> 11 #include <drivers/console.h> 12 #include <errno.h> 13 #include <lib/mmio.h> 14 #include <lib/psci/psci.h> 15 #include <plat/common/platform.h> 16 #include <platform_def.h> 17 18 #include "aml_private.h" 19 20 #define SCPI_POWER_ON 0 21 #define SCPI_POWER_RETENTION 1 22 #define SCPI_POWER_OFF 3 23 24 #define SCPI_SYSTEM_SHUTDOWN 0 25 #define SCPI_SYSTEM_REBOOT 1 26 27 static uintptr_t axg_sec_entrypoint; 28 29 static void axg_pm_set_reset_addr(u_register_t mpidr, uint64_t value) 30 { 31 unsigned int core = plat_calc_core_pos(mpidr); 32 uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); 33 34 mmio_write_64(cpu_mailbox_addr, value); 35 } 36 37 static void axg_pm_reset(u_register_t mpidr, uint32_t value) 38 { 39 unsigned int core = plat_calc_core_pos(mpidr); 40 uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8; 41 42 mmio_write_32(cpu_mailbox_addr, value); 43 } 44 45 static void __dead2 axg_system_reset(void) 46 { 47 u_register_t mpidr = read_mpidr_el1(); 48 int ret; 49 50 INFO("BL31: PSCI_SYSTEM_RESET\n"); 51 52 ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 53 if (ret != 0) { 54 ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret); 55 panic(); 56 } 57 58 axg_pm_reset(mpidr, 0); 59 60 wfi(); 61 62 ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 63 panic(); 64 } 65 66 static void __dead2 axg_system_off(void) 67 { 68 u_register_t mpidr = read_mpidr_el1(); 69 int ret; 70 71 INFO("BL31: PSCI_SYSTEM_OFF\n"); 72 73 ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 74 if (ret != 0) { 75 ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret); 76 panic(); 77 } 78 79 axg_pm_set_reset_addr(mpidr, 0); 80 axg_pm_reset(mpidr, 0); 81 82 dmbsy(); 83 wfi(); 84 85 ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 86 panic(); 87 } 88 89 static int32_t axg_pwr_domain_on(u_register_t mpidr) 90 { 91 axg_pm_set_reset_addr(mpidr, axg_sec_entrypoint); 92 aml_scpi_set_css_power_state(mpidr, 93 SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 94 dmbsy(); 95 sev(); 96 97 return PSCI_E_SUCCESS; 98 } 99 100 static void axg_pwr_domain_on_finish(const psci_power_state_t *target_state) 101 { 102 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 103 PLAT_LOCAL_STATE_OFF); 104 105 gicv2_pcpu_distif_init(); 106 gicv2_cpuif_enable(); 107 108 axg_pm_set_reset_addr(read_mpidr_el1(), 0); 109 } 110 111 static void axg_pwr_domain_off(const psci_power_state_t *target_state) 112 { 113 u_register_t mpidr = read_mpidr_el1(); 114 uint32_t system_state = SCPI_POWER_ON; 115 uint32_t cluster_state = SCPI_POWER_ON; 116 117 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 118 PLAT_LOCAL_STATE_OFF); 119 120 axg_pm_reset(mpidr, -1); 121 122 gicv2_cpuif_disable(); 123 124 if (target_state->pwr_domain_state[MPIDR_AFFLVL2] == 125 PLAT_LOCAL_STATE_OFF) 126 system_state = SCPI_POWER_OFF; 127 128 if (target_state->pwr_domain_state[MPIDR_AFFLVL1] == 129 PLAT_LOCAL_STATE_OFF) 130 cluster_state = SCPI_POWER_OFF; 131 132 133 aml_scpi_set_css_power_state(mpidr, 134 SCPI_POWER_OFF, cluster_state, 135 system_state); 136 } 137 138 static void __dead2 axg_pwr_domain_pwr_down_wfi(const psci_power_state_t 139 *target_state) 140 { 141 dsbsy(); 142 axg_pm_reset(read_mpidr_el1(), 0); 143 144 for (;;) 145 wfi(); 146 } 147 148 /******************************************************************************* 149 * Platform handlers and setup function. 150 ******************************************************************************/ 151 static const plat_psci_ops_t axg_ops = { 152 .pwr_domain_on = axg_pwr_domain_on, 153 .pwr_domain_on_finish = axg_pwr_domain_on_finish, 154 .pwr_domain_off = axg_pwr_domain_off, 155 .pwr_domain_pwr_down = axg_pwr_domain_pwr_down_wfi, 156 .system_off = axg_system_off, 157 .system_reset = axg_system_reset 158 }; 159 160 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 161 const plat_psci_ops_t **psci_ops) 162 { 163 axg_sec_entrypoint = sec_entrypoint; 164 *psci_ops = &axg_ops; 165 return 0; 166 } 167