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 <assert.h> 8 #include <errno.h> 9 10 #include <platform_def.h> 11 12 #include <arch_helpers.h> 13 #include <common/debug.h> 14 #include <drivers/arm/gicv2.h> 15 #include <drivers/console.h> 16 #include <lib/mmio.h> 17 #include <lib/psci/psci.h> 18 #include <plat/common/platform.h> 19 20 #include "aml_private.h" 21 22 #define SCPI_POWER_ON 0 23 #define SCPI_POWER_RETENTION 1 24 #define SCPI_POWER_OFF 3 25 26 #define SCPI_SYSTEM_SHUTDOWN 0 27 #define SCPI_SYSTEM_REBOOT 1 28 29 static uintptr_t gxbb_sec_entrypoint; 30 static volatile uint32_t gxbb_cpu0_go; 31 32 static void gxbb_program_mailbox(u_register_t mpidr, uint64_t value) 33 { 34 unsigned int core = plat_gxbb_calc_core_pos(mpidr); 35 uintptr_t cpu_mailbox_addr = GXBB_PSCI_MAILBOX_BASE + (core << 4); 36 37 mmio_write_64(cpu_mailbox_addr, value); 38 flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t)); 39 } 40 41 static void __dead2 gxbb_system_reset(void) 42 { 43 INFO("BL31: PSCI_SYSTEM_RESET\n"); 44 45 uint32_t status = mmio_read_32(GXBB_AO_RTI_STATUS_REG3); 46 47 NOTICE("BL31: Reboot reason: 0x%x\n", status); 48 49 status &= 0xFFFF0FF0; 50 51 console_flush(); 52 53 mmio_write_32(GXBB_AO_RTI_STATUS_REG3, status); 54 55 int ret = scpi_sys_power_state(SCPI_SYSTEM_REBOOT); 56 57 if (ret != 0) { 58 ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret); 59 panic(); 60 } 61 62 wfi(); 63 64 ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); 65 panic(); 66 } 67 68 static void __dead2 gxbb_system_off(void) 69 { 70 INFO("BL31: PSCI_SYSTEM_OFF\n"); 71 72 unsigned int ret = scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); 73 74 if (ret != 0) { 75 ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret); 76 panic(); 77 } 78 79 gxbb_program_mailbox(read_mpidr_el1(), 0); 80 81 wfi(); 82 83 ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); 84 panic(); 85 } 86 87 static int32_t gxbb_pwr_domain_on(u_register_t mpidr) 88 { 89 unsigned int core = plat_gxbb_calc_core_pos(mpidr); 90 91 /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 92 if (core == GXBB_PRIMARY_CPU) { 93 VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); 94 95 gxbb_cpu0_go = 1; 96 flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 97 dsb(); 98 isb(); 99 100 sev(); 101 102 return PSCI_E_SUCCESS; 103 } 104 105 gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint); 106 scpi_set_css_power_state(mpidr, 107 SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); 108 dmbsy(); 109 sev(); 110 111 return PSCI_E_SUCCESS; 112 } 113 114 static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state) 115 { 116 unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1()); 117 118 assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 119 PLAT_LOCAL_STATE_OFF); 120 121 if (core == GXBB_PRIMARY_CPU) { 122 gxbb_cpu0_go = 0; 123 flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); 124 dsb(); 125 isb(); 126 } 127 128 gicv2_pcpu_distif_init(); 129 gicv2_cpuif_enable(); 130 } 131 132 static void gxbb_pwr_domain_off(const psci_power_state_t *target_state) 133 { 134 u_register_t mpidr = read_mpidr_el1(); 135 unsigned int core = plat_gxbb_calc_core_pos(mpidr); 136 uintptr_t addr = GXBB_PSCI_MAILBOX_BASE + 8 + (core << 4); 137 138 mmio_write_32(addr, 0xFFFFFFFF); 139 flush_dcache_range(addr, sizeof(uint32_t)); 140 141 gicv2_cpuif_disable(); 142 143 /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 144 if (core == GXBB_PRIMARY_CPU) 145 return; 146 147 scpi_set_css_power_state(mpidr, 148 SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); 149 } 150 151 static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t 152 *target_state) 153 { 154 unsigned int core = plat_gxbb_calc_core_pos(read_mpidr_el1()); 155 156 /* CPU0 can't be turned OFF, emulate it with a WFE loop */ 157 if (core == GXBB_PRIMARY_CPU) { 158 VERBOSE("BL31: CPU0 entering wait loop...\n"); 159 160 while (gxbb_cpu0_go == 0) 161 wfe(); 162 163 VERBOSE("BL31: CPU0 resumed.\n"); 164 165 write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); 166 } 167 168 dsbsy(); 169 170 for (;;) 171 wfi(); 172 } 173 174 /******************************************************************************* 175 * Platform handlers and setup function. 176 ******************************************************************************/ 177 static const plat_psci_ops_t gxbb_ops = { 178 .pwr_domain_on = gxbb_pwr_domain_on, 179 .pwr_domain_on_finish = gxbb_pwr_domain_on_finish, 180 .pwr_domain_off = gxbb_pwr_domain_off, 181 .pwr_domain_pwr_down_wfi = gxbb_pwr_domain_pwr_down_wfi, 182 .system_off = gxbb_system_off, 183 .system_reset = gxbb_system_reset, 184 }; 185 186 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 187 const plat_psci_ops_t **psci_ops) 188 { 189 gxbb_sec_entrypoint = sec_entrypoint; 190 *psci_ops = &gxbb_ops; 191 gxbb_cpu0_go = 0; 192 return 0; 193 } 194