blob: fa24e2e0099968d4e1eaff5a4d35c2ad4480336b [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 liang7352f322019-05-02 19:29:25 +080020#include <mtspmc.h>
kenny liang3fa9dec2019-04-10 21:09:26 +080021#include <power_tracer.h>
kenny liang7352f322019-05-02 19:29:25 +080022#include <plat_dcm.h>
23#include <plat_debug.h>
kenny liang3fa9dec2019-04-10 21:09:26 +080024#include <plat_private.h>
25
kenny liang7352f322019-05-02 19:29:25 +080026#define MTK_LOCAL_STATE_OFF 2
27
28static uintptr_t secure_entrypoint;
29
30static void mp1_L2_desel_config(void)
31{
32 mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820);
33
34 dsb();
35}
36
37static 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
65static 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
89static 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
kenny liang3fa9dec2019-04-10 21:09:26 +0800117/*******************************************************************************
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 ******************************************************************************/
kenny liang3fa9dec2019-04-10 21:09:26 +0800121static const plat_psci_ops_t plat_plat_pm_ops = {
122 .cpu_standby = NULL,
kenny liang7352f322019-05-02 19:29:25 +0800123 .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,
kenny liang3fa9dec2019-04-10 21:09:26 +0800126 .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
134int 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}