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