blob: 9e0a920518be6bd6eb34a2d56d8ac2b694385e57 [file] [log] [blame]
kenny liang3fa9dec2019-04-10 21:09:26 +08001/*
kenny liang7352f322019-05-02 19:29:25 +08002 * Copyright (c) 2019, MediaTek Inc. All rights reserved.
kenny liang3fa9dec2019-04-10 21:09:26 +08003 *
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>
kenny liang7352f322019-05-02 19:29:25 +080018#include <mt_gic_v3.h>
kenny liang3fa9dec2019-04-10 21:09:26 +080019#include <mtk_plat_common.h>
kenny liang3d91c9c2019-05-03 17:02:46 +080020#include <mtgpio.h>
kenny liang7352f322019-05-02 19:29:25 +080021#include <mtspmc.h>
kenny liang7352f322019-05-02 19:29:25 +080022#include <plat_dcm.h>
23#include <plat_debug.h>
kenny liang3d91c9c2019-05-03 17:02:46 +080024#include <plat_params.h>
kenny liang3fa9dec2019-04-10 21:09:26 +080025#include <plat_private.h>
kenny liang3d91c9c2019-05-03 17:02:46 +080026#include <power_tracer.h>
kenny liange977b4d2019-05-02 20:02:05 +080027#include <pmic.h>
kenny liang3c25ba42019-08-21 20:50:20 +080028#include <spm.h>
29#include <spm_suspend.h>
kenny liange977b4d2019-05-02 20:02:05 +080030#include <rtc.h>
kenny liang3fa9dec2019-04-10 21:09:26 +080031
kenny liang7352f322019-05-02 19:29:25 +080032#define MTK_LOCAL_STATE_OFF 2
33
34static uintptr_t secure_entrypoint;
35
36static void mp1_L2_desel_config(void)
37{
38 mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820);
39
40 dsb();
41}
42
43static int plat_mtk_power_domain_on(unsigned long mpidr)
44{
45 int cpu = MPIDR_AFFLVL0_VAL(mpidr);
46 int cluster = MPIDR_AFFLVL1_VAL(mpidr);
47
48 INFO("%s():%d: mpidr: %lx, c.c: %d.%d\n",
49 __func__, __LINE__, mpidr, cluster, cpu);
50
51 /* power on cluster */
52 if (!spm_get_cluster_powerstate(cluster)) {
53 spm_poweron_cluster(cluster);
54 if (cluster == 1) {
55 l2c_parity_check_setup();
56 circular_buffer_setup();
57 mp1_L2_desel_config();
58 mt_gic_sync_dcm_disable();
59 }
60 }
61
62 /* init cpu reset arch as AARCH64 */
63 mcucfg_init_archstate(cluster, cpu, 1);
64 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
65
66 spm_poweron_cpu(cluster, cpu);
67
68 return PSCI_E_SUCCESS;
69}
70
71static void plat_mtk_power_domain_off(const psci_power_state_t *state)
72{
73 uint64_t mpidr = read_mpidr();
74 int cpu = MPIDR_AFFLVL0_VAL(mpidr);
75 int cluster = MPIDR_AFFLVL1_VAL(mpidr);
76
77 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
78
79 /* Prevent interrupts from spuriously waking up this cpu */
80 mt_gic_cpuif_disable();
81
82 spm_enable_cpu_auto_off(cluster, cpu);
83
84 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
85 if (cluster == 1)
86 mt_gic_sync_dcm_enable();
87
88 plat_mtk_cci_disable();
89 spm_enable_cluster_auto_off(cluster);
90 }
91
92 spm_set_cpu_power_off(cluster, cpu);
93}
94
95static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state)
96{
97 uint64_t mpidr = read_mpidr();
98 int cpu = MPIDR_AFFLVL0_VAL(mpidr);
99 int cluster = MPIDR_AFFLVL1_VAL(mpidr);
100
101 INFO("%s():%d: c.c: %d.%d\n", __func__, __LINE__, cluster, cpu);
102
103 assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF);
104
105 if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) {
106 enable_scu(mpidr);
107
108 /* Enable coherency if this cluster was off */
109 plat_mtk_cci_enable();
110 /* Enable big core dcm if this cluster was on */
111 plat_dcm_restore_cluster_on(mpidr);
112 /* Enable rgu dcm if this cluster was off */
113 plat_dcm_rgu_enable();
114 }
115
116 spm_disable_cpu_auto_off(cluster, cpu);
117
118 /* Enable the gic cpu interface */
119 mt_gic_pcpu_init();
120 mt_gic_cpuif_enable();
121}
122
kenny liang3fa9dec2019-04-10 21:09:26 +0800123/*******************************************************************************
kenny liange977b4d2019-05-02 20:02:05 +0800124 * MTK handlers to shutdown/reboot the system
125 ******************************************************************************/
126static void __dead2 plat_mtk_system_off(void)
127{
128 INFO("MTK System Off\n");
129
130 rtc_power_off_sequence();
131 wk_pmic_enable_sdn_delay();
132 pmic_power_off();
133
134 wfi();
135 ERROR("MTK System Off: operation not handled.\n");
136 panic();
137}
138
kenny liang3d91c9c2019-05-03 17:02:46 +0800139static void __dead2 plat_mtk_system_reset(void)
140{
141 struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
142
143 INFO("MTK System Reset\n");
144
145 mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity);
146
147 wfi();
148 ERROR("MTK System Reset: operation not handled.\n");
149 panic();
150}
151
kenny liang3c25ba42019-08-21 20:50:20 +0800152static void plat_mtk_power_domain_suspend(const psci_power_state_t *state)
153{
154 uint64_t mpidr = read_mpidr();
155 int cpu = MPIDR_AFFLVL0_VAL(mpidr);
156 int cluster = MPIDR_AFFLVL1_VAL(mpidr);
157
158 spm_system_suspend();
159
160 /* init cpu reset arch as AARCH64 */
161 mcucfg_init_archstate(cluster, cpu, 1);
162 mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
163 spm_set_bootaddr(secure_entrypoint);
164
165 /* Prevent interrupts from spuriously waking up this cpu */
166 mt_gic_cpuif_disable();
167 mt_gic_irq_save();
168
169 if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
170 plat_mtk_cci_disable();
171 disable_scu(mpidr);
172 }
173}
174
175static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state)
176{
177 uint64_t mpidr = read_mpidr();
178
179 mt_gic_init();
180 mt_gic_irq_restore();
181
182 if (state->pwr_domain_state[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF) {
183 enable_scu(mpidr);
184 plat_mtk_cci_enable();
185 plat_dcm_restore_cluster_on(mpidr);
186 }
187
188 mmio_write_32(EMI_WFIFO, 0xf);
189 spm_system_suspend_finish();
190}
191
192static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state)
193{
194 assert(PLAT_MAX_PWR_LVL >= 2);
195
196 for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++)
197 req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF;
198}
199
kenny liange977b4d2019-05-02 20:02:05 +0800200/*******************************************************************************
kenny liang3fa9dec2019-04-10 21:09:26 +0800201 * MTK_platform handler called when an affinity instance is about to be turned
202 * on. The level and mpidr determine the affinity instance.
203 ******************************************************************************/
kenny liang3fa9dec2019-04-10 21:09:26 +0800204static const plat_psci_ops_t plat_plat_pm_ops = {
205 .cpu_standby = NULL,
kenny liang7352f322019-05-02 19:29:25 +0800206 .pwr_domain_on = plat_mtk_power_domain_on,
207 .pwr_domain_on_finish = plat_mtk_power_domain_on_finish,
208 .pwr_domain_off = plat_mtk_power_domain_off,
kenny liang3c25ba42019-08-21 20:50:20 +0800209 .pwr_domain_suspend = plat_mtk_power_domain_suspend,
210 .pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish,
kenny liange977b4d2019-05-02 20:02:05 +0800211 .system_off = plat_mtk_system_off,
kenny liang3d91c9c2019-05-03 17:02:46 +0800212 .system_reset = plat_mtk_system_reset,
kenny liang3fa9dec2019-04-10 21:09:26 +0800213 .validate_power_state = NULL,
kenny liang3c25ba42019-08-21 20:50:20 +0800214 .get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state,
kenny liang3fa9dec2019-04-10 21:09:26 +0800215};
216
217int plat_setup_psci_ops(uintptr_t sec_entrypoint,
218 const plat_psci_ops_t **psci_ops)
219{
220 *psci_ops = &plat_plat_pm_ops;
221 secure_entrypoint = sec_entrypoint;
222 return 0;
223}