xref: /rk3399_ARM-atf/plat/mediatek/drivers/cpu_pm/cpcv5_4/mt_cpu_pm_smc.c (revision cf2df874cd09305ac7282fadb0fef6be597dfffb)
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