2021-11-16 01:48:20 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2022, MediaTek Inc. All rights reserved.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <common/debug.h>
|
|
|
|
#include <lib/mmio.h>
|
|
|
|
#include <plat/common/platform.h>
|
|
|
|
#include <mt_spm.h>
|
|
|
|
#include <mt_spm_conservation.h>
|
|
|
|
#include <mt_spm_internal.h>
|
|
|
|
#include <mt_spm_reg.h>
|
|
|
|
#include <mt_spm_resource_req.h>
|
2021-11-16 02:18:46 +00:00
|
|
|
#include <mt_spm_vcorefs.h>
|
2021-11-16 01:48:20 +00:00
|
|
|
#include <plat_mtk_lpm.h>
|
|
|
|
#include <plat_pm.h>
|
|
|
|
#include <platform_def.h>
|
|
|
|
|
|
|
|
#define MT_RESUMETIME_THRESHOLD_MAX (5U) /*ms*/
|
|
|
|
#define IS_RESUME_OVERTIME(delta) (delta > MT_RESUMETIME_THRESHOLD_MAX)
|
|
|
|
|
|
|
|
static struct wake_status spm_wakesta; /* record last wakesta */
|
|
|
|
|
|
|
|
static int go_to_spm_before_wfi(int state_id, unsigned int ext_opand,
|
|
|
|
struct spm_lp_scen *spm_lp,
|
|
|
|
unsigned int resource_req)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
struct pwr_ctrl *pwrctrl;
|
|
|
|
uint32_t cpu = plat_my_core_pos();
|
|
|
|
|
|
|
|
pwrctrl = spm_lp->pwrctrl;
|
|
|
|
|
|
|
|
__spm_set_cpu_status(cpu);
|
|
|
|
__spm_set_power_control(pwrctrl);
|
|
|
|
__spm_set_wakeup_event(pwrctrl);
|
2021-11-16 02:18:46 +00:00
|
|
|
__spm_sync_vcore_dvfs_power_control(pwrctrl, __spm_vcorefs.pwrctrl);
|
2021-11-16 01:48:20 +00:00
|
|
|
__spm_set_pcm_flags(pwrctrl);
|
|
|
|
|
|
|
|
__spm_src_req_update(pwrctrl, resource_req);
|
|
|
|
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
|
|
|
|
__spm_set_pcm_wdt(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
|
|
|
|
__spm_xo_soc_bblpm(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
|
|
|
|
spm_hw_s1_state_monitor_resume();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Disable auto resume by PCM in system suspend stage */
|
|
|
|
if (IS_PLAT_SUSPEND_ID(state_id)) {
|
|
|
|
__spm_disable_pcm_timer();
|
|
|
|
__spm_set_pcm_wdt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
__spm_send_cpu_wakeup_event();
|
|
|
|
|
|
|
|
INFO("cpu%d: wakesrc = 0x%x, settle = 0x%x, sec = %u\n",
|
|
|
|
cpu, pwrctrl->wake_src, mmio_read_32(SPM_CLK_SETTLE),
|
|
|
|
(mmio_read_32(PCM_TIMER_VAL) / 32768));
|
|
|
|
INFO("sw_flag = 0x%x 0x%x, req = 0x%x, pwr = 0x%x 0x%x\n",
|
|
|
|
pwrctrl->pcm_flags, pwrctrl->pcm_flags1,
|
|
|
|
mmio_read_32(SPM_SRC_REQ), mmio_read_32(PWR_STATUS),
|
|
|
|
mmio_read_32(PWR_STATUS_2ND));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void go_to_spm_after_wfi(int state_id, unsigned int ext_opand,
|
|
|
|
struct spm_lp_scen *spm_lp,
|
|
|
|
struct wake_status **status)
|
|
|
|
{
|
|
|
|
unsigned int ext_status = 0U;
|
|
|
|
|
|
|
|
spm_wakesta.tr.comm.resumetime = 0;
|
|
|
|
spm_wakesta.tr.comm.times_h = spm_wakesta.tr.comm.times_l = 0;
|
|
|
|
|
|
|
|
/* system watchdog will be resumed at kernel stage */
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
|
|
|
|
__spm_set_pcm_wdt(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_SRCLKEN_RC_BBLPM) != 0U) {
|
|
|
|
__spm_xo_soc_bblpm(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
|
|
|
|
spm_hw_s1_state_monitor_pause(&ext_status);
|
|
|
|
}
|
|
|
|
|
|
|
|
__spm_ext_int_wakeup_req_clr();
|
|
|
|
|
|
|
|
__spm_get_wakeup_status(&spm_wakesta, ext_status);
|
|
|
|
|
|
|
|
if (status != NULL) {
|
|
|
|
*status = &spm_wakesta;
|
|
|
|
}
|
|
|
|
|
|
|
|
__spm_clean_after_wakeup();
|
|
|
|
|
|
|
|
if (IS_PLAT_SUSPEND_ID(state_id)) {
|
|
|
|
__spm_output_wake_reason(state_id, &spm_wakesta);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int spm_conservation(int state_id, unsigned int ext_opand,
|
|
|
|
struct spm_lp_scen *spm_lp, unsigned int resource_req)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (spm_lp == NULL) {
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
spm_lock_get();
|
|
|
|
go_to_spm_before_wfi(state_id, ext_opand, spm_lp, resource_req);
|
|
|
|
spm_lock_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void spm_conservation_finish(int state_id, unsigned int ext_opand,
|
|
|
|
struct spm_lp_scen *spm_lp,
|
|
|
|
struct wake_status **status)
|
|
|
|
{
|
|
|
|
spm_lock_get();
|
|
|
|
go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
|
|
|
|
spm_lock_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
int spm_conservation_get_result(struct wake_status **res)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (res == NULL) {
|
|
|
|
ret = -1;
|
|
|
|
} else {
|
|
|
|
*res = &spm_wakesta;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define GPIO_BANK (GPIO_BASE + 0x6F0)
|
|
|
|
#define TRAP_UFS_FIRST BIT(11) /* bit 11, 0: UFS, 1: eMMC */
|
|
|
|
|
|
|
|
void spm_conservation_pwrctrl_init(struct pwr_ctrl *pwrctrl)
|
|
|
|
{
|
|
|
|
if (pwrctrl != NULL) {
|
|
|
|
/* For ufs, emmc storage type */
|
|
|
|
if ((mmio_read_32(GPIO_BANK) & TRAP_UFS_FIRST) != 0U) {
|
|
|
|
/* If eMMC is used, mask UFS req */
|
|
|
|
pwrctrl->reg_ufs_srcclkena_mask_b = 0;
|
|
|
|
pwrctrl->reg_ufs_infra_req_mask_b = 0;
|
|
|
|
pwrctrl->reg_ufs_apsrc_req_mask_b = 0;
|
|
|
|
pwrctrl->reg_ufs_vrf18_req_mask_b = 0;
|
|
|
|
pwrctrl->reg_ufs_ddren_req_mask_b = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|