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