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