1 /* 2 * Copyright (c) 2019, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 /* common headers */ 8 #include <arch_helpers.h> 9 #include <assert.h> 10 #include <common/debug.h> 11 #include <lib/mmio.h> 12 #include <lib/psci/psci.h> 13 #include <errno.h> 14 15 /* mediatek platform specific headers */ 16 #include <platform_def.h> 17 #include <scu.h> 18 #include <mt_gic_v3.h> 19 #include <mtk_plat_common.h> 20 #include <mtgpio.h> 21 #include <mtspmc.h> 22 #include <plat_dcm.h> 23 #include <plat_debug.h> 24 #include <plat_params.h> 25 #include <plat_private.h> 26 #include <power_tracer.h> 27 #include <pmic.h> 28 #include <spm.h> 29 #include <spm_suspend.h> 30 #include <rtc.h> 31 32 #define MTK_LOCAL_STATE_OFF 2 33 34 static uintptr_t secure_entrypoint; 35 36 static void mp1_L2_desel_config(void) 37 { 38 mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820); 39 40 dsb(); 41 } 42 43 static int plat_mtk_power_domain_on(unsigned long mpidr) 44 { 45 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 46 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 47 48 INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n", 49 __func__, __LINE__, mpidr, cluster, cpu); 50 51 /* power on cluster */ 52 if (!spm_get_cluster_powerstate(cluster)) { 53 spm_poweron_cluster(cluster); 54 if (cluster == 1) { 55 l2c_parity_check_setup(); 56 circular_buffer_setup(); 57 mp1_L2_desel_config(); 58 mt_gic_sync_dcm_disable(); 59 } 60 } 61 62 /* init cpu reset arch as AARCH64 */ 63 mcucfg_init_archstate(cluster, cpu, 1); 64 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 65 66 spm_poweron_cpu(cluster, cpu); 67 68 return PSCI_E_SUCCESS; 69 } 70 71 static void plat_mtk_power_domain_off(const psci_power_state_t *state) 72 { 73 uint64_t mpidr = read_mpidr(); 74 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 75 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 76 77 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 78 79 /* Prevent interrupts from spuriously waking up this cpu */ 80 mt_gic_cpuif_disable(); 81 82 spm_enable_cpu_auto_off(cluster, cpu); 83 84 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 85 if (cluster == 1) 86 mt_gic_sync_dcm_enable(); 87 88 plat_mtk_cci_disable(); 89 spm_enable_cluster_auto_off(cluster); 90 } 91 92 spm_set_cpu_power_off(cluster, cpu); 93 } 94 95 static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state) 96 { 97 uint64_t mpidr = read_mpidr(); 98 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 99 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 100 101 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 102 103 assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF); 104 105 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 106 enable_scu(mpidr); 107 108 /* Enable coherency if this cluster was off */ 109 plat_mtk_cci_enable(); 110 /* Enable big core dcm if this cluster was on */ 111 plat_dcm_restore_cluster_on(mpidr); 112 /* Enable rgu dcm if this cluster was off */ 113 plat_dcm_rgu_enable(); 114 } 115 116 spm_disable_cpu_auto_off(cluster, cpu); 117 118 /* Enable the gic cpu interface */ 119 mt_gic_pcpu_init(); 120 mt_gic_cpuif_enable(); 121 } 122 123 /******************************************************************************* 124 * MTK handlers to shutdown/reboot the system 125 ******************************************************************************/ 126 static void __dead2 plat_mtk_system_off(void) 127 { 128 INFO("MTK System Off\n"); 129 130 rtc_power_off_sequence(); 131 wk_pmic_enable_sdn_delay(); 132 pmic_power_off(); 133 134 wfi(); 135 ERROR("MTK System Off: operation not handled.\n"); 136 panic(); 137 } 138 139 static void __dead2 plat_mtk_system_reset(void) 140 { 141 struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); 142 143 INFO("MTK System Reset\n"); 144 145 mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity); 146 147 wfi(); 148 ERROR("MTK System Reset: operation not handled.\n"); 149 panic(); 150 } 151 152 static void plat_mtk_power_domain_suspend(const psci_power_state_t *state) 153 { 154 uint64_t mpidr = read_mpidr(); 155 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 156 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 157 158 spm_system_suspend(); 159 160 /* init cpu reset arch as AARCH64 */ 161 mcucfg_init_archstate(cluster, cpu, 1); 162 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 163 spm_set_bootaddr(secure_entrypoint); 164 165 /* Prevent interrupts from spuriously waking up this cpu */ 166 mt_gic_cpuif_disable(); 167 mt_gic_irq_save(); 168 169 if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) { 170 plat_mtk_cci_disable(); 171 disable_scu(mpidr); 172 } 173 } 174 175 static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state) 176 { 177 uint64_t mpidr = read_mpidr(); 178 179 mt_gic_init(); 180 mt_gic_irq_restore(); 181 182 if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) { 183 enable_scu(mpidr); 184 plat_mtk_cci_enable(); 185 plat_dcm_restore_cluster_on(mpidr); 186 } 187 188 mmio_write_32(EMI_WFIFO, 0xf); 189 spm_system_suspend_finish(); 190 } 191 192 static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state) 193 { 194 assert(PLAT_MAX_PWR_LVL >= 2); 195 196 for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) 197 req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; 198 } 199 200 /******************************************************************************* 201 * MTK_platform handler called when an affinity instance is about to be turned 202 * on. The level and mpidr determine the affinity instance. 203 ******************************************************************************/ 204 static const plat_psci_ops_t plat_plat_pm_ops = { 205 .cpu_standby = NULL, 206 .pwr_domain_on = plat_mtk_power_domain_on, 207 .pwr_domain_on_finish = plat_mtk_power_domain_on_finish, 208 .pwr_domain_off = plat_mtk_power_domain_off, 209 .pwr_domain_suspend = plat_mtk_power_domain_suspend, 210 .pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish, 211 .system_off = plat_mtk_system_off, 212 .system_reset = plat_mtk_system_reset, 213 .validate_power_state = NULL, 214 .get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state, 215 }; 216 217 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 218 const plat_psci_ops_t **psci_ops) 219 { 220 *psci_ops = &plat_plat_pm_ops; 221 secure_entrypoint = sec_entrypoint; 222 return 0; 223 } 224