blob: c8a2d4c37eecfd87b0521152249e9339e1f92dcc [file] [log] [blame]
developer451d49d2022-11-16 21:52:21 +08001/*
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
50static unsigned int bus26m_ext_opand;
51static unsigned int bus26m_ext_opand2;
52
53static struct mt_irqremain *refer2remain_irq;
54
55static struct mt_spm_cond_tables cond_bus26m = {
developer68ff2df2023-05-03 19:11:29 +080056 .name = "bus26m",
developer451d49d2022-11-16 21:52:21 +080057 .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
91static struct mt_spm_cond_tables cond_bus26m_res = {
92 .table_cg = { 0U },
93 .table_pll = 0U,
94};
95
96static 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
112static 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
130static 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
157int 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
172bool 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
developer68ff2df2023-05-03 19:11:29 +0800179static int update_rc_condition(int state_id, const void *val)
developer451d49d2022-11-16 21:52:21 +0800180{
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
developer68ff2df2023-05-03 19:11:29 +0800189 status.is_cond_block = mt_spm_cond_check(state_id, tlb, tlb_check,
developer451d49d2022-11-16 21:52:21 +0800190 (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
198static void update_rc_remain_irqs(const void *val)
199{
200 refer2remain_irq = (struct mt_irqremain *)val;
201}
202
203static 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
221static 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
236static 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
251static 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
277int 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:
developer68ff2df2023-05-03 19:11:29 +0800283 res = update_rc_condition(state_id, val);
developer451d49d2022-11-16 21:52:21 +0800284 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
308unsigned int spm_allow_rc_bus26m(int state_id)
309{
310 return CONSTRAINT_BUS26M_ALLOW;
311}
312
313int 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
340int 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
377int 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}