1*127793daSHaojian Zhuang /* 2*127793daSHaojian Zhuang * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. 3*127793daSHaojian Zhuang * 4*127793daSHaojian Zhuang * SPDX-License-Identifier: BSD-3-Clause 5*127793daSHaojian Zhuang */ 6*127793daSHaojian Zhuang 7*127793daSHaojian Zhuang #include <arch_helpers.h> 8*127793daSHaojian Zhuang #include <assert.h> 9*127793daSHaojian Zhuang #include <cci.h> 10*127793daSHaojian Zhuang #include <debug.h> 11*127793daSHaojian Zhuang #include <gicv2.h> 12*127793daSHaojian Zhuang #include <hi6220.h> 13*127793daSHaojian Zhuang #include <hisi_ipc.h> 14*127793daSHaojian Zhuang #include <hisi_pwrc.h> 15*127793daSHaojian Zhuang #include <hisi_sram_map.h> 16*127793daSHaojian Zhuang #include <mmio.h> 17*127793daSHaojian Zhuang #include <psci.h> 18*127793daSHaojian Zhuang 19*127793daSHaojian Zhuang #include "hikey_def.h" 20*127793daSHaojian Zhuang 21*127793daSHaojian Zhuang #define HIKEY_CLUSTER_STATE_ON 0 22*127793daSHaojian Zhuang #define HIKEY_CLUSTER_STATE_OFF 1 23*127793daSHaojian Zhuang 24*127793daSHaojian Zhuang static uintptr_t hikey_sec_entrypoint; 25*127793daSHaojian Zhuang /* There're two clusters in HiKey. */ 26*127793daSHaojian Zhuang static int hikey_cluster_state[] = {HIKEY_CLUSTER_STATE_OFF, 27*127793daSHaojian Zhuang HIKEY_CLUSTER_STATE_OFF}; 28*127793daSHaojian Zhuang 29*127793daSHaojian Zhuang /******************************************************************************* 30*127793daSHaojian Zhuang * Handler called when a power domain is about to be turned on. The 31*127793daSHaojian Zhuang * level and mpidr determine the affinity instance. 32*127793daSHaojian Zhuang ******************************************************************************/ 33*127793daSHaojian Zhuang static int hikey_pwr_domain_on(u_register_t mpidr) 34*127793daSHaojian Zhuang { 35*127793daSHaojian Zhuang int cpu, cluster; 36*127793daSHaojian Zhuang int curr_cluster; 37*127793daSHaojian Zhuang 38*127793daSHaojian Zhuang cluster = MPIDR_AFFLVL1_VAL(mpidr); 39*127793daSHaojian Zhuang cpu = MPIDR_AFFLVL0_VAL(mpidr); 40*127793daSHaojian Zhuang curr_cluster = MPIDR_AFFLVL1_VAL(read_mpidr()); 41*127793daSHaojian Zhuang if (cluster != curr_cluster) 42*127793daSHaojian Zhuang hisi_ipc_cluster_on(cpu, cluster); 43*127793daSHaojian Zhuang 44*127793daSHaojian Zhuang hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint); 45*127793daSHaojian Zhuang hisi_ipc_cpu_on(cpu, cluster); 46*127793daSHaojian Zhuang return 0; 47*127793daSHaojian Zhuang } 48*127793daSHaojian Zhuang 49*127793daSHaojian Zhuang static void hikey_pwr_domain_on_finish(const psci_power_state_t *target_state) 50*127793daSHaojian Zhuang { 51*127793daSHaojian Zhuang unsigned long mpidr; 52*127793daSHaojian Zhuang int cpu, cluster; 53*127793daSHaojian Zhuang 54*127793daSHaojian Zhuang mpidr = read_mpidr(); 55*127793daSHaojian Zhuang cluster = MPIDR_AFFLVL1_VAL(mpidr); 56*127793daSHaojian Zhuang cpu = MPIDR_AFFLVL0_VAL(mpidr); 57*127793daSHaojian Zhuang if (hikey_cluster_state[cluster] == HIKEY_CLUSTER_STATE_OFF) { 58*127793daSHaojian Zhuang /* 59*127793daSHaojian Zhuang * Enable CCI coherency for this cluster. 60*127793daSHaojian Zhuang * No need for locks as no other cpu is active at the moment. 61*127793daSHaojian Zhuang */ 62*127793daSHaojian Zhuang cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 63*127793daSHaojian Zhuang hikey_cluster_state[cluster] = HIKEY_CLUSTER_STATE_ON; 64*127793daSHaojian Zhuang } 65*127793daSHaojian Zhuang 66*127793daSHaojian Zhuang /* Zero the jump address in the mailbox for this cpu */ 67*127793daSHaojian Zhuang hisi_pwrc_set_core_bx_addr(cpu, cluster, 0); 68*127793daSHaojian Zhuang 69*127793daSHaojian Zhuang /* Program the GIC per-cpu distributor or re-distributor interface */ 70*127793daSHaojian Zhuang gicv2_pcpu_distif_init(); 71*127793daSHaojian Zhuang /* Enable the GIC cpu interface */ 72*127793daSHaojian Zhuang gicv2_cpuif_enable(); 73*127793daSHaojian Zhuang } 74*127793daSHaojian Zhuang 75*127793daSHaojian Zhuang /******************************************************************************* 76*127793daSHaojian Zhuang * Handler called when a power domain is about to be turned off. The 77*127793daSHaojian Zhuang * target_state encodes the power state that each level should transition to. 78*127793daSHaojian Zhuang ******************************************************************************/ 79*127793daSHaojian Zhuang void hikey_pwr_domain_off(const psci_power_state_t *target_state) 80*127793daSHaojian Zhuang { 81*127793daSHaojian Zhuang unsigned long mpidr; 82*127793daSHaojian Zhuang int cpu, cluster; 83*127793daSHaojian Zhuang 84*127793daSHaojian Zhuang gicv2_cpuif_disable(); 85*127793daSHaojian Zhuang 86*127793daSHaojian Zhuang mpidr = read_mpidr(); 87*127793daSHaojian Zhuang cluster = MPIDR_AFFLVL1_VAL(mpidr); 88*127793daSHaojian Zhuang cpu = MPIDR_AFFLVL0_VAL(mpidr); 89*127793daSHaojian Zhuang if (target_state->pwr_domain_state[MPIDR_AFFLVL1] == 90*127793daSHaojian Zhuang PLAT_MAX_OFF_STATE) { 91*127793daSHaojian Zhuang hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); 92*127793daSHaojian Zhuang cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 93*127793daSHaojian Zhuang hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); 94*127793daSHaojian Zhuang 95*127793daSHaojian Zhuang hisi_ipc_cluster_off(cpu, cluster); 96*127793daSHaojian Zhuang hikey_cluster_state[cluster] = HIKEY_CLUSTER_STATE_OFF; 97*127793daSHaojian Zhuang } 98*127793daSHaojian Zhuang hisi_ipc_cpu_off(cpu, cluster); 99*127793daSHaojian Zhuang } 100*127793daSHaojian Zhuang 101*127793daSHaojian Zhuang /******************************************************************************* 102*127793daSHaojian Zhuang * Handler to reboot the system. 103*127793daSHaojian Zhuang ******************************************************************************/ 104*127793daSHaojian Zhuang static void __dead2 hikey_system_reset(void) 105*127793daSHaojian Zhuang { 106*127793daSHaojian Zhuang /* Send the system reset request */ 107*127793daSHaojian Zhuang mmio_write_32(AO_SC_SYS_STAT0, 0x48698284); 108*127793daSHaojian Zhuang isb(); 109*127793daSHaojian Zhuang dsb(); 110*127793daSHaojian Zhuang 111*127793daSHaojian Zhuang wfi(); 112*127793daSHaojian Zhuang panic(); 113*127793daSHaojian Zhuang } 114*127793daSHaojian Zhuang 115*127793daSHaojian Zhuang /******************************************************************************* 116*127793daSHaojian Zhuang * Handler called to check the validity of the power state parameter. 117*127793daSHaojian Zhuang ******************************************************************************/ 118*127793daSHaojian Zhuang int hikey_validate_power_state(unsigned int power_state, 119*127793daSHaojian Zhuang psci_power_state_t *req_state) 120*127793daSHaojian Zhuang { 121*127793daSHaojian Zhuang int pstate = psci_get_pstate_type(power_state); 122*127793daSHaojian Zhuang int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 123*127793daSHaojian Zhuang int i; 124*127793daSHaojian Zhuang 125*127793daSHaojian Zhuang assert(req_state); 126*127793daSHaojian Zhuang 127*127793daSHaojian Zhuang if (pwr_lvl > PLAT_MAX_PWR_LVL) 128*127793daSHaojian Zhuang return PSCI_E_INVALID_PARAMS; 129*127793daSHaojian Zhuang 130*127793daSHaojian Zhuang /* Sanity check the requested state */ 131*127793daSHaojian Zhuang if (pstate == PSTATE_TYPE_STANDBY) { 132*127793daSHaojian Zhuang /* 133*127793daSHaojian Zhuang * It's possible to enter standby only on power level 0 134*127793daSHaojian Zhuang * Ignore any other power level. 135*127793daSHaojian Zhuang */ 136*127793daSHaojian Zhuang if (pwr_lvl != MPIDR_AFFLVL0) 137*127793daSHaojian Zhuang return PSCI_E_INVALID_PARAMS; 138*127793daSHaojian Zhuang 139*127793daSHaojian Zhuang req_state->pwr_domain_state[MPIDR_AFFLVL0] = 140*127793daSHaojian Zhuang PLAT_MAX_RET_STATE; 141*127793daSHaojian Zhuang } else { 142*127793daSHaojian Zhuang for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) 143*127793daSHaojian Zhuang req_state->pwr_domain_state[i] = 144*127793daSHaojian Zhuang PLAT_MAX_OFF_STATE; 145*127793daSHaojian Zhuang } 146*127793daSHaojian Zhuang 147*127793daSHaojian Zhuang /* 148*127793daSHaojian Zhuang * We expect the 'state id' to be zero. 149*127793daSHaojian Zhuang */ 150*127793daSHaojian Zhuang if (psci_get_pstate_id(power_state)) 151*127793daSHaojian Zhuang return PSCI_E_INVALID_PARAMS; 152*127793daSHaojian Zhuang 153*127793daSHaojian Zhuang return PSCI_E_SUCCESS; 154*127793daSHaojian Zhuang } 155*127793daSHaojian Zhuang 156*127793daSHaojian Zhuang /******************************************************************************* 157*127793daSHaojian Zhuang * Handler called to check the validity of the non secure entrypoint. 158*127793daSHaojian Zhuang ******************************************************************************/ 159*127793daSHaojian Zhuang static int hikey_validate_ns_entrypoint(uintptr_t entrypoint) 160*127793daSHaojian Zhuang { 161*127793daSHaojian Zhuang /* 162*127793daSHaojian Zhuang * Check if the non secure entrypoint lies within the non 163*127793daSHaojian Zhuang * secure DRAM. 164*127793daSHaojian Zhuang */ 165*127793daSHaojian Zhuang if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE))) 166*127793daSHaojian Zhuang return PSCI_E_SUCCESS; 167*127793daSHaojian Zhuang 168*127793daSHaojian Zhuang return PSCI_E_INVALID_ADDRESS; 169*127793daSHaojian Zhuang } 170*127793daSHaojian Zhuang 171*127793daSHaojian Zhuang /******************************************************************************* 172*127793daSHaojian Zhuang * Export the platform handlers to enable psci to invoke them 173*127793daSHaojian Zhuang ******************************************************************************/ 174*127793daSHaojian Zhuang static const plat_psci_ops_t hikey_psci_ops = { 175*127793daSHaojian Zhuang .cpu_standby = NULL, 176*127793daSHaojian Zhuang .pwr_domain_on = hikey_pwr_domain_on, 177*127793daSHaojian Zhuang .pwr_domain_on_finish = hikey_pwr_domain_on_finish, 178*127793daSHaojian Zhuang .pwr_domain_off = hikey_pwr_domain_off, 179*127793daSHaojian Zhuang .pwr_domain_suspend = NULL, 180*127793daSHaojian Zhuang .pwr_domain_suspend_finish = NULL, 181*127793daSHaojian Zhuang .system_off = NULL, 182*127793daSHaojian Zhuang .system_reset = hikey_system_reset, 183*127793daSHaojian Zhuang .validate_power_state = hikey_validate_power_state, 184*127793daSHaojian Zhuang .validate_ns_entrypoint = hikey_validate_ns_entrypoint, 185*127793daSHaojian Zhuang .get_sys_suspend_power_state = NULL, 186*127793daSHaojian Zhuang }; 187*127793daSHaojian Zhuang 188*127793daSHaojian Zhuang /******************************************************************************* 189*127793daSHaojian Zhuang * Export the platform specific power ops and initialize Power Controller 190*127793daSHaojian Zhuang ******************************************************************************/ 191*127793daSHaojian Zhuang int plat_setup_psci_ops(uintptr_t sec_entrypoint, 192*127793daSHaojian Zhuang const plat_psci_ops_t **psci_ops) 193*127793daSHaojian Zhuang { 194*127793daSHaojian Zhuang hikey_sec_entrypoint = sec_entrypoint; 195*127793daSHaojian Zhuang 196*127793daSHaojian Zhuang /* 197*127793daSHaojian Zhuang * Initialize PSCI ops struct 198*127793daSHaojian Zhuang */ 199*127793daSHaojian Zhuang *psci_ops = &hikey_psci_ops; 200*127793daSHaojian Zhuang 201*127793daSHaojian Zhuang return 0; 202*127793daSHaojian Zhuang } 203