1*28b02e23SHaojian Zhuang /* 2*28b02e23SHaojian Zhuang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3*28b02e23SHaojian Zhuang * 4*28b02e23SHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 5*28b02e23SHaojian Zhuang */ 6*28b02e23SHaojian Zhuang 7*28b02e23SHaojian Zhuang #include <arch_helpers.h> 8*28b02e23SHaojian Zhuang #include <assert.h> 9*28b02e23SHaojian Zhuang #include <cci.h> 10*28b02e23SHaojian Zhuang #include <console.h> 11*28b02e23SHaojian Zhuang #include <debug.h> 12*28b02e23SHaojian Zhuang #include <gicv2.h> 13*28b02e23SHaojian Zhuang #include <hi3660.h> 14*28b02e23SHaojian Zhuang #include <hi3660_crg.h> 15*28b02e23SHaojian Zhuang #include <mmio.h> 16*28b02e23SHaojian Zhuang #include <psci.h> 17*28b02e23SHaojian Zhuang #include "drivers/pwrc/hisi_pwrc.h" 18*28b02e23SHaojian Zhuang 19*28b02e23SHaojian Zhuang #include "hikey960_def.h" 20*28b02e23SHaojian Zhuang #include "hikey960_private.h" 21*28b02e23SHaojian Zhuang 22*28b02e23SHaojian Zhuang #define CORE_PWR_STATE(state) \ 23*28b02e23SHaojian Zhuang ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 24*28b02e23SHaojian Zhuang #define CLUSTER_PWR_STATE(state) \ 25*28b02e23SHaojian Zhuang ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 26*28b02e23SHaojian Zhuang #define SYSTEM_PWR_STATE(state) \ 27*28b02e23SHaojian Zhuang ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 28*28b02e23SHaojian Zhuang 29*28b02e23SHaojian Zhuang #define DMAC_GLB_REG_SEC 0x694 30*28b02e23SHaojian Zhuang #define AXI_CONF_BASE 0x820 31*28b02e23SHaojian Zhuang 32*28b02e23SHaojian Zhuang static uintptr_t hikey960_sec_entrypoint; 33*28b02e23SHaojian Zhuang 34*28b02e23SHaojian Zhuang static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state) 35*28b02e23SHaojian Zhuang { 36*28b02e23SHaojian Zhuang unsigned long scr; 37*28b02e23SHaojian Zhuang unsigned int val = 0; 38*28b02e23SHaojian Zhuang 39*28b02e23SHaojian Zhuang assert(cpu_state == PLAT_MAX_RET_STATE); 40*28b02e23SHaojian Zhuang 41*28b02e23SHaojian Zhuang scr = read_scr_el3(); 42*28b02e23SHaojian Zhuang 43*28b02e23SHaojian Zhuang /* Enable Physical IRQ and FIQ to wake the CPU*/ 44*28b02e23SHaojian Zhuang write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 45*28b02e23SHaojian Zhuang 46*28b02e23SHaojian Zhuang set_retention_ticks(val); 47*28b02e23SHaojian Zhuang wfi(); 48*28b02e23SHaojian Zhuang clr_retention_ticks(val); 49*28b02e23SHaojian Zhuang 50*28b02e23SHaojian Zhuang /* 51*28b02e23SHaojian Zhuang * Restore SCR to the original value, synchronisazion of 52*28b02e23SHaojian Zhuang * scr_el3 is done by eret while el3_exit to save some 53*28b02e23SHaojian Zhuang * execution cycles. 54*28b02e23SHaojian Zhuang */ 55*28b02e23SHaojian Zhuang write_scr_el3(scr); 56*28b02e23SHaojian Zhuang } 57*28b02e23SHaojian Zhuang 58*28b02e23SHaojian Zhuang static int hikey960_pwr_domain_on(u_register_t mpidr) 59*28b02e23SHaojian Zhuang { 60*28b02e23SHaojian Zhuang unsigned int core = mpidr & MPIDR_CPU_MASK; 61*28b02e23SHaojian Zhuang unsigned int cluster = 62*28b02e23SHaojian Zhuang (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; 63*28b02e23SHaojian Zhuang int cluster_stat = cluster_is_powered_on(cluster); 64*28b02e23SHaojian Zhuang 65*28b02e23SHaojian Zhuang hisi_set_cpu_boot_flag(cluster, core); 66*28b02e23SHaojian Zhuang 67*28b02e23SHaojian Zhuang mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core), 68*28b02e23SHaojian Zhuang hikey960_sec_entrypoint >> 2); 69*28b02e23SHaojian Zhuang 70*28b02e23SHaojian Zhuang if (cluster_stat) 71*28b02e23SHaojian Zhuang hisi_powerup_core(cluster, core); 72*28b02e23SHaojian Zhuang else 73*28b02e23SHaojian Zhuang hisi_powerup_cluster(cluster, core); 74*28b02e23SHaojian Zhuang 75*28b02e23SHaojian Zhuang return PSCI_E_SUCCESS; 76*28b02e23SHaojian Zhuang } 77*28b02e23SHaojian Zhuang 78*28b02e23SHaojian Zhuang static void 79*28b02e23SHaojian Zhuang hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state) 80*28b02e23SHaojian Zhuang { 81*28b02e23SHaojian Zhuang if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 82*28b02e23SHaojian Zhuang cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); 83*28b02e23SHaojian Zhuang 84*28b02e23SHaojian Zhuang gicv2_pcpu_distif_init(); 85*28b02e23SHaojian Zhuang gicv2_cpuif_enable(); 86*28b02e23SHaojian Zhuang } 87*28b02e23SHaojian Zhuang 88*28b02e23SHaojian Zhuang void hikey960_pwr_domain_off(const psci_power_state_t *target_state) 89*28b02e23SHaojian Zhuang { 90*28b02e23SHaojian Zhuang unsigned long mpidr = read_mpidr_el1(); 91*28b02e23SHaojian Zhuang unsigned int core = mpidr & MPIDR_CPU_MASK; 92*28b02e23SHaojian Zhuang unsigned int cluster = 93*28b02e23SHaojian Zhuang (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; 94*28b02e23SHaojian Zhuang 95*28b02e23SHaojian Zhuang clr_ex(); 96*28b02e23SHaojian Zhuang isb(); 97*28b02e23SHaojian Zhuang dsbsy(); 98*28b02e23SHaojian Zhuang 99*28b02e23SHaojian Zhuang gicv2_cpuif_disable(); 100*28b02e23SHaojian Zhuang 101*28b02e23SHaojian Zhuang hisi_clear_cpu_boot_flag(cluster, core); 102*28b02e23SHaojian Zhuang hisi_powerdn_core(cluster, core); 103*28b02e23SHaojian Zhuang 104*28b02e23SHaojian Zhuang /* check if any core is powered up */ 105*28b02e23SHaojian Zhuang if (hisi_test_pwrdn_allcores(cluster, core)) { 106*28b02e23SHaojian Zhuang 107*28b02e23SHaojian Zhuang cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); 108*28b02e23SHaojian Zhuang 109*28b02e23SHaojian Zhuang isb(); 110*28b02e23SHaojian Zhuang dsbsy(); 111*28b02e23SHaojian Zhuang 112*28b02e23SHaojian Zhuang hisi_powerdn_cluster(cluster, core); 113*28b02e23SHaojian Zhuang } 114*28b02e23SHaojian Zhuang } 115*28b02e23SHaojian Zhuang 116*28b02e23SHaojian Zhuang static void __dead2 hikey960_system_reset(void) 117*28b02e23SHaojian Zhuang { 118*28b02e23SHaojian Zhuang mmio_write_32(SCTRL_SCPEREN1_REG, 119*28b02e23SHaojian Zhuang SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS); 120*28b02e23SHaojian Zhuang mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef); 121*28b02e23SHaojian Zhuang panic(); 122*28b02e23SHaojian Zhuang } 123*28b02e23SHaojian Zhuang 124*28b02e23SHaojian Zhuang int hikey960_validate_power_state(unsigned int power_state, 125*28b02e23SHaojian Zhuang psci_power_state_t *req_state) 126*28b02e23SHaojian Zhuang { 127*28b02e23SHaojian Zhuang int pstate = psci_get_pstate_type(power_state); 128*28b02e23SHaojian Zhuang int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 129*28b02e23SHaojian Zhuang int i; 130*28b02e23SHaojian Zhuang 131*28b02e23SHaojian Zhuang assert(req_state); 132*28b02e23SHaojian Zhuang 133*28b02e23SHaojian Zhuang if (pwr_lvl > PLAT_MAX_PWR_LVL) 134*28b02e23SHaojian Zhuang return PSCI_E_INVALID_PARAMS; 135*28b02e23SHaojian Zhuang 136*28b02e23SHaojian Zhuang /* Sanity check the requested state */ 137*28b02e23SHaojian Zhuang if (pstate == PSTATE_TYPE_STANDBY) { 138*28b02e23SHaojian Zhuang /* 139*28b02e23SHaojian Zhuang * It's possible to enter standby only on power level 0 140*28b02e23SHaojian Zhuang * Ignore any other power level. 141*28b02e23SHaojian Zhuang */ 142*28b02e23SHaojian Zhuang if (pwr_lvl != MPIDR_AFFLVL0) 143*28b02e23SHaojian Zhuang return PSCI_E_INVALID_PARAMS; 144*28b02e23SHaojian Zhuang 145*28b02e23SHaojian Zhuang req_state->pwr_domain_state[MPIDR_AFFLVL0] = 146*28b02e23SHaojian Zhuang PLAT_MAX_RET_STATE; 147*28b02e23SHaojian Zhuang } else { 148*28b02e23SHaojian Zhuang for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 149*28b02e23SHaojian Zhuang req_state->pwr_domain_state[i] = 150*28b02e23SHaojian Zhuang PLAT_MAX_OFF_STATE; 151*28b02e23SHaojian Zhuang } 152*28b02e23SHaojian Zhuang 153*28b02e23SHaojian Zhuang /* 154*28b02e23SHaojian Zhuang * We expect the 'state id' to be zero. 155*28b02e23SHaojian Zhuang */ 156*28b02e23SHaojian Zhuang if (psci_get_pstate_id(power_state)) 157*28b02e23SHaojian Zhuang return PSCI_E_INVALID_PARAMS; 158*28b02e23SHaojian Zhuang 159*28b02e23SHaojian Zhuang return PSCI_E_SUCCESS; 160*28b02e23SHaojian Zhuang } 161*28b02e23SHaojian Zhuang 162*28b02e23SHaojian Zhuang static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint) 163*28b02e23SHaojian Zhuang { 164*28b02e23SHaojian Zhuang /* 165*28b02e23SHaojian Zhuang * Check if the non secure entrypoint lies within the non 166*28b02e23SHaojian Zhuang * secure DRAM. 167*28b02e23SHaojian Zhuang */ 168*28b02e23SHaojian Zhuang if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE))) 169*28b02e23SHaojian Zhuang return PSCI_E_SUCCESS; 170*28b02e23SHaojian Zhuang 171*28b02e23SHaojian Zhuang return PSCI_E_INVALID_ADDRESS; 172*28b02e23SHaojian Zhuang } 173*28b02e23SHaojian Zhuang 174*28b02e23SHaojian Zhuang static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state) 175*28b02e23SHaojian Zhuang { 176*28b02e23SHaojian Zhuang u_register_t mpidr = read_mpidr_el1(); 177*28b02e23SHaojian Zhuang unsigned int core = mpidr & MPIDR_CPU_MASK; 178*28b02e23SHaojian Zhuang unsigned int cluster = 179*28b02e23SHaojian Zhuang (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; 180*28b02e23SHaojian Zhuang 181*28b02e23SHaojian Zhuang if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 182*28b02e23SHaojian Zhuang return; 183*28b02e23SHaojian Zhuang 184*28b02e23SHaojian Zhuang if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 185*28b02e23SHaojian Zhuang clr_ex(); 186*28b02e23SHaojian Zhuang isb(); 187*28b02e23SHaojian Zhuang dsbsy(); 188*28b02e23SHaojian Zhuang 189*28b02e23SHaojian Zhuang gicv2_cpuif_disable(); 190*28b02e23SHaojian Zhuang 191*28b02e23SHaojian Zhuang hisi_cpuidle_lock(cluster, core); 192*28b02e23SHaojian Zhuang hisi_set_cpuidle_flag(cluster, core); 193*28b02e23SHaojian Zhuang hisi_cpuidle_unlock(cluster, core); 194*28b02e23SHaojian Zhuang 195*28b02e23SHaojian Zhuang mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core), 196*28b02e23SHaojian Zhuang hikey960_sec_entrypoint >> 2); 197*28b02e23SHaojian Zhuang 198*28b02e23SHaojian Zhuang hisi_enter_core_idle(cluster, core); 199*28b02e23SHaojian Zhuang } 200*28b02e23SHaojian Zhuang 201*28b02e23SHaojian Zhuang /* Perform the common cluster specific operations */ 202*28b02e23SHaojian Zhuang if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 203*28b02e23SHaojian Zhuang hisi_cpuidle_lock(cluster, core); 204*28b02e23SHaojian Zhuang hisi_disable_pdc(cluster); 205*28b02e23SHaojian Zhuang 206*28b02e23SHaojian Zhuang /* check if any core is powered up */ 207*28b02e23SHaojian Zhuang if (hisi_test_pwrdn_allcores(cluster, core)) { 208*28b02e23SHaojian Zhuang 209*28b02e23SHaojian Zhuang cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 210*28b02e23SHaojian Zhuang 211*28b02e23SHaojian Zhuang isb(); 212*28b02e23SHaojian Zhuang dsbsy(); 213*28b02e23SHaojian Zhuang 214*28b02e23SHaojian Zhuang /* mask the pdc wakeup irq, then 215*28b02e23SHaojian Zhuang * enable pdc to power down the core 216*28b02e23SHaojian Zhuang */ 217*28b02e23SHaojian Zhuang hisi_pdc_mask_cluster_wakeirq(cluster); 218*28b02e23SHaojian Zhuang hisi_enable_pdc(cluster); 219*28b02e23SHaojian Zhuang 220*28b02e23SHaojian Zhuang hisi_cpuidle_unlock(cluster, core); 221*28b02e23SHaojian Zhuang 222*28b02e23SHaojian Zhuang /* check the SR flag bit to determine 223*28b02e23SHaojian Zhuang * CLUSTER_IDLE_IPC or AP_SR_IPC to send 224*28b02e23SHaojian Zhuang */ 225*28b02e23SHaojian Zhuang if (hisi_test_ap_suspend_flag(cluster)) 226*28b02e23SHaojian Zhuang hisi_enter_ap_suspend(cluster, core); 227*28b02e23SHaojian Zhuang else 228*28b02e23SHaojian Zhuang hisi_enter_cluster_idle(cluster, core); 229*28b02e23SHaojian Zhuang } else { 230*28b02e23SHaojian Zhuang /* enable pdc */ 231*28b02e23SHaojian Zhuang hisi_enable_pdc(cluster); 232*28b02e23SHaojian Zhuang hisi_cpuidle_unlock(cluster, core); 233*28b02e23SHaojian Zhuang } 234*28b02e23SHaojian Zhuang } 235*28b02e23SHaojian Zhuang } 236*28b02e23SHaojian Zhuang 237*28b02e23SHaojian Zhuang static void hikey960_sr_dma_reinit(void) 238*28b02e23SHaojian Zhuang { 239*28b02e23SHaojian Zhuang unsigned int ctr = 0; 240*28b02e23SHaojian Zhuang 241*28b02e23SHaojian Zhuang mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3); 242*28b02e23SHaojian Zhuang 243*28b02e23SHaojian Zhuang /* 1~15 channel is set non_secure */ 244*28b02e23SHaojian Zhuang for (ctr = 1; ctr <= 15; ctr++) 245*28b02e23SHaojian Zhuang mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40), 246*28b02e23SHaojian Zhuang (1 << 6) | (1 << 18)); 247*28b02e23SHaojian Zhuang } 248*28b02e23SHaojian Zhuang 249*28b02e23SHaojian Zhuang static void 250*28b02e23SHaojian Zhuang hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 251*28b02e23SHaojian Zhuang { 252*28b02e23SHaojian Zhuang unsigned long mpidr = read_mpidr_el1(); 253*28b02e23SHaojian Zhuang unsigned int cluster = 254*28b02e23SHaojian Zhuang (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; 255*28b02e23SHaojian Zhuang 256*28b02e23SHaojian Zhuang /* Nothing to be done on waking up from retention from CPU level */ 257*28b02e23SHaojian Zhuang if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 258*28b02e23SHaojian Zhuang return; 259*28b02e23SHaojian Zhuang 260*28b02e23SHaojian Zhuang if (hisi_test_ap_suspend_flag(cluster)) { 261*28b02e23SHaojian Zhuang hikey960_sr_dma_reinit(); 262*28b02e23SHaojian Zhuang gicv2_cpuif_enable(); 263*28b02e23SHaojian Zhuang console_init(PL011_UART6_BASE, PL011_UART_CLK_IN_HZ, 264*28b02e23SHaojian Zhuang PL011_BAUDRATE); 265*28b02e23SHaojian Zhuang } 266*28b02e23SHaojian Zhuang 267*28b02e23SHaojian Zhuang hikey960_pwr_domain_on_finish(target_state); 268*28b02e23SHaojian Zhuang } 269*28b02e23SHaojian Zhuang 270*28b02e23SHaojian Zhuang static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state) 271*28b02e23SHaojian Zhuang { 272*28b02e23SHaojian Zhuang int i; 273*28b02e23SHaojian Zhuang 274*28b02e23SHaojian Zhuang for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 275*28b02e23SHaojian Zhuang req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 276*28b02e23SHaojian Zhuang } 277*28b02e23SHaojian Zhuang 278*28b02e23SHaojian Zhuang static const plat_psci_ops_t hikey960_psci_ops = { 279*28b02e23SHaojian Zhuang .cpu_standby = hikey960_pwr_domain_standby, 280*28b02e23SHaojian Zhuang .pwr_domain_on = hikey960_pwr_domain_on, 281*28b02e23SHaojian Zhuang .pwr_domain_on_finish = hikey960_pwr_domain_on_finish, 282*28b02e23SHaojian Zhuang .pwr_domain_off = hikey960_pwr_domain_off, 283*28b02e23SHaojian Zhuang .pwr_domain_suspend = hikey960_pwr_domain_suspend, 284*28b02e23SHaojian Zhuang .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish, 285*28b02e23SHaojian Zhuang .system_off = NULL, 286*28b02e23SHaojian Zhuang .system_reset = hikey960_system_reset, 287*28b02e23SHaojian Zhuang .validate_power_state = hikey960_validate_power_state, 288*28b02e23SHaojian Zhuang .validate_ns_entrypoint = hikey960_validate_ns_entrypoint, 289*28b02e23SHaojian Zhuang .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state, 290*28b02e23SHaojian Zhuang }; 291*28b02e23SHaojian Zhuang 292*28b02e23SHaojian Zhuang int plat_setup_psci_ops(uintptr_t sec_entrypoint, 293*28b02e23SHaojian Zhuang const plat_psci_ops_t **psci_ops) 294*28b02e23SHaojian Zhuang { 295*28b02e23SHaojian Zhuang hikey960_sec_entrypoint = sec_entrypoint; 296*28b02e23SHaojian Zhuang 297*28b02e23SHaojian Zhuang INFO("%s: sec_entrypoint=0x%lx\n", __func__, 298*28b02e23SHaojian Zhuang (unsigned long)hikey960_sec_entrypoint); 299*28b02e23SHaojian Zhuang 300*28b02e23SHaojian Zhuang /* 301*28b02e23SHaojian Zhuang * Initialize PSCI ops struct 302*28b02e23SHaojian Zhuang */ 303*28b02e23SHaojian Zhuang *psci_ops = &hikey960_psci_ops; 304*28b02e23SHaojian Zhuang return 0; 305*28b02e23SHaojian Zhuang } 306