17ac6a76cSjason-ch chen /*
27ac6a76cSjason-ch chen * Copyright (c) 2022, MediaTek Inc. All rights reserved.
37ac6a76cSjason-ch chen *
47ac6a76cSjason-ch chen * SPDX-License-Identifier: BSD-3-Clause
57ac6a76cSjason-ch chen */
67ac6a76cSjason-ch chen
77ac6a76cSjason-ch chen #include <common/debug.h>
87ac6a76cSjason-ch chen #include <lib/mmio.h>
97ac6a76cSjason-ch chen #include <plat/common/platform.h>
107ac6a76cSjason-ch chen #include <mt_spm.h>
117ac6a76cSjason-ch chen #include <mt_spm_conservation.h>
127ac6a76cSjason-ch chen #include <mt_spm_internal.h>
137ac6a76cSjason-ch chen #include <mt_spm_reg.h>
147ac6a76cSjason-ch chen #include <mt_spm_resource_req.h>
15*635e6b10Sjason-ch chen #include <mt_spm_vcorefs.h>
167ac6a76cSjason-ch chen #include <plat_mtk_lpm.h>
177ac6a76cSjason-ch chen #include <plat_pm.h>
187ac6a76cSjason-ch chen #include <platform_def.h>
197ac6a76cSjason-ch chen
207ac6a76cSjason-ch chen #define MT_RESUMETIME_THRESHOLD_MAX (5U) /*ms*/
217ac6a76cSjason-ch chen #define IS_RESUME_OVERTIME(delta) (delta > MT_RESUMETIME_THRESHOLD_MAX)
227ac6a76cSjason-ch chen
237ac6a76cSjason-ch chen static struct wake_status spm_wakesta; /* record last wakesta */
247ac6a76cSjason-ch chen
go_to_spm_before_wfi(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,unsigned int resource_req)257ac6a76cSjason-ch chen static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
267ac6a76cSjason-ch chen struct spm_lp_scen *spm_lp,
277ac6a76cSjason-ch chen unsigned int resource_req)
287ac6a76cSjason-ch chen {
297ac6a76cSjason-ch chen int ret = 0;
307ac6a76cSjason-ch chen struct pwr_ctrl *pwrctrl;
317ac6a76cSjason-ch chen uint32_t cpu = plat_my_core_pos();
327ac6a76cSjason-ch chen
337ac6a76cSjason-ch chen pwrctrl = spm_lp->pwrctrl;
347ac6a76cSjason-ch chen
357ac6a76cSjason-ch chen __spm_set_cpu_status(cpu);
367ac6a76cSjason-ch chen __spm_set_power_control(pwrctrl);
377ac6a76cSjason-ch chen __spm_set_wakeup_event(pwrctrl);
38*635e6b10Sjason-ch chen __spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
397ac6a76cSjason-ch chen __spm_set_pcm_flags(pwrctrl);
407ac6a76cSjason-ch chen
417ac6a76cSjason-ch chen __spm_src_req_update(pwrctrl, resource_req);
427ac6a76cSjason-ch chen
437ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
447ac6a76cSjason-ch chen __spm_set_pcm_wdt(1);
457ac6a76cSjason-ch chen }
467ac6a76cSjason-ch chen
477ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
487ac6a76cSjason-ch chen __spm_xo_soc_bblpm(1);
497ac6a76cSjason-ch chen }
507ac6a76cSjason-ch chen
517ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
527ac6a76cSjason-ch chen spm_hw_s1_state_monitor_resume();
537ac6a76cSjason-ch chen }
547ac6a76cSjason-ch chen
557ac6a76cSjason-ch chen /* Disable auto resume by PCM in system suspend stage */
567ac6a76cSjason-ch chen if (IS_PLAT_SUSPEND_ID(state_id)) {
577ac6a76cSjason-ch chen __spm_disable_pcm_timer();
587ac6a76cSjason-ch chen __spm_set_pcm_wdt(0);
597ac6a76cSjason-ch chen }
607ac6a76cSjason-ch chen
617ac6a76cSjason-ch chen __spm_send_cpu_wakeup_event();
627ac6a76cSjason-ch chen
637ac6a76cSjason-ch chen INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
647ac6a76cSjason-ch chen cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
657ac6a76cSjason-ch chen (mmio_read_32(PCM_TIMER_VAL) / 32768));
667ac6a76cSjason-ch chen INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
677ac6a76cSjason-ch chen pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
687ac6a76cSjason-ch chen mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
697ac6a76cSjason-ch chen mmio_read_32(PWR_STATUS_2ND));
707ac6a76cSjason-ch chen
717ac6a76cSjason-ch chen return ret;
727ac6a76cSjason-ch chen }
737ac6a76cSjason-ch chen
go_to_spm_after_wfi(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)747ac6a76cSjason-ch chen static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
757ac6a76cSjason-ch chen struct spm_lp_scen *spm_lp,
767ac6a76cSjason-ch chen struct wake_status **status)
777ac6a76cSjason-ch chen {
787ac6a76cSjason-ch chen unsigned int ext_status = 0U;
797ac6a76cSjason-ch chen
807ac6a76cSjason-ch chen spm_wakesta.tr.comm.resumetime = 0;
817ac6a76cSjason-ch chen spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
827ac6a76cSjason-ch chen
837ac6a76cSjason-ch chen /* system watchdog will be resumed at kernel stage */
847ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
857ac6a76cSjason-ch chen __spm_set_pcm_wdt(0);
867ac6a76cSjason-ch chen }
877ac6a76cSjason-ch chen
887ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
897ac6a76cSjason-ch chen __spm_xo_soc_bblpm(0);
907ac6a76cSjason-ch chen }
917ac6a76cSjason-ch chen
927ac6a76cSjason-ch chen if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
937ac6a76cSjason-ch chen spm_hw_s1_state_monitor_pause(&ext_status);
947ac6a76cSjason-ch chen }
957ac6a76cSjason-ch chen
967ac6a76cSjason-ch chen __spm_ext_int_wakeup_req_clr();
977ac6a76cSjason-ch chen
987ac6a76cSjason-ch chen __spm_get_wakeup_status(&spm_wakesta, ext_status);
997ac6a76cSjason-ch chen
1007ac6a76cSjason-ch chen if (status != NULL) {
1017ac6a76cSjason-ch chen *status = &spm_wakesta;
1027ac6a76cSjason-ch chen }
1037ac6a76cSjason-ch chen
1047ac6a76cSjason-ch chen __spm_clean_after_wakeup();
1057ac6a76cSjason-ch chen
1067ac6a76cSjason-ch chen if (IS_PLAT_SUSPEND_ID(state_id)) {
1077ac6a76cSjason-ch chen __spm_output_wake_reason(state_id, &spm_wakesta);
1087ac6a76cSjason-ch chen }
1097ac6a76cSjason-ch chen
1107ac6a76cSjason-ch chen }
1117ac6a76cSjason-ch chen
spm_conservation(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,unsigned int resource_req)1127ac6a76cSjason-ch chen int spm_conservation(int state_id, unsigned int ext_opand,
1137ac6a76cSjason-ch chen struct spm_lp_scen *spm_lp, unsigned int resource_req)
1147ac6a76cSjason-ch chen {
1157ac6a76cSjason-ch chen int ret = 0;
1167ac6a76cSjason-ch chen
1177ac6a76cSjason-ch chen if (spm_lp == NULL) {
1187ac6a76cSjason-ch chen ret = -1;
1197ac6a76cSjason-ch chen } else {
1207ac6a76cSjason-ch chen spm_lock_get();
1217ac6a76cSjason-ch chen go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
1227ac6a76cSjason-ch chen spm_lock_release();
1237ac6a76cSjason-ch chen }
1247ac6a76cSjason-ch chen
1257ac6a76cSjason-ch chen return ret;
1267ac6a76cSjason-ch chen }
1277ac6a76cSjason-ch chen
spm_conservation_finish(int state_id,unsigned int ext_opand,struct spm_lp_scen * spm_lp,struct wake_status ** status)1287ac6a76cSjason-ch chen void spm_conservation_finish(int state_id, unsigned int ext_opand,
1297ac6a76cSjason-ch chen struct spm_lp_scen *spm_lp,
1307ac6a76cSjason-ch chen struct wake_status **status)
1317ac6a76cSjason-ch chen {
1327ac6a76cSjason-ch chen spm_lock_get();
1337ac6a76cSjason-ch chen go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
1347ac6a76cSjason-ch chen spm_lock_release();
1357ac6a76cSjason-ch chen }
1367ac6a76cSjason-ch chen
spm_conservation_get_result(struct wake_status ** res)1377ac6a76cSjason-ch chen int spm_conservation_get_result(struct wake_status **res)
1387ac6a76cSjason-ch chen {
1397ac6a76cSjason-ch chen int ret = 0;
1407ac6a76cSjason-ch chen
1417ac6a76cSjason-ch chen if (res == NULL) {
1427ac6a76cSjason-ch chen ret = -1;
1437ac6a76cSjason-ch chen } else {
1447ac6a76cSjason-ch chen *res = &spm_wakesta;
1457ac6a76cSjason-ch chen }
1467ac6a76cSjason-ch chen return ret;
1477ac6a76cSjason-ch chen }
1487ac6a76cSjason-ch chen
1497ac6a76cSjason-ch chen #define GPIO_BANK (GPIO_BASE + 0x6F0)
1507ac6a76cSjason-ch chen #define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
1517ac6a76cSjason-ch chen
spm_conservation_pwrctrl_init(struct pwr_ctrl * pwrctrl)1527ac6a76cSjason-ch chen void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
1537ac6a76cSjason-ch chen {
1547ac6a76cSjason-ch chen if (pwrctrl != NULL) {
1557ac6a76cSjason-ch chen /* For ufs, emmc storage type */
1567ac6a76cSjason-ch chen if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
1577ac6a76cSjason-ch chen /* If eMMC is used, mask UFS req */
1587ac6a76cSjason-ch chen pwrctrl->reg_ufs_srcclkena_mask_b = 0;
1597ac6a76cSjason-ch chen pwrctrl->reg_ufs_infra_req_mask_b = 0;
1607ac6a76cSjason-ch chen pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
1617ac6a76cSjason-ch chen pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
1627ac6a76cSjason-ch chen pwrctrl->reg_ufs_ddren_req_mask_b = 0;
1637ac6a76cSjason-ch chen }
1647ac6a76cSjason-ch chen }
1657ac6a76cSjason-ch chen }
166