1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <assert.h> 8*91f16700Schasinglulu #include <errno.h> 9*91f16700Schasinglulu 10*91f16700Schasinglulu #include <platform_def.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu #include <arch_helpers.h> 13*91f16700Schasinglulu #include <common/debug.h> 14*91f16700Schasinglulu #include <drivers/delay_timer.h> 15*91f16700Schasinglulu #include <drivers/generic_delay_timer.h> 16*91f16700Schasinglulu #include <lib/cassert.h> 17*91f16700Schasinglulu #include <lib/psci/psci.h> 18*91f16700Schasinglulu 19*91f16700Schasinglulu #include <sq_common.h> 20*91f16700Schasinglulu #include "sq_scpi.h" 21*91f16700Schasinglulu 22*91f16700Schasinglulu uintptr_t sq_sec_entrypoint; 23*91f16700Schasinglulu 24*91f16700Schasinglulu int sq_pwr_domain_on(u_register_t mpidr) 25*91f16700Schasinglulu { 26*91f16700Schasinglulu #if SQ_USE_SCMI_DRIVER 27*91f16700Schasinglulu sq_scmi_on(mpidr); 28*91f16700Schasinglulu #else 29*91f16700Schasinglulu /* 30*91f16700Schasinglulu * SCP takes care of powering up parent power domains so we 31*91f16700Schasinglulu * only need to care about level 0 32*91f16700Schasinglulu */ 33*91f16700Schasinglulu scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on, 34*91f16700Schasinglulu scpi_power_on); 35*91f16700Schasinglulu #endif 36*91f16700Schasinglulu 37*91f16700Schasinglulu return PSCI_E_SUCCESS; 38*91f16700Schasinglulu } 39*91f16700Schasinglulu 40*91f16700Schasinglulu static void sq_pwr_domain_on_finisher_common( 41*91f16700Schasinglulu const psci_power_state_t *target_state) 42*91f16700Schasinglulu { 43*91f16700Schasinglulu assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF); 44*91f16700Schasinglulu 45*91f16700Schasinglulu /* 46*91f16700Schasinglulu * Perform the common cluster specific operations i.e enable coherency 47*91f16700Schasinglulu * if this cluster was off. 48*91f16700Schasinglulu */ 49*91f16700Schasinglulu if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) 50*91f16700Schasinglulu plat_sq_interconnect_enter_coherency(); 51*91f16700Schasinglulu } 52*91f16700Schasinglulu 53*91f16700Schasinglulu void sq_pwr_domain_on_finish(const psci_power_state_t *target_state) 54*91f16700Schasinglulu { 55*91f16700Schasinglulu /* Assert that the system power domain need not be initialized */ 56*91f16700Schasinglulu assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN); 57*91f16700Schasinglulu 58*91f16700Schasinglulu sq_pwr_domain_on_finisher_common(target_state); 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* Program the gic per-cpu distributor or re-distributor interface */ 61*91f16700Schasinglulu sq_gic_pcpu_init(); 62*91f16700Schasinglulu 63*91f16700Schasinglulu /* Enable the gic cpu interface */ 64*91f16700Schasinglulu sq_gic_cpuif_enable(); 65*91f16700Schasinglulu } 66*91f16700Schasinglulu 67*91f16700Schasinglulu #if !SQ_USE_SCMI_DRIVER 68*91f16700Schasinglulu static void sq_power_down_common(const psci_power_state_t *target_state) 69*91f16700Schasinglulu { 70*91f16700Schasinglulu uint32_t cluster_state = scpi_power_on; 71*91f16700Schasinglulu uint32_t system_state = scpi_power_on; 72*91f16700Schasinglulu 73*91f16700Schasinglulu /* Prevent interrupts from spuriously waking up this cpu */ 74*91f16700Schasinglulu sq_gic_cpuif_disable(); 75*91f16700Schasinglulu 76*91f16700Schasinglulu /* Check if power down at system power domain level is requested */ 77*91f16700Schasinglulu if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) 78*91f16700Schasinglulu system_state = scpi_power_retention; 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* Cluster is to be turned off, so disable coherency */ 81*91f16700Schasinglulu if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) { 82*91f16700Schasinglulu plat_sq_interconnect_exit_coherency(); 83*91f16700Schasinglulu cluster_state = scpi_power_off; 84*91f16700Schasinglulu } 85*91f16700Schasinglulu 86*91f16700Schasinglulu /* 87*91f16700Schasinglulu * Ask the SCP to power down the appropriate components depending upon 88*91f16700Schasinglulu * their state. 89*91f16700Schasinglulu */ 90*91f16700Schasinglulu scpi_set_sq_power_state(read_mpidr_el1(), 91*91f16700Schasinglulu scpi_power_off, 92*91f16700Schasinglulu cluster_state, 93*91f16700Schasinglulu system_state); 94*91f16700Schasinglulu } 95*91f16700Schasinglulu #endif 96*91f16700Schasinglulu 97*91f16700Schasinglulu void sq_pwr_domain_off(const psci_power_state_t *target_state) 98*91f16700Schasinglulu { 99*91f16700Schasinglulu #if SQ_USE_SCMI_DRIVER 100*91f16700Schasinglulu /* Prevent interrupts from spuriously waking up this cpu */ 101*91f16700Schasinglulu sq_gic_cpuif_disable(); 102*91f16700Schasinglulu 103*91f16700Schasinglulu /* Cluster is to be turned off, so disable coherency */ 104*91f16700Schasinglulu if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) { 105*91f16700Schasinglulu plat_sq_interconnect_exit_coherency(); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu sq_scmi_off(target_state); 109*91f16700Schasinglulu #else 110*91f16700Schasinglulu sq_power_down_common(target_state); 111*91f16700Schasinglulu #endif 112*91f16700Schasinglulu } 113*91f16700Schasinglulu 114*91f16700Schasinglulu void __dead2 sq_system_off(void) 115*91f16700Schasinglulu { 116*91f16700Schasinglulu #if SQ_USE_SCMI_DRIVER 117*91f16700Schasinglulu sq_scmi_sys_shutdown(); 118*91f16700Schasinglulu #else 119*91f16700Schasinglulu volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE; 120*91f16700Schasinglulu 121*91f16700Schasinglulu /* set PD[9] high to power off the system */ 122*91f16700Schasinglulu gpio[5] |= 0x2; /* set output */ 123*91f16700Schasinglulu gpio[1] |= 0x2; /* set high */ 124*91f16700Schasinglulu dmbst(); 125*91f16700Schasinglulu 126*91f16700Schasinglulu generic_delay_timer_init(); 127*91f16700Schasinglulu 128*91f16700Schasinglulu mdelay(1); 129*91f16700Schasinglulu 130*91f16700Schasinglulu while (1) { 131*91f16700Schasinglulu gpio[1] &= ~0x2; /* set low */ 132*91f16700Schasinglulu dmbst(); 133*91f16700Schasinglulu 134*91f16700Schasinglulu mdelay(1); 135*91f16700Schasinglulu 136*91f16700Schasinglulu gpio[1] |= 0x2; /* set high */ 137*91f16700Schasinglulu dmbst(); 138*91f16700Schasinglulu 139*91f16700Schasinglulu mdelay(100); 140*91f16700Schasinglulu } 141*91f16700Schasinglulu 142*91f16700Schasinglulu wfi(); 143*91f16700Schasinglulu ERROR("SQ System Off: operation not handled.\n"); 144*91f16700Schasinglulu panic(); 145*91f16700Schasinglulu #endif 146*91f16700Schasinglulu } 147*91f16700Schasinglulu 148*91f16700Schasinglulu void __dead2 sq_system_reset(void) 149*91f16700Schasinglulu { 150*91f16700Schasinglulu #if SQ_USE_SCMI_DRIVER 151*91f16700Schasinglulu sq_scmi_sys_reboot(); 152*91f16700Schasinglulu #else 153*91f16700Schasinglulu uint32_t response; 154*91f16700Schasinglulu 155*91f16700Schasinglulu /* Send the system reset request to the SCP */ 156*91f16700Schasinglulu response = scpi_sys_power_state(scpi_system_reboot); 157*91f16700Schasinglulu 158*91f16700Schasinglulu if (response != SCP_OK) { 159*91f16700Schasinglulu ERROR("SQ System Reset: SCP error %u.\n", response); 160*91f16700Schasinglulu panic(); 161*91f16700Schasinglulu } 162*91f16700Schasinglulu wfi(); 163*91f16700Schasinglulu ERROR("SQ System Reset: operation not handled.\n"); 164*91f16700Schasinglulu panic(); 165*91f16700Schasinglulu #endif 166*91f16700Schasinglulu } 167*91f16700Schasinglulu 168*91f16700Schasinglulu void sq_cpu_standby(plat_local_state_t cpu_state) 169*91f16700Schasinglulu { 170*91f16700Schasinglulu u_register_t scr; 171*91f16700Schasinglulu 172*91f16700Schasinglulu assert(cpu_state == SQ_LOCAL_STATE_RET); 173*91f16700Schasinglulu 174*91f16700Schasinglulu scr = read_scr_el3(); 175*91f16700Schasinglulu /* Enable PhysicalIRQ bit for NS world to wake the CPU */ 176*91f16700Schasinglulu write_scr_el3(scr | SCR_IRQ_BIT); 177*91f16700Schasinglulu isb(); 178*91f16700Schasinglulu dsb(); 179*91f16700Schasinglulu wfi(); 180*91f16700Schasinglulu 181*91f16700Schasinglulu /* 182*91f16700Schasinglulu * Restore SCR to the original value, synchronisation of scr_el3 is 183*91f16700Schasinglulu * done by eret while el3_exit to save some execution cycles. 184*91f16700Schasinglulu */ 185*91f16700Schasinglulu write_scr_el3(scr); 186*91f16700Schasinglulu } 187*91f16700Schasinglulu 188*91f16700Schasinglulu const plat_psci_ops_t sq_psci_ops = { 189*91f16700Schasinglulu .pwr_domain_on = sq_pwr_domain_on, 190*91f16700Schasinglulu .pwr_domain_off = sq_pwr_domain_off, 191*91f16700Schasinglulu .pwr_domain_on_finish = sq_pwr_domain_on_finish, 192*91f16700Schasinglulu .cpu_standby = sq_cpu_standby, 193*91f16700Schasinglulu .system_off = sq_system_off, 194*91f16700Schasinglulu .system_reset = sq_system_reset, 195*91f16700Schasinglulu }; 196*91f16700Schasinglulu 197*91f16700Schasinglulu int plat_setup_psci_ops(uintptr_t sec_entrypoint, 198*91f16700Schasinglulu const struct plat_psci_ops **psci_ops) 199*91f16700Schasinglulu { 200*91f16700Schasinglulu #if !RESET_TO_BL31 201*91f16700Schasinglulu uintptr_t *sq_sec_ep = (uintptr_t *)BL2_MAILBOX_BASE; 202*91f16700Schasinglulu 203*91f16700Schasinglulu *sq_sec_ep = sec_entrypoint; 204*91f16700Schasinglulu flush_dcache_range((uint64_t)sq_sec_ep, 205*91f16700Schasinglulu sizeof(*sq_sec_ep)); 206*91f16700Schasinglulu #else 207*91f16700Schasinglulu sq_sec_entrypoint = sec_entrypoint; 208*91f16700Schasinglulu flush_dcache_range((uint64_t)&sq_sec_entrypoint, 209*91f16700Schasinglulu sizeof(sq_sec_entrypoint)); 210*91f16700Schasinglulu #endif 211*91f16700Schasinglulu 212*91f16700Schasinglulu *psci_ops = &sq_psci_ops; 213*91f16700Schasinglulu 214*91f16700Schasinglulu return 0; 215*91f16700Schasinglulu } 216