xref: /rk3399_ARM-atf/plat/mediatek/mt8183/plat_pm.c (revision 7352f329e8db1ee655ef1a062ef6fc6dabb3bec2)
1 /*
2  * Copyright (c) 2019, MediaTek Inc. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /* common headers */
8 #include <arch_helpers.h>
9 #include <assert.h>
10 #include <common/debug.h>
11 #include <lib/mmio.h>
12 #include <lib/psci/psci.h>
13 #include <errno.h>
14 
15 /* mediatek platform specific headers */
16 #include <platform_def.h>
17 #include <scu.h>
18 #include <mt_gic_v3.h>
19 #include <mtk_plat_common.h>
20 #include <mtspmc.h>
21 #include <power_tracer.h>
22 #include <plat_dcm.h>
23 #include <plat_debug.h>
24 #include <plat_private.h>
25 
26 #define MTK_LOCAL_STATE_OFF     2
27 
28 static uintptr_t secure_entrypoint;
29 
30 static void mp1_L2_desel_config(void)
31 {
32 	mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820);
33 
34 	dsb();
35 }
36 
37 static int plat_mtk_power_domain_on(unsigned long mpidr)
38 {
39 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
40 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
41 
42 	INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n",
43 		__func__, __LINE__, mpidr, cluster, cpu);
44 
45 	/* power on cluster */
46 	if (!spm_get_cluster_powerstate(cluster)) {
47 		spm_poweron_cluster(cluster);
48 		if (cluster == 1) {
49 			l2c_parity_check_setup();
50 			circular_buffer_setup();
51 			mp1_L2_desel_config();
52 			mt_gic_sync_dcm_disable();
53 		}
54 	}
55 
56 	/* init cpu reset arch as AARCH64 */
57 	mcucfg_init_archstate(cluster, cpu, 1);
58 	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
59 
60 	spm_poweron_cpu(cluster, cpu);
61 
62 	return PSCI_E_SUCCESS;
63 }
64 
65 static void plat_mtk_power_domain_off(const psci_power_state_t *state)
66 {
67 	uint64_t mpidr = read_mpidr();
68 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
69 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
70 
71 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
72 
73 	/* Prevent interrupts from spuriously waking up this cpu */
74 	mt_gic_cpuif_disable();
75 
76 	spm_enable_cpu_auto_off(cluster, cpu);
77 
78 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
79 		if (cluster == 1)
80 			mt_gic_sync_dcm_enable();
81 
82 		plat_mtk_cci_disable();
83 		spm_enable_cluster_auto_off(cluster);
84 	}
85 
86 	spm_set_cpu_power_off(cluster, cpu);
87 }
88 
89 static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
90 {
91 	uint64_t mpidr = read_mpidr();
92 	int cpu = MPIDR_AFFLVL0_VAL(mpidr);
93 	int cluster = MPIDR_AFFLVL1_VAL(mpidr);
94 
95 	INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
96 
97 	assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
98 
99 	if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
100 		enable_scu(mpidr);
101 
102 		/* Enable coherency if this cluster was off */
103 		plat_mtk_cci_enable();
104 		/* Enable big core dcm if this cluster was on */
105 		plat_dcm_restore_cluster_on(mpidr);
106 		/* Enable rgu dcm if this cluster was off */
107 		plat_dcm_rgu_enable();
108 	}
109 
110 	spm_disable_cpu_auto_off(cluster, cpu);
111 
112 	/* Enable the gic cpu interface */
113 	mt_gic_pcpu_init();
114 	mt_gic_cpuif_enable();
115 }
116 
117 /*******************************************************************************
118  * MTK_platform handler called when an affinity instance is about to be turned
119  * on. The level and mpidr determine the affinity instance.
120  ******************************************************************************/
121 static const plat_psci_ops_t plat_plat_pm_ops = {
122 	.cpu_standby			= NULL,
123 	.pwr_domain_on			= plat_mtk_power_domain_on,
124 	.pwr_domain_on_finish		= plat_mtk_power_domain_on_finish,
125 	.pwr_domain_off			= plat_mtk_power_domain_off,
126 	.pwr_domain_suspend		= NULL,
127 	.pwr_domain_suspend_finish	= NULL,
128 	.system_off			= NULL,
129 	.system_reset			= NULL,
130 	.validate_power_state		= NULL,
131 	.get_sys_suspend_power_state	= NULL,
132 };
133 
134 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
135 			const plat_psci_ops_t **psci_ops)
136 {
137 	*psci_ops = &plat_plat_pm_ops;
138 	secure_entrypoint = sec_entrypoint;
139 	return 0;
140 }
141