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
pwr_state_prompt(unsigned int cpu,const psci_power_state_t * state)23 static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
24 {
25 return 0;
26 }
27
pwr_state_reflect(unsigned int cpu,const psci_power_state_t * state)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
pwr_cpu_pwron(unsigned int cpu,const psci_power_state_t * state)39 static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
40 {
41 return 0;
42 }
43
pwr_cpu_pwrdwn(unsigned int cpu,const psci_power_state_t * state)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
pwr_cluster_pwron(unsigned int cpu,const psci_power_state_t * state)52 static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
53 {
54 return 0;
55 }
56
pwr_cluster_pwrdwn(unsigned int cpu,const psci_power_state_t * state)57 static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
58 {
59 return 0;
60 }
61
pwr_mcusys_pwron(unsigned int cpu,const psci_power_state_t * state)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
pwr_mcusys_pwron_finished(unsigned int cpu,const psci_power_state_t * state)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
pwr_mcusys_pwrdwn(unsigned int cpu,const psci_power_state_t * state)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) {
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
120 plat_mt_lp_cpu_rc = -1;
121
122 return -1;
123 }
124
125 static const struct mt_lpm_tz plat_pm = {
126 .pwr_prompt = pwr_state_prompt,
127 .pwr_reflect = pwr_state_reflect,
128 .pwr_cpu_on = pwr_cpu_pwron,
129 .pwr_cpu_dwn = pwr_cpu_pwrdwn,
130 .pwr_cluster_on = pwr_cluster_pwron,
131 .pwr_cluster_dwn = pwr_cluster_pwrdwn,
132 .pwr_mcusys_dwn = pwr_mcusys_pwrdwn,
133 .pwr_mcusys_on = pwr_mcusys_pwron,
134 .pwr_mcusys_on_finished = pwr_mcusys_pwron_finished
135 };
136
mt_plat_cpu_pm_init(void)137 const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
138 {
139 mtk_cpc_init();
140
141 if (mcdi_try_init() == 0) {
142 INFO("MCDI init done.\n");
143 }
144
145 mt_lp_irqremain_init();
146
147 return &plat_pm;
148 }
149