1 /*
2 * Copyright (c) 2025, MediaTek Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <stdint.h>
8 #include <lib/spinlock.h>
9
10 #include "mt_cpu_pm.h"
11 #include "mt_cpu_pm_cpc.h"
12 #include "mt_cpu_pm_smc.h"
13 #include "mt_lp_irqremain.h"
14
15 /*
16 * The locker must use the bakery locker when cache turn off.
17 * Using spin_lock will has better performance.
18 */
19 #ifdef MT_CPU_PM_USING_BAKERY_LOCK
20 DEFINE_BAKERY_LOCK(mt_cpu_pm_smc_lock);
21 #define plat_cpu_pm_smc_lock_init() bakery_lock_init(&mt_cpu_pm_smc_lock)
22 #define plat_cpu_pm_smc_lock() bakery_lock_get(&mt_cpu_pm_smc_lock)
23 #define plat_cpu_pm_smc_unlock() bakery_lock_release(&mt_cpu_pm_smc_lock)
24 #else
25 spinlock_t mt_cpu_pm_smc_lock;
26 #define plat_cpu_pm_smc_lock_init()
27 #define plat_cpu_pm_smc_lock() spin_lock(&mt_cpu_pm_smc_lock)
28 #define plat_cpu_pm_smc_unlock() spin_unlock(&mt_cpu_pm_smc_lock)
29 #endif /* MT_CPU_PM_USING_BAKERY_LOCK */
30
cpupm_dispatcher(u_register_t lp_id,u_register_t act,u_register_t arg1,u_register_t arg2,void * handle,struct smccc_res * smccc_ret)31 static uint64_t cpupm_dispatcher(u_register_t lp_id,
32 u_register_t act,
33 u_register_t arg1,
34 u_register_t arg2,
35 void *handle,
36 struct smccc_res *smccc_ret)
37 {
38 uint64_t res = 0;
39
40 switch (lp_id) {
41 case CPC_COMMAND:
42 res = mtk_cpc_handler(act, arg1, arg2);
43 break;
44 default:
45 break;
46 }
47
48 return res;
49 }
50
cpupm_lp_dispatcher(u_register_t lp_id,u_register_t act,u_register_t arg1,u_register_t arg2,void * handle,struct smccc_res * smccc_ret)51 static uint64_t cpupm_lp_dispatcher(u_register_t lp_id,
52 u_register_t act,
53 u_register_t arg1,
54 u_register_t arg2,
55 void *handle,
56 struct smccc_res *smccc_ret)
57 {
58 uint64_t res = 0;
59 #ifdef CPU_PM_IRQ_REMAIN_ENABLE
60 int ret;
61 #endif
62 switch (lp_id) {
63 case LP_CPC_COMMAND:
64 res = mtk_cpc_handler(act, arg1, arg2);
65 break;
66 #ifdef CPU_PM_IRQ_REMAIN_ENABLE
67 case IRQS_REMAIN_ALLOC:
68 if (act & MT_LPM_SMC_ACT_GET)
69 res = (uint64_t)mt_lp_irqremain_count();
70 break;
71 case IRQS_REMAIN_CTRL:
72 plat_cpu_pm_smc_lock();
73 if (act & MT_LPM_SMC_ACT_SUBMIT)
74 ret = mt_lp_irqremain_submit();
75 else if (act & MT_LPM_SMC_ACT_PUSH) {
76 ret = mt_lp_irqremain_push();
77 if (ret)
78 INFO("Irqs remain push fail\n");
79 } else
80 INFO("Irqs remain control not support! (0x%lx)\n", act);
81 plat_cpu_pm_smc_unlock();
82 break;
83 case IRQS_REMAIN_IRQ:
84 case IRQS_REMAIN_WAKEUP_CAT:
85 case IRQS_REMAIN_WAKEUP_SRC:
86 plat_cpu_pm_smc_lock();
87 if (act & MT_LPM_SMC_ACT_SET) {
88 const struct mt_lp_irqinfo info = {
89 .val = (unsigned int)arg1,
90 };
91
92 ret = mt_lp_irqremain_set((unsigned int)lp_id, &info);
93 if (ret)
94 INFO("Irqs remain command: %lu, set fail\n",
95 lp_id);
96 } else if (act & MT_LPM_SMC_ACT_GET) {
97 struct mt_lp_irqinfo info;
98
99 ret = mt_lp_irqremain_get((unsigned int)arg1,
100 (unsigned int)lp_id, &info);
101 if (ret) {
102 INFO("Irqs remain command: %lu, get fail\n",
103 lp_id);
104 res = 0;
105 } else
106 res = (uint64_t)info.val;
107 } else
108 INFO("Irqs remain command not support! (0x%lx)\n", act);
109 plat_cpu_pm_smc_unlock();
110 break;
111 #ifdef CPU_PM_SUSPEND_NOTIFY
112 case SUSPEND_SRC:
113 ret = cpupm_set_suspend_state((unsigned int)act,
114 (unsigned int)arg1);
115 if (ret)
116 INFO("cpu_pm lp command: %lu, set fail\n", lp_id);
117 break;
118 #endif
119 case CPU_PM_COUNTER_CTRL:
120 if (act & MT_LPM_SMC_ACT_SET)
121 mtk_cpu_pm_counter_enable((bool)arg1);
122 else if (act & MT_LPM_SMC_ACT_GET)
123 res = (uint64_t)mtk_cpu_pm_counter_enabled();
124 break;
125 case CPU_PM_RECORD_CTRL:
126 if (act & MT_LPM_SMC_ACT_GET) {
127 if (arg1 == 0)
128 res = mtk_mcusys_off_record_cnt_get();
129 else if (arg1 == 1)
130 res = mtk_mcusys_off_record_name_get();
131 }
132 break;
133 #if CONFIG_MTK_PM_SUPPORT && CONFIG_MTK_CPU_SUSPEND_EN
134 case SUSPEND_ABORT_REASON:
135 if (act & MT_LPM_SMC_ACT_GET)
136 res = mtk_suspend_abort_reason_get();
137 break;
138 #endif
139 #ifdef CONFIG_MTK_CPU_ILDO
140 case CPU_PM_RET_CTRL:
141 if (act & MT_LPM_SMC_ACT_SET)
142 res = cpupm_cpu_retention_control((unsigned int) arg1);
143 else if (act & MT_LPM_SMC_ACT_GET)
144 res = cpupu_get_cpu_retention_control();
145 else if (act & MT_LPM_SMC_ACT_COMPAT)
146 res = CPU_PM_CPU_RET_IS_ENABLED;
147 break;
148 #endif
149 #endif
150 default:
151 break;
152 }
153 return res;
154 }
155
secure_cpupm_dispatcher(u_register_t lp_id,u_register_t act,u_register_t arg1,u_register_t arg2,void * handle,struct smccc_res * smccc_ret)156 static uint64_t secure_cpupm_dispatcher(u_register_t lp_id,
157 u_register_t act,
158 u_register_t arg1,
159 u_register_t arg2,
160 void *handle,
161 struct smccc_res *smccc_ret)
162 {
163 uint64_t res = 0;
164
165 switch (lp_id) {
166 case CPC_COMMAND:
167 res = mtk_cpc_trace_dump(act, arg1, arg2);
168 break;
169 default:
170 break;
171 }
172
173 return res;
174 }
175
cpupm_smc_init(void)176 void cpupm_smc_init(void)
177 {
178 plat_cpu_pm_smc_lock_init();
179 mt_lpm_dispatcher_registry(MT_LPM_SMC_USER_CPU_PM,
180 cpupm_dispatcher);
181
182 mt_lpm_dispatcher_registry(MT_LPM_SMC_USER_CPU_PM_LP,
183 cpupm_lp_dispatcher);
184
185 mt_secure_lpm_dispatcher_registry(MT_LPM_SMC_USER_SECURE_CPU_PM,
186 secure_cpupm_dispatcher);
187 }
188