1 /* 2 * Copyright (c) 2018-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 gxl_sec_entrypoint; 28 static volatile uint32_t gxl_cpu0_go; 29 30 static void gxl_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 gxl_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 gxl_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 gxl_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 gxl_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 gxl_pm_set_reset_addr(mpidr, 0); 92 gxl_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 gxl_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, emulate it with a WFE loop */ 105 if (core == AML_PRIMARY_CPU) { 106 VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 107 108 gxl_cpu0_go = 1; 109 flush_dcache_range((uintptr_t)&gxl_cpu0_go, 110 sizeof(gxl_cpu0_go)); 111 dsb(); 112 isb(); 113 114 sev(); 115 116 return PSCI_E_SUCCESS; 117 } 118 119 gxl_pm_set_reset_addr(mpidr, gxl_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 gxl_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 gxl_cpu0_go = 0; 137 flush_dcache_range((uintptr_t)&gxl_cpu0_go, 138 sizeof(gxl_cpu0_go)); 139 dsb(); 140 isb(); 141 } 142 143 gicv2_pcpu_distif_init(); 144 gicv2_cpuif_enable(); 145 } 146 147 static void gxl_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, emulate it with a WFE loop */ 155 if (core == AML_PRIMARY_CPU) 156 return; 157 158 aml_scpi_set_css_power_state(mpidr, 159 SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); 160 } 161 162 static void __dead2 gxl_pwr_domain_pwr_down_wfi(const psci_power_state_t 163 *target_state) 164 { 165 u_register_t mpidr = read_mpidr_el1(); 166 unsigned int core = plat_calc_core_pos(mpidr); 167 168 /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 169 if (core == AML_PRIMARY_CPU) { 170 VERBOSE("BL31: CPU0 entering wait loop...\n"); 171 172 while (gxl_cpu0_go == 0) 173 wfe(); 174 175 VERBOSE("BL31: CPU0 resumed.\n"); 176 177 /* 178 * Because setting CPU0's warm reset entrypoint through PSCI 179 * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem 180 * to work, jump to it manually. 181 * In order to avoid an assert, mmu has to be disabled. 182 */ 183 disable_mmu_el3(); 184 ((void(*)(void))gxl_sec_entrypoint)(); 185 } 186 187 dsbsy(); 188 gxl_pm_set_reset_addr(mpidr, 0); 189 gxl_pm_reset(mpidr); 190 191 for (;;) 192 wfi(); 193 } 194 195 /******************************************************************************* 196 * Platform handlers and setup function. 197 ******************************************************************************/ 198 static const plat_psci_ops_t gxl_ops = { 199 .pwr_domain_on = gxl_pwr_domain_on, 200 .pwr_domain_on_finish = gxl_pwr_domain_on_finish, 201 .pwr_domain_off = gxl_pwr_domain_off, 202 .pwr_domain_pwr_down = gxl_pwr_domain_pwr_down_wfi, 203 .system_off = gxl_system_off, 204 .system_reset = gxl_system_reset, 205 }; 206 207 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 208 const plat_psci_ops_t **psci_ops) 209 { 210 gxl_sec_entrypoint = sec_entrypoint; 211 *psci_ops = &gxl_ops; 212 gxl_cpu0_go = 0; 213 return 0; 214 } 215