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