1 /* 2 * Copyright (c) 2021, MediaTek Inc. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdint.h> 9 10 #include <arch_helpers.h> 11 #include <lib/psci/psci.h> 12 #include <lib/spinlock.h> 13 14 #include <mt_cpu_pm_cpc.h> 15 #include <mt_lp_irqremain.h> 16 #include <mt_lp_rm.h> 17 #include <mt_mcdi.h> 18 #include <plat_mtk_lpm.h> 19 #include <plat_pm.h> 20 21 DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1); 22 23 static int plat_mt_lp_cpu_rc; 24 25 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state) 26 { 27 return 0; 28 } 29 30 static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state) 31 { 32 mtk_cpc_core_on_hint_clr(cpu); 33 34 if (IS_SYSTEM_SUSPEND_STATE(state)) { 35 mtk_cpc_time_sync(); 36 } 37 38 return 0; 39 } 40 41 static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state) 42 { 43 return 0; 44 } 45 46 static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state) 47 { 48 /* clear DBGPRCR.CORENPDRQ to allow CPU power down */ 49 write_dbgprcr_el1(0ULL); 50 51 return 0; 52 } 53 54 static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state) 55 { 56 return 0; 57 } 58 59 static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state) 60 { 61 return 0; 62 } 63 64 static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state) 65 { 66 if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) { 67 return -1; 68 } 69 70 mtk_cpc_mcusys_off_reflect(); 71 72 return 0; 73 } 74 75 static int pwr_mcusys_pwron_finished(unsigned int cpu, 76 const psci_power_state_t *state) 77 { 78 int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS]; 79 80 if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) { 81 return -1; 82 } 83 84 mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id); 85 mt_lp_irqremain_release(); 86 87 return 0; 88 } 89 90 static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state) 91 { 92 int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS]; 93 94 if (!IS_MCUSYS_OFF_STATE(state)) { 95 goto mt_pwr_mcusysoff_break; 96 } 97 98 if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */ 99 goto mt_pwr_mcusysoff_break; 100 } 101 102 if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) { 103 goto mt_pwr_mcusysoff_break; 104 } 105 106 plat_mt_lp_cpu_rc = 107 mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL); 108 109 if (plat_mt_lp_cpu_rc < 0) { 110 goto mt_pwr_mcusysoff_reflect; 111 } 112 113 mt_lp_irqremain_aquire(); 114 115 return 0; 116 117 mt_pwr_mcusysoff_reflect: 118 mtk_cpc_mcusys_off_reflect(); 119 120 mt_pwr_mcusysoff_break: 121 plat_mt_lp_cpu_rc = -1; 122 123 return -1; 124 } 125 126 static const struct mt_lpm_tz plat_pm = { 127 .pwr_prompt = pwr_state_prompt, 128 .pwr_reflect = pwr_state_reflect, 129 .pwr_cpu_on = pwr_cpu_pwron, 130 .pwr_cpu_dwn = pwr_cpu_pwrdwn, 131 .pwr_cluster_on = pwr_cluster_pwron, 132 .pwr_cluster_dwn = pwr_cluster_pwrdwn, 133 .pwr_mcusys_dwn = pwr_mcusys_pwrdwn, 134 .pwr_mcusys_on = pwr_mcusys_pwron, 135 .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished 136 }; 137 138 const struct mt_lpm_tz *mt_plat_cpu_pm_init(void) 139 { 140 mtk_cpc_init(); 141 142 if (mcdi_try_init() == 0) { 143 INFO("MCDI init done.\n"); 144 } 145 146 mt_lp_irqremain_init(); 147 148 return &plat_pm; 149 } 150