1 /* 2 * Copyright (c) 2019, 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 g12a_sec_entrypoint; 28 static volatile uint32_t g12a_cpu0_go; 29 30 static void g12a_pm_set_reset_addr(u_register_t mpidr, uint64_t value) 31 { 32 unsigned int core = plat_calc_core_pos(mpidr); 33 uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); 34 35 mmio_write_64(cpu_mailbox_addr, value); 36 } 37 38 static void g12a_pm_reset(u_register_t mpidr) 39 { 40 unsigned int core = plat_calc_core_pos(mpidr); 41 uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8; 42 43 mmio_write_32(cpu_mailbox_addr, 0); 44 } 45 46 static void __dead2 g12a_system_reset(void) 47 { 48 INFO("BL31: PSCI_SYSTEM_RESET\n"); 49 50 u_register_t mpidr = read_mpidr_el1(); 51 uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); 52 int ret; 53 54 NOTICE("BL31: Reboot reason: 0x%x\n", status); 55 56 status &= 0xFFFF0FF0; 57 58 console_flush(); 59 60 mmio_write_32(AML_AO_RTI_STATUS_REG3, status); 61 62 ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 63 64 if (ret != 0) { 65 ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret); 66 panic(); 67 } 68 69 g12a_pm_reset(mpidr); 70 71 wfi(); 72 73 ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 74 panic(); 75 } 76 77 static void __dead2 g12a_system_off(void) 78 { 79 INFO("BL31: PSCI_SYSTEM_OFF\n"); 80 81 u_register_t mpidr = read_mpidr_el1(); 82 int ret; 83 84 ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 85 86 if (ret != 0) { 87 ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret); 88 panic(); 89 } 90 91 g12a_pm_set_reset_addr(mpidr, 0); 92 g12a_pm_reset(mpidr); 93 94 wfi(); 95 96 ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 97 panic(); 98 } 99 100 static int32_t g12a_pwr_domain_on(u_register_t mpidr) 101 { 102 unsigned int core = plat_calc_core_pos(mpidr); 103 104 /* CPU0 can't be turned OFF */ 105 if (core == AML_PRIMARY_CPU) { 106 VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 107 108 g12a_cpu0_go = 1; 109 flush_dcache_range((uintptr_t)&g12a_cpu0_go, 110 sizeof(g12a_cpu0_go)); 111 dsb(); 112 isb(); 113 114 sev(); 115 116 return PSCI_E_SUCCESS; 117 } 118 119 g12a_pm_set_reset_addr(mpidr, g12a_sec_entrypoint); 120 aml_scpi_set_css_power_state(mpidr, 121 SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 122 dmbsy(); 123 sev(); 124 125 return PSCI_E_SUCCESS; 126 } 127 128 static void g12a_pwr_domain_on_finish(const psci_power_state_t *target_state) 129 { 130 unsigned int core = plat_calc_core_pos(read_mpidr_el1()); 131 132 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 133 PLAT_LOCAL_STATE_OFF); 134 135 if (core == AML_PRIMARY_CPU) { 136 g12a_cpu0_go = 0; 137 flush_dcache_range((uintptr_t)&g12a_cpu0_go, 138 sizeof(g12a_cpu0_go)); 139 dsb(); 140 isb(); 141 } 142 143 gicv2_pcpu_distif_init(); 144 gicv2_cpuif_enable(); 145 } 146 147 static void g12a_pwr_domain_off(const psci_power_state_t *target_state) 148 { 149 u_register_t mpidr = read_mpidr_el1(); 150 unsigned int core = plat_calc_core_pos(mpidr); 151 152 gicv2_cpuif_disable(); 153 154 /* CPU0 can't be turned OFF */ 155 if (core == AML_PRIMARY_CPU) 156 return; 157 158 aml_scpi_set_css_power_state(mpidr, 159 SCPI_POWER_OFF, SCPI_POWER_ON, 160 SCPI_POWER_ON); 161 } 162 163 static void __dead2 g12a_pwr_domain_pwr_down_wfi(const psci_power_state_t 164 *target_state) 165 { 166 u_register_t mpidr = read_mpidr_el1(); 167 unsigned int core = plat_calc_core_pos(mpidr); 168 169 /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 170 if (core == AML_PRIMARY_CPU) { 171 VERBOSE("BL31: CPU0 entering wait loop...\n"); 172 173 while (g12a_cpu0_go == 0) 174 wfe(); 175 176 VERBOSE("BL31: CPU0 resumed.\n"); 177 178 /* 179 * Because setting CPU0's warm reset entrypoint through PSCI 180 * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem 181 * to work, jump to it manually. 182 * In order to avoid an assert, MMU has to be disabled. 183 */ 184 disable_mmu_el3(); 185 ((void(*)(void))g12a_sec_entrypoint)(); 186 } 187 188 dsbsy(); 189 g12a_pm_set_reset_addr(mpidr, 0); 190 g12a_pm_reset(mpidr); 191 192 for (;;) 193 wfi(); 194 } 195 196 /******************************************************************************* 197 * Platform handlers and setup function. 198 ******************************************************************************/ 199 static const plat_psci_ops_t g12a_ops = { 200 .pwr_domain_on = g12a_pwr_domain_on, 201 .pwr_domain_on_finish = g12a_pwr_domain_on_finish, 202 .pwr_domain_off = g12a_pwr_domain_off, 203 .pwr_domain_pwr_down_wfi = g12a_pwr_domain_pwr_down_wfi, 204 .system_off = g12a_system_off, 205 .system_reset = g12a_system_reset 206 }; 207 208 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 209 const plat_psci_ops_t **psci_ops) 210 { 211 g12a_sec_entrypoint = sec_entrypoint; 212 *psci_ops = &g12a_ops; 213 g12a_cpu0_go = 0; 214 return 0; 215 } 216