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