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