2 * PASS (Power Aware System Service)
4 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 #include <pass/hal-log.h>
26 #include "../shared/sysfs.h"
29 #define HAL_VERSION MAKE_2B_CODE_4(VER_MAJOR,VER_MINOR,VER_REVISION,VER_RELEASE)
30 #define DEV_VERSION_CPU MAKE_2B_CODE_2(1,0)
32 #define CPUFREQ_PATH_PREFIX "/sys/devices/system/cpu/"
33 #define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_governor"
34 #define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_available_governors"
37 * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
38 * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
40 #define CPUFREQ_CURR_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_cur_freq"
41 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq"
42 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq"
43 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold"
45 #define LOADTABLE_PATH_PREFIX "/sys/kernel/debug/cpufreq/"
46 #define LOADTABLE_PATH_SUFFIX "/load_table"
48 #define CPU_ONLINE_PATH_PREFIX "/sys/devices/system/cpu/cpu"
49 #define CPU_ONLINE_PATH_SUFFIX "/online"
50 #define CPU_ONLINE_STATE_ON 1
51 #define CPU_ONLINE_STATE_OFF 0
53 #define TMU_PATH_PREFIX "/sys/class/thermal/"
54 #define TMU_TEMP_PATH_SUFFIX "/temp"
55 #define TMU_POLICY_PATH_SUFFIX "/policy"
57 #define TM2_CPU_MIN_NUM 0
58 #define TM2_CPU_MAX_NUM 7
60 static int tm2_dvfs_get_curr_governor(char *res_name, char *governor)
65 if ((!res_name) || (!governor))
68 snprintf(path, PATH_MAX, "%s%s%s",
71 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
73 ret = sysfs_read_str(path, governor, BUFF_MAX);
80 static int tm2_dvfs_set_curr_governor(char *res_name, char *governor)
85 if ((!res_name) || (!governor))
88 snprintf(path, PATH_MAX, "%s%s%s",
91 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
93 ret = sysfs_write_str(path, governor);
100 static int tm2_dvfs_get_curr_freq(char *res_name)
108 snprintf(path, PATH_MAX, "%s%s%s",
111 CPUFREQ_CURR_FREQ_PATH_SUFFIX);
113 ret = sysfs_read_int(path, &freq);
120 static int tm2_dvfs_get_min_freq(char *res_name)
128 snprintf(path, PATH_MAX, "%s%s%s",
131 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
133 ret = sysfs_read_int(path, &freq);
140 static int tm2_dvfs_set_min_freq(char *res_name, int freq)
145 if ((!res_name) || (freq < 0))
148 snprintf(path, PATH_MAX, "%s%s%s",
151 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
153 ret = sysfs_write_int(path, freq);
160 static int tm2_dvfs_get_max_freq(char *res_name)
168 snprintf(path, PATH_MAX, "%s%s%s",
171 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
173 ret = sysfs_read_int(path, &freq);
180 static int tm2_dvfs_set_max_freq(char *res_name, int freq)
185 if ((!res_name) || (freq < 0))
188 snprintf(path, PATH_MAX, "%s%s%s",
191 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
193 ret = sysfs_write_int(path, freq);
199 static int tm2_dvfs_get_up_threshold(char *res_name)
207 snprintf(path, PATH_MAX, "%s%s%s",
210 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
212 ret = sysfs_read_int(path, &val);
219 static int tm2_dvfs_set_up_threshold(char *res_name, int up_threshold)
224 if ((!res_name) || (up_threshold < 0))
227 snprintf(path, PATH_MAX, "%s%s%s",
230 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
232 ret = sysfs_write_int(path, up_threshold);
239 static int tm2_dvfs_get_load_table(char *res_name, void *pass_cpu_load_table)
244 static struct pass_resource_dvfs_ops tm2_cpu_dvfs_ops = {
245 .get_curr_governor = tm2_dvfs_get_curr_governor,
246 .set_curr_governor = tm2_dvfs_set_curr_governor,
247 .get_avail_governor = NULL,
248 .get_curr_freq = tm2_dvfs_get_curr_freq,
249 .get_min_freq = tm2_dvfs_get_min_freq,
250 .set_min_freq = tm2_dvfs_set_min_freq,
251 .get_max_freq = tm2_dvfs_get_max_freq,
252 .set_max_freq = tm2_dvfs_set_max_freq,
253 .get_up_threshold = tm2_dvfs_get_up_threshold,
254 .set_up_threshold = tm2_dvfs_set_up_threshold,
255 .get_load_table = tm2_dvfs_get_load_table,
258 static int tm2_hotplug_get_online_state(char *res_name, int cpu)
265 if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
268 snprintf(path, PATH_MAX, "%s%d%s",
269 CPU_ONLINE_PATH_PREFIX,
271 CPU_ONLINE_PATH_SUFFIX);
273 ret = sysfs_read_int(path, &online);
280 static int tm2_hotplug_set_online_state(char *res_name, int cpu, int on)
287 if ((cpu < TM2_CPU_MIN_NUM) || (cpu > TM2_CPU_MAX_NUM))
289 if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
293 * NOTE: Exynos SoC series cannot turn off the CPU0
294 * because of h/w design. To prevent the critical problem,
295 * if someone try to turn off the CPU0, just return without any
298 if (on == 0 && cpu == 0) {
299 _E("cannot turn off the CPU0");
303 snprintf(path, PATH_MAX, "%s%d%s",
304 CPU_ONLINE_PATH_PREFIX,
306 CPU_ONLINE_PATH_SUFFIX);
308 ret = sysfs_write_int(path, on);
315 static struct pass_resource_hotplug_ops tm2_cpu_hotplus_ops = {
316 .get_online_state = tm2_hotplug_get_online_state,
317 .set_online_state = tm2_hotplug_set_online_state,
318 .get_online_min_num = NULL,
319 .set_online_min_num = NULL,
320 .get_online_max_num = NULL,
321 .set_online_max_num = NULL,
324 static int tm2_tmu_get_temp(char *res_thermal_name)
329 if (!res_thermal_name)
332 snprintf(path, PATH_MAX, "%s%s%s",
335 TMU_TEMP_PATH_SUFFIX);
337 ret = sysfs_read_int(path, &temp);
344 static int tm2_tmu_get_policy(char *res_thermal_name, char *policy)
349 if ((!res_thermal_name) || (!policy))
352 snprintf(path, PATH_MAX, "%s%s%s",
355 TMU_POLICY_PATH_SUFFIX);
357 ret = sysfs_read_str(path, policy, BUFF_MAX);
364 static struct pass_resource_tmu_ops tm2_cpu_tmu_ops = {
365 .get_temp = tm2_tmu_get_temp,
366 .get_policy = tm2_tmu_get_policy,
369 static int tm2_cpu_open(char *res_name, struct pass_resource_info *info,
370 struct pass_resource_common **common)
372 struct pass_resource_cpu *cpu_res;
377 /* TODO: Possibility of a memory leak */
378 cpu_res = calloc(1, sizeof(struct pass_resource_cpu));
382 cpu_res->common.info = info;
383 cpu_res->dvfs = tm2_cpu_dvfs_ops;
384 cpu_res->hotplug = tm2_cpu_hotplus_ops;
385 cpu_res->tmu = tm2_cpu_tmu_ops;
387 *common = (struct pass_resource_common *) cpu_res;
392 static int tm2_cpu_close(char *res_name, struct pass_resource_common *common)
402 HAL_MODULE_STRUCTURE = {
403 .magic = HAL_INFO_TAG,
404 .hal_version = HAL_VERSION,
405 .device_version = DEV_VERSION_CPU,
406 .id = PASS_RESOURCE_CPU_ID,
407 .name = PASS_RESOURCE_CPU_NAME,
408 .open = tm2_cpu_open,
409 .close = tm2_cpu_close,