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