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 #ifndef MTK_PLAT_CIRQ_UNSUPPORT
9 #include <mtk_cirq.h>
10 #endif
11 #include <drivers/spm/mt_spm_resource_req.h>
12 #include <lib/pm/mtk_pm.h>
13 #include <lpm/mt_lp_rm.h>
14 #include <mt_spm.h>
15 #include <mt_spm_cond.h>
16 #include <mt_spm_conservation.h>
17 #include <mt_spm_constraint.h>
18 #include <mt_spm_idle.h>
19 #include <mt_spm_internal.h>
20 #include <mt_spm_notifier.h>
21 #include "mt_spm_rc_api.h"
22 #include "mt_spm_rc_internal.h"
23 #include <mt_spm_reg.h>
24 #include <mt_spm_suspend.h>
25 
26 #define CONSTRAINT_BUS26M_ALLOW (MT_RM_CONSTRAINT_ALLOW_CPU_BUCK_OFF | \
27 				 MT_RM_CONSTRAINT_ALLOW_DRAM_S0 | \
28 				 MT_RM_CONSTRAINT_ALLOW_DRAM_S1 | \
29 				 MT_RM_CONSTRAINT_ALLOW_VCORE_LP | \
30 				 MT_RM_CONSTRAINT_ALLOW_LVTS_STATE | \
31 				 MT_RM_CONSTRAINT_ALLOW_BUS26M_OFF)
32 
33 #define CONSTRAINT_BUS26M_PCM_FLAG (SPM_FLAG_DISABLE_INFRA_PDN | \
34 				    SPM_FLAG_DISABLE_VCORE_DVS | \
35 				    SPM_FLAG_DISABLE_VCORE_DFS | \
36 				    SPM_FLAG_SRAM_SLEEP_CTRL | \
37 				    SPM_FLAG_ENABLE_LVTS_WORKAROUND | \
38 				    SPM_FLAG_KEEP_CSYSPWRACK_HIGH | \
39 				    SPM_FLAG_DISABLE_DRAMC_MCU_SRAM_SLEEP)
40 
41 #define CONSTRAINT_BUS26M_PCM_FLAG1 (SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH)
42 
43 /* If sspm sram won't enter sleep voltage then vcore couldn't enter low power mode */
44 #if defined(MTK_PLAT_SPM_SRAM_SLP_UNSUPPORT) && SPM_SRAM_SLEEP_RC_RES_RESTRICT
45 #define CONSTRAINT_BUS26M_RESOURCE_REQ	(MT_SPM_26M)
46 #else
47 #define CONSTRAINT_BUS26M_RESOURCE_REQ	(0)
48 #endif
49 
50 static unsigned int bus26m_ext_opand;
51 static unsigned int bus26m_ext_opand2;
52 
53 static struct mt_irqremain *refer2remain_irq;
54 
55 static struct mt_spm_cond_tables cond_bus26m = {
56 	.name = "bus26m",
57 	.table_cg = {
58 		0xFF5DD002,	/* MTCMOS1 */
59 		0x0000003C,	/* MTCMOS2 */
60 		0x27AF8000,	/* INFRA0  */
61 		0x22010876,	/* INFRA1  */
62 		0x86000650,	/* INFRA2  */
63 		0x30008020,	/* INFRA3  */
64 		0x80000000,	/* INFRA4  */
65 		0x01002A3B,	/* PERI0   */
66 		0x00090000,	/* VPPSYS0_0  */
67 		0x38FF3E69,     /* VPPSYS0_1  */
68 		0xF0081450,	/* VPPSYS1_0  */
69 		0x00003000,     /* VPPSYS1_1  */
70 		0x00000000,	/* VDOSYS0_0  */
71 		0x00000000,     /* VDOSYS0_1  */
72 		0x000001FF,	/* VDOSYS1_0  */
73 		0x000001E0,     /* VDOSYS1_1  */
74 		0x00FB0007,	/* VDOSYS1_2  */
75 	},
76 	.table_pll = (PLL_BIT_UNIVPLL |
77 		      PLL_BIT_MFGPLL |
78 		      PLL_BIT_MSDCPLL |
79 		      PLL_BIT_TVDPLL1 |
80 		      PLL_BIT_TVDPLL2 |
81 		      PLL_BIT_MMPLL |
82 		      PLL_BIT_ETHPLL |
83 		      PLL_BIT_IMGPLL |
84 		      PLL_BIT_APLL1 |
85 		      PLL_BIT_APLL2 |
86 		      PLL_BIT_APLL3 |
87 		      PLL_BIT_APLL4 |
88 		      PLL_BIT_APLL5),
89 };
90 
91 static struct mt_spm_cond_tables cond_bus26m_res = {
92 	.table_cg = { 0U },
93 	.table_pll = 0U,
94 };
95 
96 static struct constraint_status status = {
97 	.id = MT_RM_CONSTRAINT_ID_BUS26M,
98 	.is_valid = (MT_SPM_RC_VALID_SW |
99 		     MT_SPM_RC_VALID_COND_CHECK |
100 		     MT_SPM_RC_VALID_COND_LATCH |
101 		     MT_SPM_RC_VALID_TRACE_TIME),
102 	.is_cond_block = 0U,
103 	.enter_cnt = 0U,
104 	.all_pll_dump = 0U,
105 	.cond_res = &cond_bus26m_res,
106 	.residency = 0ULL,
107 };
108 
109 #ifdef MTK_PLAT_CIRQ_UNSUPPORT
110 #define do_irqs_delivery()
111 #else
mt_spm_irq_remain_dump(struct mt_irqremain * irqs,unsigned int irq_index,struct wake_status * wakeup)112 static void mt_spm_irq_remain_dump(struct mt_irqremain *irqs,
113 				   unsigned int irq_index,
114 				   struct wake_status *wakeup)
115 {
116 	if ((irqs == NULL) || (wakeup == NULL)) {
117 		return;
118 	}
119 
120 	INFO("[SPM] r12=0x%08x(0x%08x), flag=0x%08x 0x%08x 0x%08x, irq:%u(0x%08x) set pending\n",
121 	     wakeup->tr.comm.r12,
122 	     wakeup->md32pcm_wakeup_sta,
123 	     wakeup->tr.comm.debug_flag,
124 	     wakeup->tr.comm.b_sw_flag0,
125 	     wakeup->tr.comm.b_sw_flag1,
126 	     irqs->wakeupsrc[irq_index],
127 	     irqs->irqs[irq_index]);
128 }
129 
do_irqs_delivery(void)130 static void do_irqs_delivery(void)
131 {
132 	unsigned int idx;
133 	struct wake_status *wakeup = NULL;
134 	struct mt_irqremain *irqs = refer2remain_irq;
135 
136 	if (irqs == NULL) {
137 		return;
138 	}
139 
140 	if (spm_conservation_get_result(&wakeup) == 0) {
141 		if (wakeup != NULL) {
142 			for (idx = 0; idx < irqs->count; idx++) {
143 				if (((wakeup->tr.comm.r12 & irqs->wakeupsrc[idx]) != 0U) ||
144 				    ((wakeup->tr.comm.raw_sta & irqs->wakeupsrc[idx]) != 0U)) {
145 					if ((irqs->wakeupsrc_cat[idx] &
146 					     MT_IRQ_REMAIN_CAT_LOG) != 0U) {
147 						mt_spm_irq_remain_dump(irqs, idx, wakeup);
148 					}
149 					mt_irq_set_pending(irqs->irqs[idx]);
150 				}
151 			}
152 		}
153 	}
154 }
155 #endif
156 
spm_bus26m_conduct(int state_id,struct spm_lp_scen * spm_lp,unsigned int * resource_req)157 int spm_bus26m_conduct(int state_id, struct spm_lp_scen *spm_lp, unsigned int *resource_req)
158 {
159 	unsigned int res_req = CONSTRAINT_BUS26M_RESOURCE_REQ;
160 
161 	if ((spm_lp == NULL) || (resource_req == NULL)) {
162 		return -1;
163 	}
164 
165 	spm_lp->pwrctrl->pcm_flags = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG;
166 	spm_lp->pwrctrl->pcm_flags1 = (uint32_t)CONSTRAINT_BUS26M_PCM_FLAG1;
167 
168 	*resource_req |= res_req;
169 	return 0;
170 }
171 
spm_is_valid_rc_bus26m(unsigned int cpu,int state_id)172 bool spm_is_valid_rc_bus26m(unsigned int cpu, int state_id)
173 {
174 	return (!(status.is_cond_block && (status.is_valid & MT_SPM_RC_VALID_COND_CHECK) > 0) &&
175 		IS_MT_RM_RC_READY(status.is_valid) &&
176 		(IS_PLAT_SUSPEND_ID(state_id) || (state_id == MT_PLAT_PWR_STATE_SYSTEM_BUS)));
177 }
178 
update_rc_condition(int state_id,const void * val)179 static int update_rc_condition(int state_id, const void *val)
180 {
181 	const struct mt_spm_cond_tables *tlb = (const struct mt_spm_cond_tables *)val;
182 	const struct mt_spm_cond_tables *tlb_check =
183 		(const struct mt_spm_cond_tables *)&cond_bus26m;
184 
185 	if (tlb == NULL) {
186 		return MT_RM_STATUS_BAD;
187 	}
188 
189 	status.is_cond_block = mt_spm_cond_check(state_id, tlb, tlb_check,
190 						 (status.is_valid & MT_SPM_RC_VALID_COND_LATCH) ?
191 						 &cond_bus26m_res : NULL);
192 	status.all_pll_dump = mt_spm_dump_all_pll(tlb, tlb_check,
193 						  (status.is_valid & MT_SPM_RC_VALID_COND_LATCH) ?
194 						  &cond_bus26m_res : NULL);
195 	return MT_RM_STATUS_OK;
196 }
197 
update_rc_remain_irqs(const void * val)198 static void update_rc_remain_irqs(const void *val)
199 {
200 	refer2remain_irq = (struct mt_irqremain *)val;
201 }
202 
update_rc_fmaudio_adsp(int type,const void * val)203 static void update_rc_fmaudio_adsp(int type, const void *val)
204 {
205 	int *flag = (int *)val;
206 	unsigned int ext_op = (type == PLAT_RC_IS_ADSP) ?
207 			      (MT_SPM_EX_OP_SET_IS_ADSP | MT_SPM_EX_OP_SET_SUSPEND_MODE) :
208 			      MT_SPM_EX_OP_SET_SUSPEND_MODE;
209 
210 	if (flag == NULL) {
211 		return;
212 	}
213 
214 	if (*flag != 0) {
215 		SPM_RC_BITS_SET(bus26m_ext_opand, ext_op);
216 	} else {
217 		SPM_RC_BITS_CLR(bus26m_ext_opand, ext_op);
218 	}
219 }
220 
update_rc_usb_peri(const void * val)221 static void update_rc_usb_peri(const void *val)
222 {
223 	int *flag = (int *)val;
224 
225 	if (flag == NULL) {
226 		return;
227 	}
228 
229 	if (*flag != 0) {
230 		SPM_RC_BITS_SET(bus26m_ext_opand2, MT_SPM_EX_OP_PERI_ON);
231 	} else {
232 		SPM_RC_BITS_CLR(bus26m_ext_opand2, MT_SPM_EX_OP_PERI_ON);
233 	}
234 }
235 
update_rc_usb_infra(const void * val)236 static void update_rc_usb_infra(const void *val)
237 {
238 	int *flag = (int *)val;
239 
240 	if (flag == NULL) {
241 		return;
242 	}
243 
244 	if (*flag != 0) {
245 		SPM_RC_BITS_SET(bus26m_ext_opand2, MT_SPM_EX_OP_INFRA_ON);
246 	} else {
247 		SPM_RC_BITS_CLR(bus26m_ext_opand2, MT_SPM_EX_OP_INFRA_ON);
248 	}
249 }
250 
update_rc_status(const void * val)251 static void update_rc_status(const void *val)
252 {
253 	const struct rc_common_state *st;
254 
255 	st = (const struct rc_common_state *)val;
256 
257 	if (st == NULL) {
258 		return;
259 	}
260 
261 	if (st->type == CONSTRAINT_UPDATE_COND_CHECK) {
262 		struct mt_spm_cond_tables * const tlb = &cond_bus26m;
263 
264 		spm_rc_condition_modifier(st->id, st->act, st->value,
265 					  MT_RM_CONSTRAINT_ID_BUS26M, tlb);
266 	} else if ((st->type == CONSTRAINT_UPDATE_VALID) ||
267 		   (st->type == CONSTRAINT_RESIDNECY)) {
268 		spm_rc_constraint_status_set(st->id, st->type, st->act,
269 					     MT_RM_CONSTRAINT_ID_BUS26M,
270 					     (struct constraint_status * const)st->value,
271 					     (struct constraint_status * const)&status);
272 	} else {
273 		INFO("[%s:%d] - Unknown type: 0x%x\n", __func__, __LINE__, st->type);
274 	}
275 }
276 
spm_update_rc_bus26m(int state_id,int type,const void * val)277 int spm_update_rc_bus26m(int state_id, int type, const void *val)
278 {
279 	int res = MT_RM_STATUS_OK;
280 
281 	switch (type) {
282 	case PLAT_RC_UPDATE_CONDITION:
283 		res = update_rc_condition(state_id, val);
284 		break;
285 	case PLAT_RC_UPDATE_REMAIN_IRQS:
286 		update_rc_remain_irqs(val);
287 		break;
288 	case PLAT_RC_IS_FMAUDIO:
289 	case PLAT_RC_IS_ADSP:
290 		update_rc_fmaudio_adsp(type, val);
291 		break;
292 	case PLAT_RC_IS_USB_PERI:
293 		update_rc_usb_peri(val);
294 		break;
295 	case PLAT_RC_IS_USB_INFRA:
296 		update_rc_usb_infra(val);
297 		break;
298 	case PLAT_RC_STATUS:
299 		update_rc_status(val);
300 		break;
301 	default:
302 		INFO("[%s:%d] - Do nothing for type: %d\n", __func__, __LINE__, type);
303 		break;
304 	}
305 	return res;
306 }
307 
spm_allow_rc_bus26m(int state_id)308 unsigned int spm_allow_rc_bus26m(int state_id)
309 {
310 	return CONSTRAINT_BUS26M_ALLOW;
311 }
312 
spm_run_rc_bus26m(unsigned int cpu,int state_id)313 int spm_run_rc_bus26m(unsigned int cpu, int state_id)
314 {
315 	unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
316 
317 #ifndef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
318 	mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_ENTER, CONSTRAINT_BUS26M_ALLOW |
319 			       (IS_PLAT_SUSPEND_ID(state_id) ?
320 				MT_RM_CONSTRAINT_ALLOW_AP_SUSPEND : 0));
321 #endif
322 	if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME) {
323 		ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
324 	}
325 
326 	if (IS_PLAT_SUSPEND_ID(state_id)) {
327 		mt_spm_suspend_enter(state_id,
328 				     (MT_SPM_EX_OP_CLR_26M_RECORD |
329 				      MT_SPM_EX_OP_SET_WDT |
330 				      MT_SPM_EX_OP_HW_S1_DETECT |
331 				      bus26m_ext_opand |
332 				      bus26m_ext_opand2),
333 				     CONSTRAINT_BUS26M_RESOURCE_REQ);
334 	} else {
335 		mt_spm_idle_generic_enter(state_id, ext_op, spm_bus26m_conduct);
336 	}
337 	return MT_RM_STATUS_OK;
338 }
339 
spm_reset_rc_bus26m(unsigned int cpu,int state_id)340 int spm_reset_rc_bus26m(unsigned int cpu, int state_id)
341 {
342 	unsigned int ext_op = MT_SPM_EX_OP_HW_S1_DETECT;
343 
344 #ifndef MTK_PLAT_SPM_SSPM_NOTIFIER_UNSUPPORT
345 	mt_spm_sspm_notify_u32(MT_SPM_NOTIFY_LP_LEAVE, 0);
346 #endif
347 	if (status.is_valid & MT_SPM_RC_VALID_TRACE_TIME) {
348 		ext_op |= MT_SPM_EX_OP_TRACE_TIMESTAMP_EN;
349 	}
350 
351 	if (IS_PLAT_SUSPEND_ID(state_id)) {
352 		mt_spm_suspend_resume(state_id,
353 				      (bus26m_ext_opand | bus26m_ext_opand2 |
354 				       MT_SPM_EX_OP_SET_WDT | ext_op),
355 				      NULL);
356 		bus26m_ext_opand = 0;
357 	} else {
358 		struct wake_status *waken = NULL;
359 
360 		if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_TRACE_EVENT)) {
361 			ext_op |= MT_SPM_EX_OP_TRACE_LP;
362 		}
363 
364 		mt_spm_idle_generic_resume(state_id, ext_op, &waken, NULL);
365 		status.enter_cnt++;
366 
367 		if (spm_unlikely(status.is_valid & MT_SPM_RC_VALID_RESIDNECY)) {
368 			status.residency += (waken != NULL) ? waken->tr.comm.timer_out : 0;
369 		}
370 	}
371 
372 	do_irqs_delivery();
373 
374 	return MT_RM_STATUS_OK;
375 }
376 
spm_get_status_rc_bus26m(unsigned int type,void * priv)377 int spm_get_status_rc_bus26m(unsigned int type, void *priv)
378 {
379 	int ret = MT_RM_STATUS_OK;
380 
381 	if (type == PLAT_RC_STATUS) {
382 		int res = 0;
383 		struct rc_common_state *st = (struct rc_common_state *)priv;
384 
385 		if (st == NULL) {
386 			return MT_RM_STATUS_BAD;
387 		}
388 
389 		res = spm_rc_constraint_status_get(st->id, st->type,
390 						   st->act, MT_RM_CONSTRAINT_ID_BUS26M,
391 						   (struct constraint_status * const)&status,
392 						   (struct constraint_status * const)st->value);
393 		if ((res == 0) && (st->id != MT_RM_CONSTRAINT_ID_ALL)) {
394 			ret = MT_RM_STATUS_STOP;
395 		}
396 	}
397 	return ret;
398 }
399