1*da54c724SKai Liang /*
2*da54c724SKai Liang * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3*da54c724SKai Liang *
4*da54c724SKai Liang * SPDX-License-Identifier: BSD-3-Clause
5*da54c724SKai Liang */
6*da54c724SKai Liang
7*da54c724SKai Liang #include <assert.h>
8*da54c724SKai Liang #include <stdint.h>
9*da54c724SKai Liang
10*da54c724SKai Liang #include <lib/spinlock.h>
11*da54c724SKai Liang #include <platform_def.h>
12*da54c724SKai Liang
13*da54c724SKai Liang #include "../inc/pwr_topology.h"
14*da54c724SKai Liang #include <lib/pm/mtk_pm.h>
15*da54c724SKai Liang #include <lpm/mt_lp_rm.h>
16*da54c724SKai Liang
17*da54c724SKai Liang #ifdef MT_CPU_PM_USING_BAKERY_LOCK
18*da54c724SKai Liang DEFINE_BAKERY_LOCK(mt_pwr_lock);
19*da54c724SKai Liang
20*da54c724SKai Liang #define plat_pwr_lock_init() bakery_lock_init(&mt_pwr_lock)
21*da54c724SKai Liang
22*da54c724SKai Liang #define plat_pwr_lock() bakery_lock_get(&mt_pwr_lock)
23*da54c724SKai Liang
24*da54c724SKai Liang #define plat_pwr_unlock() bakery_lock_release(&mt_pwr_lock)
25*da54c724SKai Liang #else
26*da54c724SKai Liang spinlock_t mt_pwr_lock;
27*da54c724SKai Liang
28*da54c724SKai Liang #define plat_pwr_lock_init()
29*da54c724SKai Liang #define plat_pwr_lock() spin_lock(&mt_pwr_lock)
30*da54c724SKai Liang
31*da54c724SKai Liang #define plat_pwr_unlock() spin_unlock(&mt_pwr_lock)
32*da54c724SKai Liang #endif
33*da54c724SKai Liang
34*da54c724SKai Liang enum mt_pwr_domain_node {
35*da54c724SKai Liang MT_PWR_NONMCUSYS = 0,
36*da54c724SKai Liang MT_PWR_MCUSYS_PDN,
37*da54c724SKai Liang MT_PWR_MAX
38*da54c724SKai Liang };
39*da54c724SKai Liang
40*da54c724SKai Liang #if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \
41*da54c724SKai Liang !CPU_PM_DOMAIN_CORE_ONLY
42*da54c724SKai Liang static int mt_pwr_domain_st[MT_PWR_MAX];
43*da54c724SKai Liang #endif
44*da54c724SKai Liang
45*da54c724SKai Liang #define ALL_IN_ONE_GROUP 0xFF
pwr_domain_coordination(enum pwr_domain_status pwr,const mtk_pstate_type psci_state,const struct mtk_cpupm_pwrstate * state,afflv_prepare fn)46*da54c724SKai Liang unsigned int pwr_domain_coordination(enum pwr_domain_status pwr,
47*da54c724SKai Liang const mtk_pstate_type psci_state,
48*da54c724SKai Liang const struct mtk_cpupm_pwrstate *state,
49*da54c724SKai Liang afflv_prepare fn)
50*da54c724SKai Liang {
51*da54c724SKai Liang unsigned int pstate = 0;
52*da54c724SKai Liang
53*da54c724SKai Liang #if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN && \
54*da54c724SKai Liang !CPU_PM_DOMAIN_CORE_ONLY
55*da54c724SKai Liang unsigned int is_flush = 0;
56*da54c724SKai Liang struct pwr_toplogy tp = {
57*da54c724SKai Liang .cur_group_bit = ALL_IN_ONE_GROUP,
58*da54c724SKai Liang .group = ALL_IN_ONE_GROUP,
59*da54c724SKai Liang };
60*da54c724SKai Liang
61*da54c724SKai Liang /* Skip to process smp */
62*da54c724SKai Liang if (pwr > PWR_DOMAIN_OFF)
63*da54c724SKai Liang return pstate;
64*da54c724SKai Liang
65*da54c724SKai Liang if (!IS_MT_PLAT_PWR_STATE_MCUSYS(state->pwr.state_id)) {
66*da54c724SKai Liang plat_pwr_lock();
67*da54c724SKai Liang if (pwr == PWR_DOMAIN_OFF)
68*da54c724SKai Liang mt_pwr_domain_st[MT_PWR_NONMCUSYS] += 1;
69*da54c724SKai Liang else
70*da54c724SKai Liang mt_pwr_domain_st[MT_PWR_NONMCUSYS] -= 1;
71*da54c724SKai Liang flush_dcache_range(
72*da54c724SKai Liang (uintptr_t)&mt_pwr_domain_st[MT_PWR_NONMCUSYS],
73*da54c724SKai Liang sizeof(mt_pwr_domain_st[MT_PWR_NONMCUSYS]));
74*da54c724SKai Liang plat_pwr_unlock();
75*da54c724SKai Liang }
76*da54c724SKai Liang
77*da54c724SKai Liang plat_pwr_lock();
78*da54c724SKai Liang if (state->pwr.afflv >= PLAT_MT_CPU_SUSPEND_CLUSTER)
79*da54c724SKai Liang pstate |= MT_CPUPM_PWR_DOMAIN_CLUSTER;
80*da54c724SKai Liang
81*da54c724SKai Liang if (psci_get_pstate_pwrlvl(psci_state) >= PLAT_MT_CPU_SUSPEND_CLUSTER)
82*da54c724SKai Liang pstate |= MT_CPUPM_PWR_DOMAIN_PERCORE_DSU;
83*da54c724SKai Liang
84*da54c724SKai Liang if (pwr == PWR_DOMAIN_OFF) {
85*da54c724SKai Liang if (IS_PLAT_MCUSYSOFF_AFFLV(state->pwr.afflv) &&
86*da54c724SKai Liang (mt_pwr_domain_st[MT_PWR_NONMCUSYS] == 0)) {
87*da54c724SKai Liang int ret = MTK_CPUPM_E_OK;
88*da54c724SKai Liang
89*da54c724SKai Liang tp.group = ALL_IN_ONE_GROUP;
90*da54c724SKai Liang if (fn)
91*da54c724SKai Liang ret = fn(1, state, &tp);
92*da54c724SKai Liang
93*da54c724SKai Liang if (ret == MTK_CPUPM_E_OK) {
94*da54c724SKai Liang pstate |= MT_CPUPM_PWR_DOMAIN_MCUSYS;
95*da54c724SKai Liang mt_pwr_domain_st[MT_PWR_MCUSYS_PDN] += 1;
96*da54c724SKai Liang is_flush = 1;
97*da54c724SKai Liang }
98*da54c724SKai Liang }
99*da54c724SKai Liang } else {
100*da54c724SKai Liang if (mt_pwr_domain_st[MT_PWR_MCUSYS_PDN]) {
101*da54c724SKai Liang tp.group = 0x0;
102*da54c724SKai Liang if (fn)
103*da54c724SKai Liang fn(1, state, &tp);
104*da54c724SKai Liang pstate |= MT_CPUPM_PWR_DOMAIN_MCUSYS;
105*da54c724SKai Liang mt_pwr_domain_st[MT_PWR_MCUSYS_PDN] -= 1;
106*da54c724SKai Liang is_flush = 1;
107*da54c724SKai Liang }
108*da54c724SKai Liang if (mt_pwr_domain_st[MT_PWR_NONMCUSYS] < 0)
109*da54c724SKai Liang assert(0);
110*da54c724SKai Liang }
111*da54c724SKai Liang
112*da54c724SKai Liang if (is_flush)
113*da54c724SKai Liang flush_dcache_range(
114*da54c724SKai Liang (uintptr_t)&mt_pwr_domain_st[MT_PWR_MCUSYS_PDN],
115*da54c724SKai Liang sizeof(mt_pwr_domain_st[MT_PWR_MCUSYS_PDN]));
116*da54c724SKai Liang
117*da54c724SKai Liang plat_pwr_unlock();
118*da54c724SKai Liang #endif
119*da54c724SKai Liang return pstate;
120*da54c724SKai Liang }
121*da54c724SKai Liang
pwr_topology_init(void)122*da54c724SKai Liang void pwr_topology_init(void)
123*da54c724SKai Liang {
124*da54c724SKai Liang plat_pwr_lock_init();
125*da54c724SKai Liang }
126