1 /*
2 * Copyright (c) 2023, MediaTek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <common/debug.h>
8 #include <drivers/spm/mt_spm_resource_req.h>
9 #include <lib/pm/mtk_pm.h>
10 #include <lpm/mt_lpm_smc.h>
11 #include <mt_spm.h>
12 #include <mt_spm_cond.h>
13 #include <mt_spm_conservation.h>
14 #include <mt_spm_constraint.h>
15 #include <mt_spm_idle.h>
16 #include <mt_spm_internal.h>
17 #include <mt_spm_notifier.h>
18 #include "mt_spm_rc_api.h"
19 #include "mt_spm_rc_internal.h"
20 #include <mt_spm_reg.h>
21 #include <mt_spm_suspend.h>
22
23 #define CONSTRAINT_CPU_BUCK_PCM_FLAG (SPM_FLAG_DISABLE_INFRA_PDN | \
24 SPM_FLAG_DISABLE_VCORE_DVS | \
25 SPM_FLAG_DISABLE_VCORE_DFS | \
26 SPM_FLAG_SRAM_SLEEP_CTRL | \
27 SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP | \
28 SPM_FLAG_KEEP_CSYSPWRACK_HIGH)
29
30 #define CONSTRAINT_CPU_BUCK_PCM_FLAG1 (0)
31
32 #define CONSTRAINT_CPU_BUCK_RESOURCE_REQ (MT_SPM_DRAM_S1 | \
33 MT_SPM_DRAM_S0 | \
34 MT_SPM_SYSPLL | \
35 MT_SPM_INFRA | \
36 MT_SPM_26M | \
37 MT_SPM_XO_FPM)
38
39 static unsigned int cpubuckldo_status = (MT_SPM_RC_VALID_SW | MT_SPM_RC_VALID_TRACE_TIME);
40 static unsigned int cpubuckldo_enter_cnt;
41
spm_cpu_bcuk_ldo_conduct(int state_id,struct spm_lp_scen * spm_lp,unsigned int * resource_req)42 int spm_cpu_bcuk_ldo_conduct(int state_id,
43 struct spm_lp_scen *spm_lp,
44 unsigned int *resource_req)
45 {
46 unsigned int res_req = CONSTRAINT_CPU_BUCK_RESOURCE_REQ;
47
48 if ((spm_lp == NULL) || (resource_req == NULL)) {
49 return -1;
50 }
51
52 spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG;
53 spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_CPU_BUCK_PCM_FLAG1;
54
55 *resource_req |= res_req;
56 return 0;
57 }
58
spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu,int state_id)59 bool spm_is_valid_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
60 {
61 return IS_MT_RM_RC_READY(cpubuckldo_status);
62 }
63
update_rc_status(const void * val)64 static void update_rc_status(const void *val)
65 {
66 const struct rc_common_state *st = (const struct rc_common_state *)val;
67
68 if (st == NULL) {
69 return;
70 }
71
72 if ((st->type == CONSTRAINT_UPDATE_VALID) && st->value) {
73 if ((st->id == MT_RM_CONSTRAINT_ID_ALL) ||
74 (st->id == MT_RM_CONSTRAINT_ID_CPU_BUCK_LDO)) {
75 struct constraint_status *con = (struct constraint_status *)st->value;
76
77 if ((st->act & MT_LPM_SMC_ACT_CLR) > 0U) {
78 SPM_RC_BITS_CLR(cpubuckldo_status, con->is_valid);
79 } else {
80 SPM_RC_BITS_SET(cpubuckldo_status, con->is_valid);
81 }
82 }
83 }
84 }
85
spm_update_rc_cpu_buck_ldo(int state_id,int type,const void * val)86 int spm_update_rc_cpu_buck_ldo(int state_id, int type, const void *val)
87 {
88 if (type == PLAT_RC_STATUS) {
89 update_rc_status(val);
90 }
91 return MT_RM_STATUS_OK;
92 }
93
spm_allow_rc_cpu_buck_ldo(int state_id)94 unsigned int spm_allow_rc_cpu_buck_ldo(int state_id)
95 {
96 return MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF;
97 }
98
spm_run_rc_cpu_buck_ldo(unsigned int cpu,int state_id)99 int spm_run_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
100 {
101 (void)cpu;
102 unsigned int ext_op = 0U;
103
104 #ifndef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
105 mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER,
106 (IS_PLAT_SUSPEND_ID(state_id) ?
107 MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : (0U)));
108 #endif
109 if (cpubuckldo_status & MT_SPM_RC_VALID_TRACE_TIME) {
110 ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
111 }
112
113 if (IS_PLAT_SUSPEND_ID(state_id)) {
114 mt_spm_suspend_enter(state_id,
115 (MT_SPM_EX_OP_CLR_26M_RECORD |
116 MT_SPM_EX_OP_SET_SUSPEND_MODE |
117 MT_SPM_EX_OP_SET_WDT),
118 CONSTRAINT_CPU_BUCK_RESOURCE_REQ);
119 } else {
120 mt_spm_idle_generic_enter(state_id, ext_op, spm_cpu_bcuk_ldo_conduct);
121 }
122
123 cpubuckldo_enter_cnt++;
124
125 return 0;
126 }
127
spm_reset_rc_cpu_buck_ldo(unsigned int cpu,int state_id)128 int spm_reset_rc_cpu_buck_ldo(unsigned int cpu, int state_id)
129 {
130 (void)cpu;
131 unsigned int ext_op = 0U;
132
133 #ifndef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
134 mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0U);
135 #endif
136 if (cpubuckldo_status & MT_SPM_RC_VALID_TRACE_TIME) {
137 ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
138 }
139
140 if (IS_PLAT_SUSPEND_ID(state_id)) {
141 mt_spm_suspend_resume(state_id, MT_SPM_EX_OP_SET_WDT, NULL);
142 } else {
143 mt_spm_idle_generic_resume(state_id, ext_op, NULL, NULL);
144 }
145
146 return 0;
147 }
148
spm_get_status_rc_cpu_buck_ldo(unsigned int type,void * priv)149 int spm_get_status_rc_cpu_buck_ldo(unsigned int type, void *priv)
150 {
151 int ret = MT_RM_STATUS_OK;
152
153 if (type != PLAT_RC_STATUS) {
154 return ret;
155 }
156
157 struct rc_common_state *st = (struct rc_common_state *)priv;
158
159 if (st == NULL) {
160 return MT_RM_STATUS_BAD;
161 }
162
163 if ((st->id == MT_RM_CONSTRAINT_ID_ALL) ||
164 (st->id == MT_RM_CONSTRAINT_ID_CPU_BUCK_LDO)) {
165 struct constraint_status *dest;
166
167 dest = (struct constraint_status *)st->value;
168 do {
169 if (dest == NULL) {
170 break;
171 }
172 if (st->type == CONSTRAINT_GET_VALID) {
173 dest->is_valid = cpubuckldo_status;
174 } else if (st->type == CONSTRAINT_COND_BLOCK) {
175 dest->is_cond_block = 0;
176 } else if (st->type == CONSTRAINT_GET_ENTER_CNT) {
177 if (st->id == MT_RM_CONSTRAINT_ID_ALL) {
178 dest->enter_cnt += cpubuckldo_enter_cnt;
179 } else {
180 dest->enter_cnt = cpubuckldo_enter_cnt;
181 }
182 } else {
183 break;
184 }
185 if (st->id != MT_RM_CONSTRAINT_ID_ALL) {
186 ret = MT_RM_STATUS_STOP;
187 }
188 } while (0);
189 }
190 return ret;
191 }
192