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 <rtc.h> 29 30 #define MTK_LOCAL_STATE_OFF 2 31 32 static uintptr_t secure_entrypoint; 33 34 static void mp1_L2_desel_config(void) 35 { 36 mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820); 37 38 dsb(); 39 } 40 41 static int plat_mtk_power_domain_on(unsigned long mpidr) 42 { 43 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 44 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 45 46 INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n", 47 __func__, __LINE__, mpidr, cluster, cpu); 48 49 /* power on cluster */ 50 if (!spm_get_cluster_powerstate(cluster)) { 51 spm_poweron_cluster(cluster); 52 if (cluster == 1) { 53 l2c_parity_check_setup(); 54 circular_buffer_setup(); 55 mp1_L2_desel_config(); 56 mt_gic_sync_dcm_disable(); 57 } 58 } 59 60 /* init cpu reset arch as AARCH64 */ 61 mcucfg_init_archstate(cluster, cpu, 1); 62 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); 63 64 spm_poweron_cpu(cluster, cpu); 65 66 return PSCI_E_SUCCESS; 67 } 68 69 static void plat_mtk_power_domain_off(const psci_power_state_t *state) 70 { 71 uint64_t mpidr = read_mpidr(); 72 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 73 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 74 75 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 76 77 /* Prevent interrupts from spuriously waking up this cpu */ 78 mt_gic_cpuif_disable(); 79 80 spm_enable_cpu_auto_off(cluster, cpu); 81 82 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 83 if (cluster == 1) 84 mt_gic_sync_dcm_enable(); 85 86 plat_mtk_cci_disable(); 87 spm_enable_cluster_auto_off(cluster); 88 } 89 90 spm_set_cpu_power_off(cluster, cpu); 91 } 92 93 static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state) 94 { 95 uint64_t mpidr = read_mpidr(); 96 int cpu = MPIDR_AFFLVL0_VAL(mpidr); 97 int cluster = MPIDR_AFFLVL1_VAL(mpidr); 98 99 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu); 100 101 assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF); 102 103 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { 104 enable_scu(mpidr); 105 106 /* Enable coherency if this cluster was off */ 107 plat_mtk_cci_enable(); 108 /* Enable big core dcm if this cluster was on */ 109 plat_dcm_restore_cluster_on(mpidr); 110 /* Enable rgu dcm if this cluster was off */ 111 plat_dcm_rgu_enable(); 112 } 113 114 spm_disable_cpu_auto_off(cluster, cpu); 115 116 /* Enable the gic cpu interface */ 117 mt_gic_pcpu_init(); 118 mt_gic_cpuif_enable(); 119 } 120 121 /******************************************************************************* 122 * MTK handlers to shutdown/reboot the system 123 ******************************************************************************/ 124 static void __dead2 plat_mtk_system_off(void) 125 { 126 INFO("MTK System Off\n"); 127 128 rtc_power_off_sequence(); 129 wk_pmic_enable_sdn_delay(); 130 pmic_power_off(); 131 132 wfi(); 133 ERROR("MTK System Off: operation not handled.\n"); 134 panic(); 135 } 136 137 static void __dead2 plat_mtk_system_reset(void) 138 { 139 struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); 140 141 INFO("MTK System Reset\n"); 142 143 mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity); 144 145 wfi(); 146 ERROR("MTK System Reset: operation not handled.\n"); 147 panic(); 148 } 149 150 /******************************************************************************* 151 * MTK_platform handler called when an affinity instance is about to be turned 152 * on. The level and mpidr determine the affinity instance. 153 ******************************************************************************/ 154 static const plat_psci_ops_t plat_plat_pm_ops = { 155 .cpu_standby = NULL, 156 .pwr_domain_on = plat_mtk_power_domain_on, 157 .pwr_domain_on_finish = plat_mtk_power_domain_on_finish, 158 .pwr_domain_off = plat_mtk_power_domain_off, 159 .pwr_domain_suspend = NULL, 160 .pwr_domain_suspend_finish = NULL, 161 .system_off = plat_mtk_system_off, 162 .system_reset = plat_mtk_system_reset, 163 .validate_power_state = NULL, 164 .get_sys_suspend_power_state = NULL, 165 }; 166 167 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 168 const plat_psci_ops_t **psci_ops) 169 { 170 *psci_ops = &plat_plat_pm_ops; 171 secure_entrypoint = sec_entrypoint; 172 return 0; 173 } 174