summaryrefslogtreecommitdiffstats
path: root/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
blob: 8c012e7519cbfedc9f92119eee53a47a3e3b9461 (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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
 * Copyright (c) 2021, MediaTek Inc. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <assert.h>
#include <stdint.h>

#include <arch_helpers.h>
#include <lib/psci/psci.h>
#include <lib/spinlock.h>

#include <mt_cpu_pm_cpc.h>
#include <mt_lp_irqremain.h>
#include <mt_lp_rm.h>
#include <mt_mcdi.h>
#include <plat_mtk_lpm.h>
#include <plat_pm.h>

DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);

static int plat_mt_lp_cpu_rc;

static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
{
	return 0;
}

static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
{
	mtk_cpc_core_on_hint_clr(cpu);

	if (IS_SYSTEM_SUSPEND_STATE(state)) {
		mtk_cpc_time_sync();
	}

	return 0;
}

static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
{
	return 0;
}

static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
{
	/* clear DBGPRCR.CORENPDRQ to allow CPU power down  */
	write_dbgprcr_el1(0ULL);

	return 0;
}

static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
{
	return 0;
}

static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
{
	return 0;
}

static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
{
	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
		return -1;
	}

	mtk_cpc_mcusys_off_reflect();

	return 0;
}

static int pwr_mcusys_pwron_finished(unsigned int cpu,
					const psci_power_state_t *state)
{
	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];

	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
		return -1;
	}

	mt_lp_rm_reset_constraint(plat_mt_lp_cpu_rc, cpu, state_id);
	mt_lp_irqremain_release();

	return 0;
}

static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
{
	int state_id = state->pwr_domain_state[MTK_AFFLVL_MCUSYS];

	if (!IS_MCUSYS_OFF_STATE(state)) {
		goto mt_pwr_mcusysoff_break;
	}

	if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
		goto mt_pwr_mcusysoff_break;
	}

	if (mtk_cpc_mcusys_off_prepare() != CPC_SUCCESS) {
		goto mt_pwr_mcusysoff_break;
	}

	plat_mt_lp_cpu_rc =
		mt_lp_rm_find_and_run_constraint(0, cpu, state_id, NULL);

	if (plat_mt_lp_cpu_rc < 0) {
		goto mt_pwr_mcusysoff_reflect;
	}

	mt_lp_irqremain_aquire();

	return 0;

mt_pwr_mcusysoff_reflect:
	mtk_cpc_mcusys_off_reflect();

mt_pwr_mcusysoff_break:
	plat_mt_lp_cpu_rc = -1;

	return -1;
}

static const struct mt_lpm_tz plat_pm = {
	.pwr_prompt			= pwr_state_prompt,
	.pwr_reflect			= pwr_state_reflect,
	.pwr_cpu_on			= pwr_cpu_pwron,
	.pwr_cpu_dwn			= pwr_cpu_pwrdwn,
	.pwr_cluster_on			= pwr_cluster_pwron,
	.pwr_cluster_dwn		= pwr_cluster_pwrdwn,
	.pwr_mcusys_dwn			= pwr_mcusys_pwrdwn,
	.pwr_mcusys_on			= pwr_mcusys_pwron,
	.pwr_mcusys_on_finished		= pwr_mcusys_pwron_finished
};

const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
{
	mtk_cpc_init();

	if (mcdi_try_init() == 0) {
		INFO("MCDI init done.\n");
	}

	mt_lp_irqremain_init();

	return &plat_pm;
}