blob: 0d8631d931ed74cf35953f779611ad66f23188df [file] [log] [blame]
xjb04a4022021-11-25 15:01:52 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 MediaTek Inc.
4 */
5
6#include <linux/sched.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/random.h>
10#include <linux/fs.h>
11
12#include "met_drv.h"
13#include "trace.h"
14#include "core_plf_init.h"
15#include "core_plf_trace.h"
16
17static unsigned int MT_GPU_DVFS_IDX = NR_MT_CPU_DVFS;
18static unsigned int g_u4GPUVolt;
19static unsigned int g_u4Volt[NR_MT_CPU_DVFS + 1];
20
21/* g_ap_ptpod: cpu volt from ap or sspm setting
22 * if 1: cpu volt from ap
23 * if 0: cpu volt from sspm */
24static unsigned int g_ap_ptpod;
25
26/* gpu_volt_enable:
27 * if 1: enable gpu volt to output
28 * if 0: disable gpu volt to output */
29static unsigned int gpu_volt_enable = 1;
30
31/* get_volt_by_wq:
32 * if 1: get cpu/gpu volt by workqueue
33 * if 0: get cpu/gpu volt in irq */
34static unsigned int get_volt_by_wq;
35
36static int ptpod_started;
37static struct kobject *kobj_ptpod;
38static struct delayed_work get_volt_dwork;
39
40noinline void ms_ptpod(void)
41{
42 char *SOB, *EOB;
43
44 if (g_ap_ptpod) {
45 MET_TRACE_GETBUF(&SOB, &EOB);
46
47 if (gpu_volt_enable) {
48 g_u4Volt[MT_GPU_DVFS_IDX] = g_u4GPUVolt;
49 EOB = ms_formatD_EOL(EOB, ARRAY_SIZE(g_u4Volt), g_u4Volt);
50 } else
51 EOB = ms_formatD_EOL(EOB, ARRAY_SIZE(g_u4Volt) - 1, g_u4Volt);
52
53 MET_TRACE_PUTBUF(SOB, EOB);
54 } else {
55 if (gpu_volt_enable) {
56 MET_TRACE_GETBUF(&SOB, &EOB);
57 EOB = ms_formatD_EOL(EOB, 1, &g_u4GPUVolt);
58 MET_TRACE_PUTBUF(SOB, EOB);
59 }
60 }
61}
62
63#if 0
64static void ptpod_cpu_voltSampler(enum mt_cpu_dvfs_id id, unsigned int volt)
65{
66 switch (id) {
67 case MT_CPU_DVFS_LL:
68 g_u4CPUVolt_LL = volt;
69 break;
70 case MT_CPU_DVFS_L:
71 g_u4CPUVolt_L = volt;
72 break;
73 case MT_CPU_DVFS_CCI:
74 g_u4CPUVolt_CCI = volt;
75 break;
76 default:
77 return;
78 }
79 ptpod();
80}
81#endif
82
83#if 0
84static void ptpod_gpu_voltSampler(unsigned int a_u4Volt)
85{
86 g_u4GPUVolt = (a_u4Volt+50)/100;
87
88 if (ptpod_started)
89 ptpod();
90}
91#endif
92
93#define PTPOD_CONF_SHOW_IMPLEMENT(var) \
94 do { \
95 int i; \
96 i = snprintf(buf, PAGE_SIZE, "%d\n", var); \
97 return i; \
98 } while (0)
99
100#define PTPOD_CONF_STORE_IMPLEMENT(var) \
101 do { \
102 int value; \
103 if ((n == 0) || (buf == NULL)) \
104 return -EINVAL; \
105 if (kstrtoint(buf, 0, &value) != 0) \
106 return -EINVAL; \
107 if (value == 1) \
108 var = 1; \
109 else \
110 var = 0; \
111 return n; \
112 } while (0)
113
114
115static ssize_t ap_ptpod_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
116{
117 PTPOD_CONF_SHOW_IMPLEMENT(g_ap_ptpod);
118}
119
120static ssize_t ap_ptpod_enable_store(struct kobject *kobj,
121 struct kobj_attribute *attr,
122 const char *buf,
123 size_t n)
124{
125 PTPOD_CONF_STORE_IMPLEMENT(g_ap_ptpod);
126}
127
128static ssize_t gpu_volt_enable_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
129{
130 PTPOD_CONF_SHOW_IMPLEMENT(gpu_volt_enable);
131}
132
133static ssize_t gpu_volt_enable_store(struct kobject *kobj,
134 struct kobj_attribute *attr,
135 const char *buf,
136 size_t n)
137{
138 PTPOD_CONF_STORE_IMPLEMENT(gpu_volt_enable);
139}
140
141static ssize_t get_volt_by_wq_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
142{
143 PTPOD_CONF_SHOW_IMPLEMENT(get_volt_by_wq);
144}
145
146static ssize_t get_volt_by_wq_store(struct kobject *kobj,
147 struct kobj_attribute *attr,
148 const char *buf,
149 size_t n)
150{
151 PTPOD_CONF_STORE_IMPLEMENT(get_volt_by_wq);
152}
153
154static struct kobj_attribute ap_ptpod_enable_attr = __ATTR(ap_ptpod_enable, 0664, ap_ptpod_enable_show, ap_ptpod_enable_store);
155static struct kobj_attribute gpu_volt_enable_attr = __ATTR(gpu_volt_enable, 0664, gpu_volt_enable_show, gpu_volt_enable_store);
156static struct kobj_attribute get_volt_by_wq_attr = __ATTR(get_volt_by_wq, 0664, get_volt_by_wq_show, get_volt_by_wq_store);
157
158/* create ptpod related kobj node */
159#define KOBJ_ATTR_LIST \
160 do { \
161 KOBJ_ATTR_ITEM(ap_ptpod_enable); \
162 KOBJ_ATTR_ITEM(gpu_volt_enable); \
163 KOBJ_ATTR_ITEM(get_volt_by_wq); \
164 } while (0)
165
166static int ptpod_create(struct kobject *parent)
167{
168 int ret = 0;
169
170 kobj_ptpod = parent;
171
172#define KOBJ_ATTR_ITEM(attr_name) \
173 do { \
174 ret = sysfs_create_file(kobj_ptpod, &attr_name ## _attr.attr); \
175 if (ret != 0) { \
176 pr_notice("Failed to create " #attr_name " in sysfs\n"); \
177 return ret; \
178 } \
179 } while (0)
180 KOBJ_ATTR_LIST;
181#undef KOBJ_ATTR_ITEM
182
183 return 0;
184}
185
186static void ptpod_delete(void)
187{
188#define KOBJ_ATTR_ITEM(attr_name) \
189 sysfs_remove_file(kobj_ptpod, &attr_name ## _attr.attr)
190
191 if (kobj_ptpod != NULL) {
192 KOBJ_ATTR_LIST;
193 kobj_ptpod = NULL;
194 }
195#undef KOBJ_ATTR_ITEM
196}
197
198static void update_volt_value(void)
199{
200 int i;
201
202 if (g_ap_ptpod && mt_cpufreq_get_cur_volt_symbol) {
203 /*
204 g_u4CPUVolt_LL = mt_cpufreq_get_cur_volt_symbol(MT_CPU_DVFS_LL)/100;
205 g_u4CPUVolt_L = mt_cpufreq_get_cur_volt_symbol(MT_CPU_DVFS_L)/100;
206 g_u4CPUVolt_CCI = mt_cpufreq_get_cur_volt_symbol(MT_CPU_DVFS_CCI)/100;
207 */
208 for (i = 0; i < NR_MT_CPU_DVFS; i++)
209 g_u4Volt[i] = mt_cpufreq_get_cur_volt_symbol(i) / 100;
210 }
211
212 if (gpu_volt_enable) {
213 if (mt_gpufreq_get_cur_volt_symbol)
214 g_u4GPUVolt = ((mt_gpufreq_get_cur_volt_symbol() + 50) / 100);
215 }
216}
217
218static void get_volt_notify(unsigned long long stamp, int cpu)
219{
220 schedule_delayed_work(&get_volt_dwork, 0);
221}
222
223static void met_ptpod_polling_by_wq(struct work_struct *work)
224{
225 update_volt_value();
226
227 ms_ptpod();
228}
229
230static void met_ptpod_polling(unsigned long long stamp, int cpu)
231{
232 update_volt_value();
233
234 ms_ptpod();
235}
236
237/*
238 * Called from "met-cmd --start"
239 */
240static void ptpod_start(void)
241{
242#if 0
243 met_gpufreq_setvolt_registerCB(ptpod_gpu_voltSampler, kFOR_MET_PTPOD_USE);
244#endif
245
246 if (get_volt_by_wq) {
247 met_ptpod.timed_polling = get_volt_notify;
248
249 INIT_DELAYED_WORK(&get_volt_dwork, met_ptpod_polling_by_wq);
250 } else
251 met_ptpod.timed_polling = met_ptpod_polling;
252
253 update_volt_value();
254
255 ms_ptpod();
256
257#if 0
258 /* register callback */
259 if (mt_cpufreq_setvolt_registerCB_symbol)
260 mt_cpufreq_setvolt_registerCB_symbol(ptpod_cpu_voltSampler);
261#endif
262
263 ptpod_started = 1;
264}
265
266/*
267 * Called from "met-cmd --stop"
268 */
269static void ptpod_stop(void)
270{
271 ptpod_started = 0;
272
273#if 0
274 /* unregister callback */
275 if (mt_cpufreq_setvolt_registerCB_symbol)
276 mt_cpufreq_setvolt_registerCB_symbol(NULL);
277#endif
278
279 if (get_volt_by_wq)
280 cancel_delayed_work_sync(&get_volt_dwork);
281
282 update_volt_value();
283
284 ms_ptpod();
285
286#if 0
287 met_gpufreq_setvolt_registerCB(NULL, kFOR_MET_PTPOD_USE);
288#endif
289}
290
291static char help[] =
292 " --ptpod Measure CPU/GPU voltage\n";
293static int ptpod_print_help(char *buf, int len)
294{
295 return snprintf(buf, PAGE_SIZE, help);
296}
297
298/*
299 * It will be called back when run "met-cmd --extract" and mode is 1
300 */
301static int ptpod_print_header(char *buf, int len)
302{
303 int str_len = 0;
304
305 if (g_ap_ptpod) {
306 int i;
307
308 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
309 "met-info [000] 0.0: met_ptpod_header: ");
310
311 for (i = 0; i < NR_MT_CPU_DVFS; i++)
312 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "CPUVolt_%d,", i);
313
314 if (gpu_volt_enable)
315 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "GPUVolt,");
316
317 buf[str_len-1] = '\n';
318
319 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
320 "met-info [000] 0.0: met_ptpod_version: ap\n");
321 } else {
322 if (gpu_volt_enable) {
323 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
324 "met-info [000] 0.0: met_ptpod_header: ");
325
326 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len, "GPUVolt\n");
327 }
328
329 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
330 "met-info [000] 0.0: met_ptpod_version: sspm\n");
331 }
332
333 if (gpu_volt_enable)
334 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
335 "met-info [000] 0.0: met_ptpod_gpu_volt_enable: YES\n");
336 else
337 str_len += snprintf(buf + str_len, PAGE_SIZE - str_len,
338 "met-info [000] 0.0: met_ptpod_gpu_volt_enable: NO\n");
339
340 return str_len;
341}
342
343struct metdevice met_ptpod = {
344 .name = "ptpod",
345 .owner = THIS_MODULE,
346 .type = MET_TYPE_PMU,
347 .cpu_related = 0,
348 .create_subfs = ptpod_create,
349 .delete_subfs = ptpod_delete,
350 .start = ptpod_start,
351 .stop = ptpod_stop,
352 .timed_polling = met_ptpod_polling,
353 .print_help = ptpod_print_help,
354 .print_header = ptpod_print_header,
355};
356EXPORT_SYMBOL(met_ptpod);