mediatek: mt8183: support CPU hotplug
[project/bcm63xx/atf.git] / plat / mediatek / mt8183 / plat_pm.c
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 }