summaryrefslogtreecommitdiff
path: root/plat/mediatek/drivers/spm/mt8188/mt_spm_conservation.c
blob: bcb2df64b6880be7b8f6d27d66dd936852e630b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * 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;
}