xref: /rk3399_ARM-atf/plat/mediatek/mt8186/drivers/spm/mt_spm_conservation.c (revision 1f4adc3a34f80249d40bfc7033a65f4217d7ee04)
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