blob: bcb2df64b6880be7b8f6d27d66dd936852e630b1 [file] [log] [blame]
/*
* Copyright (c) 2023, MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <lib/pm/mtk_pm.h>
#include <lpm/mt_lp_rqm.h>
#include "mt_spm.h"
#include "mt_spm_conservation.h"
#include "mt_spm_reg.h"
#include <platform_def.h>
#define INFRA_EMI_DCM_CFG0 U(0x10002028)
static struct wake_status spm_wakesta; /* record last wakesta */
static wake_reason_t spm_wake_reason = WR_NONE;
static unsigned int emi_bak;
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;
unsigned int cpu = plat_my_core_pos();
pwrctrl = spm_lp->pwrctrl;
/* EMI workaround */
emi_bak = mmio_read_32(INFRA_EMI_DCM_CFG0) & BIT(22);
mmio_setbits_32(INFRA_EMI_DCM_CFG0, BIT(22));
__spm_set_cpu_status(cpu);
__spm_set_power_control(pwrctrl);
__spm_set_wakeup_event(pwrctrl);
__spm_set_pcm_flags(pwrctrl);
__spm_src_req_update(pwrctrl, resource_req);
if ((ext_opand & MT_SPM_EX_OP_CLR_26M_RECORD) != 0U) {
__spm_clean_before_wfi();
}
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
__spm_set_pcm_wdt(1);
}
if ((ext_opand & MT_SPM_EX_OP_HW_S1_DETECT) != 0U) {
spm_hw_s1_state_monitor_resume();
}
__spm_send_cpu_wakeup_event();
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;
if ((ext_opand & MT_SPM_EX_OP_SET_WDT) != 0U) {
__spm_set_pcm_wdt(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();
spm_wake_reason = __spm_output_wake_reason(&spm_wakesta);
/* EMI workaround */
if (emi_bak == 0U) {
mmio_clrbits_32(INFRA_EMI_DCM_CFG0, BIT(22));
}
}
int spm_conservation(int state_id, unsigned int ext_opand,
struct spm_lp_scen *spm_lp,
unsigned int resource_req)
{
unsigned int rc_state = resource_req;
if (spm_lp == NULL) {
return -1;
}
spin_lock(&spm_lock);
go_to_spm_before_wfi(state_id, ext_opand, spm_lp, rc_state);
spin_unlock(&spm_lock);
return 0;
}
void spm_conservation_finish(int state_id, unsigned int ext_opand, struct spm_lp_scen *spm_lp,
struct wake_status **status)
{
spin_lock(&spm_lock);
go_to_spm_after_wfi(state_id, ext_opand, spm_lp, status);
spin_unlock(&spm_lock);
}
int spm_conservation_get_result(struct wake_status **res)
{
if (res == NULL) {
return -1;
}
*res = &spm_wakesta;
return 0;
}