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