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