pass-hal: tm2: Add implementation of HAL for CPU
[platform/adaptation/tm2/pass-hal-tm2.git] / src / cpu / cpu.c
1 #include <errno.h>
2 #include <limits.h>
3 #include <pass/hal.h>
4 #include <pass/hal-log.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "../shared/sysfs.h"
10
11 /* TODO: Version! */
12 #define HAL_VERSION     MAKE_2B_CODE_4(VER_MAJOR,VER_MINOR,VER_REVISION,VER_RELEASE)
13 #define DEV_VERSION_CPU MAKE_2B_CODE_2(1,0)
14
15 #define CPUFREQ_PATH_PREFIX                     "/sys/devices/system/cpu/"
16 #define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX       "/cpufreq/scaling_governor"
17 #define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX      "/cpufreq/scaling_available_governors"
18
19 /*
20  * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
21  * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
22  */
23 #define CPUFREQ_CURR_FREQ_PATH_SUFFIX           "/cpufreq/cpuinfo_cur_freq"
24 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX            "/cpufreq/scaling_min_freq"
25 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX            "/cpufreq/scaling_max_freq"
26 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX        "/cpufreq/ondemand/up_threshold"
27
28 #define LOADTABLE_PATH_PREFIX                   "/sys/kernel/debug/cpufreq/"
29 #define LOADTABLE_PATH_SUFFIX                   "/load_table"
30
31 #define CPU_ONLINE_PATH_PREFIX                  "/sys/devices/system/cpu/cpu"
32 #define CPU_ONLINE_PATH_SUFFIX                  "/online"
33 #define CPU_ONLINE_STATE_ON                     1
34 #define CPU_ONLINE_STATE_OFF                    0
35
36 #define TMU_PATH_PREFIX                         "/sys/class/thermal/thermal_zone"
37 #define TMU_TEMP_PATH_SUFFIX                    "/temp"
38 #define TMU_POLICY_PATH_SUFFIX                  "/policy"
39
40 #define TM2_CPU_MIN_NUM                         0
41 #define TM2_CPU_MAX_NUM                         7
42
43 #define TM2_CPU_LITTLE_RESNAME                  "cpu0"
44 #define TM2_CPU_BIG_RESNAME                     "cpu4"
45 #define TM2_CPU_LITTLE_THERMAL_ZONE_NUM         3
46 #define TM2_CPU_BIG_THERMAL_ZONE_NUM            0
47
48
49 static int tm2_dvfs_get_curr_governor(char *res_name, char *governor)
50 {
51         char path[PATH_MAX];
52         int ret;
53
54         if ((!res_name) || (!governor))
55                 return -EINVAL;
56
57         snprintf(path, PATH_MAX, "%s%s%s",
58                 CPUFREQ_PATH_PREFIX,
59                 res_name,
60                 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
61
62         ret = sysfs_read_str(path, governor, BUFF_MAX);
63         if (ret < 0)
64                 return ret;
65
66         return 0;
67 }
68
69 static int tm2_dvfs_set_curr_governor(char *res_name, char *governor)
70 {
71         char path[PATH_MAX];
72         int ret;
73
74         if ((!res_name) || (!governor))
75                 return -EINVAL;
76
77         snprintf(path, PATH_MAX, "%s%s%s",
78                 CPUFREQ_PATH_PREFIX,
79                 res_name,
80                 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
81
82         ret = sysfs_write_str(path, governor);
83         if (ret < 0)
84                 return ret;
85
86         return 0;
87 }
88
89 static int tm2_dvfs_get_curr_freq(char *res_name)
90 {
91         char path[PATH_MAX];
92         int freq, ret;
93
94         if (!res_name)
95                 return -EINVAL;
96
97         snprintf(path, PATH_MAX, "%s%s%s",
98                 CPUFREQ_PATH_PREFIX,
99                 res_name,
100                 CPUFREQ_CURR_FREQ_PATH_SUFFIX);
101
102         ret = sysfs_read_int(path, &freq);
103         if (ret < 0)
104                 return ret;
105
106         return freq;
107 }
108
109 static int tm2_dvfs_get_min_freq(char *res_name)
110 {
111         char path[PATH_MAX];
112         int freq, ret;
113
114         if (!res_name)
115                 return -EINVAL;
116
117         snprintf(path, PATH_MAX, "%s%s%s",
118                 CPUFREQ_PATH_PREFIX,
119                 res_name,
120                 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
121
122         ret = sysfs_read_int(path, &freq);
123         if (ret < 0)
124                 return ret;
125
126         return freq;
127 }
128
129 static int tm2_dvfs_set_min_freq(char *res_name, int freq)
130 {
131         char path[PATH_MAX];
132         int ret;
133
134         if ((!res_name) || (freq < 0))
135                 return -EINVAL;
136
137         snprintf(path, PATH_MAX, "%s%s%s",
138                 CPUFREQ_PATH_PREFIX,
139                 res_name,
140                 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
141
142         ret = sysfs_write_int(path, freq);
143         if (ret < 0)
144                 return ret;
145
146         return 0;
147 }
148
149 static int tm2_dvfs_get_max_freq(char *res_name)
150 {
151         char path[PATH_MAX];
152         int freq, ret;
153
154         if (!res_name)
155                 return -EINVAL;
156
157         snprintf(path, PATH_MAX, "%s%s%s",
158                 CPUFREQ_PATH_PREFIX,
159                 res_name,
160                 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
161
162         ret = sysfs_read_int(path, &freq);
163         if (ret < 0)
164                 return ret;
165
166         return freq;
167 }
168
169 static int tm2_dvfs_set_max_freq(char *res_name, int freq)
170 {
171         char path[PATH_MAX];
172         int ret;
173
174         if ((!res_name) || (freq < 0))
175                 return -EINVAL;
176
177         snprintf(path, PATH_MAX, "%s%s%s",
178                 CPUFREQ_PATH_PREFIX,
179                 res_name,
180                 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
181
182         ret = sysfs_write_int(path, freq);
183         if (ret < 0)
184                 return ret;
185         return 0;
186 }
187
188 static int tm2_dvfs_get_up_threshold(char *res_name)
189 {
190         char path[PATH_MAX];
191         int val, ret;
192
193         if (!res_name)
194                 return -EINVAL;
195
196         snprintf(path, PATH_MAX, "%s%s%s",
197                 CPUFREQ_PATH_PREFIX,
198                 res_name,
199                 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
200
201         ret = sysfs_read_int(path, &val);
202         if (ret < 0)
203                 return ret;
204
205         return val;
206 }
207
208 static int tm2_dvfs_set_up_threshold(char *res_name, int up_threshold)
209 {
210         char path[PATH_MAX];
211         int ret;
212
213         if ((!res_name) || (up_threshold < 0))
214                 return -EINVAL;
215
216         snprintf(path, PATH_MAX, "%s%s%s",
217                 CPUFREQ_PATH_PREFIX,
218                 res_name,
219                 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
220
221         ret = sysfs_write_int(path, up_threshold);
222         if (ret < 0)
223                 return ret;
224
225         return 0;
226 }
227
228 static int tm2_dvfs_get_load_table(char *res_name, void *pass_cpu_load_table)
229 {
230         return 0;
231 }
232
233 static struct pass_resource_dvfs_ops tm2_cpu_dvfs_ops =  {
234         .get_curr_governor = tm2_dvfs_get_curr_governor,
235         .set_curr_governor = tm2_dvfs_set_curr_governor,
236         .get_avail_governor = NULL,
237         .get_curr_freq = tm2_dvfs_get_curr_freq,
238         .get_min_freq = tm2_dvfs_get_min_freq,
239         .set_min_freq = tm2_dvfs_set_min_freq,
240         .get_max_freq = tm2_dvfs_get_max_freq,
241         .set_max_freq = tm2_dvfs_set_max_freq,
242         .get_up_threshold = tm2_dvfs_get_up_threshold,
243         .set_up_threshold = tm2_dvfs_set_up_threshold,
244         .get_load_table = tm2_dvfs_get_load_table,
245 };
246
247 static int tm2_hotplug_get_online_state(char *res_name, int cpu)
248 {
249         char path[PATH_MAX];
250         int ret, online;
251
252         if ((!res_name))
253                 return -EINVAL;
254         if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
255                 return -EINVAL;
256
257         snprintf(path, PATH_MAX, "%s%d%s",
258                 CPU_ONLINE_PATH_PREFIX,
259                 cpu,
260                 CPU_ONLINE_PATH_SUFFIX);
261
262         ret = sysfs_read_int(path, &online);
263         if (ret < 0)
264                 return ret;
265
266         return online;
267 }
268
269 static int tm2_hotplug_set_online_state(char *res_name, int cpu, int on)
270 {
271         char path[PATH_MAX];
272         int ret;
273
274
275         if ((!res_name))
276                 return -EINVAL;
277         if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
278                 return -EINVAL;
279         if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
280                 return -EINVAL;
281
282         /* TODO: Can we turn off CPU0? */
283
284         snprintf(path, PATH_MAX, "%s%d%s",
285                 CPU_ONLINE_PATH_PREFIX,
286                 cpu,
287                 CPU_ONLINE_PATH_SUFFIX);
288
289         ret = sysfs_write_int(path, on);
290         if (ret < 0)
291                 return ret;
292
293         return 0;
294 }
295
296 static struct pass_resource_hotplug_ops tm2_cpu_hotplus_ops = {
297         .get_online_state = tm2_hotplug_get_online_state,
298         .set_online_state = tm2_hotplug_set_online_state,
299 };
300
301 static int tm2_tmu_get_temp(char *res_name)
302 {
303         char path[PATH_MAX];
304         int tz_num, temp;
305         int ret;
306
307         if (!res_name)
308                 return -EINVAL;
309
310         if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
311                 tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
312         else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
313                 tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
314         else
315                 return -EINVAL;
316
317         snprintf(path, PATH_MAX, "%s%d%s",
318                 TMU_PATH_PREFIX,
319                 tz_num,
320                 TMU_TEMP_PATH_SUFFIX);
321
322         ret = sysfs_read_int(path, &temp);
323         if (ret < 0)
324                 return ret;
325
326         return temp;
327 }
328
329 static int tm2_tmu_get_policy(char *res_name, char *policy)
330 {
331         char path[PATH_MAX];
332         int ret, tz_num;
333
334         if ((!res_name) || (!policy))
335                 return -EINVAL;
336
337         if (!strcmp(res_name, TM2_CPU_LITTLE_RESNAME))
338                 tz_num = TM2_CPU_LITTLE_THERMAL_ZONE_NUM;
339         else if (!strcmp(res_name, TM2_CPU_BIG_RESNAME))
340                 tz_num = TM2_CPU_BIG_THERMAL_ZONE_NUM;
341         else
342                 return -EINVAL;
343
344         snprintf(path, PATH_MAX, "%s%d%s",
345                 TMU_PATH_PREFIX,
346                 tz_num,
347                 TMU_POLICY_PATH_SUFFIX);
348
349         ret = sysfs_read_str(path, policy, BUFF_MAX);
350         if (ret < 0)
351                 return ret;
352
353         return 0;
354 }
355
356 static struct pass_resource_tmu_ops tm2_cpu_tmu_ops = {
357         .get_temp = tm2_tmu_get_temp,
358         .get_policy = tm2_tmu_get_policy,
359 };
360
361 static int tm2_cpu_open(struct pass_resource_info *info,
362                 struct pass_resource_common **common)
363 {
364         struct pass_resource_cpu *cpu_res;
365
366         if (!info)
367                 return -EINVAL;
368
369         /* TODO: Possibility of a memory leak */
370         cpu_res = calloc(1, sizeof(struct pass_resource_cpu));
371         if (!cpu_res)
372                 return -ENOMEM;
373
374         cpu_res->common.info = info;
375         cpu_res->dvfs = tm2_cpu_dvfs_ops;
376         cpu_res->hotplug = tm2_cpu_hotplus_ops;
377         cpu_res->tmu = tm2_cpu_tmu_ops;
378
379         *common = (struct pass_resource_common *) cpu_res;
380
381         return 0;
382 }
383
384 static int tm2_cpu_close(struct pass_resource_common *common)
385 {
386         if (!common)
387                 return -EINVAL;
388
389         free(common);
390
391         return 0;
392 }
393
394 HAL_MODULE_STRUCTURE = {
395         .magic = HAL_INFO_TAG,
396         .hal_version = HAL_VERSION,
397         .device_version = DEV_VERSION_CPU,
398         .id = PASS_RESOURCE_CPU_ID,
399         .name = PASS_RESOURCE_CPU_NAME,
400         .author = "Wook Song <wook16.song@samsung.com>",
401         .open = tm2_cpu_open,
402         .close = tm2_cpu_close,
403 };