2 * HAL backend for hal-api-power which is used for PASS daemon
4 * Copyright (c) 2021 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.
25 #include <hal/hal-power-interface.h>
31 /*************************
32 * H/W Resource Defintions
34 #define CPUFREQ_PATH_PREFIX "/sys/devices/system/cpu/"
35 #define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_governor"
36 #define CPUFREQ_AVAIL_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_available_governors"
39 * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
40 * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
42 #define CPUFREQ_CURR_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_cur_freq"
43 #define CPUFREQ_AVAILABLE_MIN_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_min_freq"
44 #define CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_max_freq"
45 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq"
46 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq"
47 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold"
49 #define CPU_ONLINE_PATH_PREFIX "/sys/devices/system/cpu/cpu"
50 #define CPU_ONLINE_PATH_SUFFIX "/online"
51 #define CPU_ONLINE_STATE_ON 1
52 #define CPU_ONLINE_STATE_OFF 0
54 #define TMU_PATH_PREFIX "/sys/class/thermal/"
55 #define TMU_TEMP_PATH_SUFFIX "/temp"
56 #define TMU_POLICY_PATH_SUFFIX "/policy"
57 #define TMU_MAX_TEMP_MASK 0xFFFFF
59 #define DEVFREQ_BUS_PATH_PREFIX "/sys/class/devfreq/"
60 #define DEVFREQ_BUS_CURR_GOVERNOR_PATH_SUFFIX "/governor"
61 #define DEVFREQ_BUS_CURR_FREQ_PATH_SUFFIX "/cur_freq"
62 #define DEVFREQ_BUS_MIN_FREQ_PATH_SUFFIX "/min_freq"
63 #define DEVFREQ_BUS_MAX_FREQ_PATH_SUFFIX "/max_freq"
64 #define DEVFREQ_BUS_AVAILABLE_FREQ_PATH_SUFFIX "/available_frequencies"
66 #define FAULT_AROUND_BYTES_PATH "/sys/kernel/debug/fault_around_bytes"
68 /*************************************************
69 * HAL backend implementation for CPU H/W Resource
71 static int cpufreq_dvfs_get_curr_governor(char *res_name, char *governor)
76 if ((!res_name) || (!governor))
79 snprintf(path, PATH_MAX, "%s%s%s",
82 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
84 ret = sysfs_read_str(path, governor, BUFF_MAX);
91 static int cpufreq_dvfs_set_curr_governor(char *res_name, char *governor)
96 if ((!res_name) || (!governor))
99 snprintf(path, PATH_MAX, "%s%s%s",
102 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX);
104 ret = sysfs_write_str(path, governor);
111 static int cpufreq_dvfs_get_curr_freq(char *res_name)
119 snprintf(path, PATH_MAX, "%s%s%s",
122 CPUFREQ_CURR_FREQ_PATH_SUFFIX);
124 ret = sysfs_read_int(path, &freq);
131 static int cpufreq_dvfs_get_min_freq(char *res_name)
139 snprintf(path, PATH_MAX, "%s%s%s",
142 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
144 ret = sysfs_read_int(path, &freq);
151 static int cpufreq_dvfs_set_min_freq(char *res_name, int freq)
156 if ((!res_name) || (freq < 0))
159 snprintf(path, PATH_MAX, "%s%s%s",
162 CPUFREQ_MIN_FREQ_PATH_SUFFIX);
164 ret = sysfs_write_int(path, freq);
171 static int cpufreq_dvfs_get_max_freq(char *res_name)
179 snprintf(path, PATH_MAX, "%s%s%s",
182 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
184 ret = sysfs_read_int(path, &freq);
191 static int cpufreq_dvfs_set_max_freq(char *res_name, int freq)
196 if ((!res_name) || (freq < 0))
199 snprintf(path, PATH_MAX, "%s%s%s",
202 CPUFREQ_MAX_FREQ_PATH_SUFFIX);
204 ret = sysfs_write_int(path, freq);
210 static int cpufreq_dvfs_get_available_min_freq(char *res_name)
218 snprintf(path, PATH_MAX, "%s%s%s",
221 CPUFREQ_AVAILABLE_MIN_FREQ_PATH_SUFFIX);
223 ret = sysfs_read_int(path, &val);
231 static int cpufreq_dvfs_get_available_max_freq(char *res_name)
239 snprintf(path, PATH_MAX, "%s%s%s",
242 CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX);
244 ret = sysfs_read_int(path, &val);
251 static int cpufreq_dvfs_get_up_threshold(char *res_name)
259 snprintf(path, PATH_MAX, "%s%s%s",
262 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
264 ret = sysfs_read_int(path, &val);
271 static int cpufreq_dvfs_set_up_threshold(char *res_name, int up_threshold)
276 if ((!res_name) || (up_threshold < 0))
279 snprintf(path, PATH_MAX, "%s%s%s",
282 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX);
284 ret = sysfs_write_int(path, up_threshold);
291 static struct pass_resource_dvfs_ops cpufreq_dvfs_ops = {
292 .get_curr_governor = cpufreq_dvfs_get_curr_governor,
293 .set_curr_governor = cpufreq_dvfs_set_curr_governor,
294 .get_curr_freq = cpufreq_dvfs_get_curr_freq,
295 .get_min_freq = cpufreq_dvfs_get_min_freq,
296 .set_min_freq = cpufreq_dvfs_set_min_freq,
297 .get_max_freq = cpufreq_dvfs_get_max_freq,
298 .set_max_freq = cpufreq_dvfs_set_max_freq,
299 .get_available_min_freq = cpufreq_dvfs_get_available_min_freq,
300 .get_available_max_freq = cpufreq_dvfs_get_available_max_freq,
301 .get_up_threshold = cpufreq_dvfs_get_up_threshold,
302 .set_up_threshold = cpufreq_dvfs_set_up_threshold,
305 static int cpu_hotplug_get_online_state(char *res_name, int cpu)
313 snprintf(path, PATH_MAX, "%s%d%s",
314 CPU_ONLINE_PATH_PREFIX,
316 CPU_ONLINE_PATH_SUFFIX);
318 ret = sysfs_read_int(path, &online);
325 static int cpu_hotplug_set_online_state(char *res_name, int cpu, int on)
332 if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
336 * NOTE: Exynos SoC series cannot turn off the CPU0
337 * because of h/w design. To prevent the critical problem,
338 * if someone try to turn off the CPU0, just return without any
341 if (on == 0 && cpu == 0) {
345 snprintf(path, PATH_MAX, "%s%d%s",
346 CPU_ONLINE_PATH_PREFIX,
348 CPU_ONLINE_PATH_SUFFIX);
350 ret = sysfs_write_int(path, on);
357 static struct pass_resource_hotplug_ops cpu_hotplus_ops = {
358 .get_online_state = cpu_hotplug_get_online_state,
359 .set_online_state = cpu_hotplug_set_online_state,
360 .get_online_min_num = NULL,
361 .set_online_min_num = NULL,
362 .get_online_max_num = NULL,
363 .set_online_max_num = NULL,
366 static int tmu_get_temp(char *res_thermal_name)
371 if (!res_thermal_name)
374 snprintf(path, PATH_MAX, "%s%s%s",
377 TMU_TEMP_PATH_SUFFIX);
379 ret = sysfs_read_int(path, &temp);
384 * Thermal framework provides the current temperature
385 * as five digits interger like 54430 when temperature is 54.430
386 * degrees centigrade. But, Thermal Monitor in Tizen usually
387 * use two digits interger without decimal point.
388 * So that round temperature value. It constraints the maximume
389 * temperature as 1048 degrees centigrade for preventing integer
390 * overflow. Usually, the embedded device never over 1000 degrees
393 return (((temp & TMU_MAX_TEMP_MASK) + 500) / 1000);
396 static int tmu_get_policy(char *res_thermal_name, char *policy)
401 if ((!res_thermal_name) || (!policy))
404 snprintf(path, PATH_MAX, "%s%s%s",
407 TMU_POLICY_PATH_SUFFIX);
409 ret = sysfs_read_str(path, policy, BUFF_MAX);
416 static struct pass_resource_tmu_ops tmu_ops = {
417 .get_temp = tmu_get_temp,
418 .get_policy = tmu_get_policy,
421 /*****************************************************
422 * HAL backend implementation for BUS/GPU H/W Resource
424 static int devfreq_dvfs_get_curr_governor(char *res_name, char *governor)
429 if ((!res_name) || (!governor))
432 snprintf(path, PATH_MAX, "%s%s%s",
433 DEVFREQ_BUS_PATH_PREFIX,
435 DEVFREQ_BUS_CURR_GOVERNOR_PATH_SUFFIX);
437 ret = sysfs_read_str(path, governor, BUFF_MAX);
444 static int devfreq_dvfs_set_curr_governor(char *res_name, char *governor)
449 if ((!res_name) || (!governor))
452 snprintf(path, PATH_MAX, "%s%s%s",
453 DEVFREQ_BUS_PATH_PREFIX,
455 DEVFREQ_BUS_CURR_GOVERNOR_PATH_SUFFIX);
457 ret = sysfs_write_str(path, governor);
464 static int devfreq_dvfs_get_curr_freq(char *res_name)
472 snprintf(path, PATH_MAX, "%s%s%s",
473 DEVFREQ_BUS_PATH_PREFIX,
475 DEVFREQ_BUS_CURR_FREQ_PATH_SUFFIX);
477 ret = sysfs_read_int(path, &freq);
484 static int devfreq_dvfs_get_min_freq(char *res_name)
492 snprintf(path, PATH_MAX, "%s%s%s",
493 DEVFREQ_BUS_PATH_PREFIX,
495 DEVFREQ_BUS_MIN_FREQ_PATH_SUFFIX);
497 ret = sysfs_read_int(path, &freq);
504 static int devfreq_dvfs_set_min_freq(char *res_name, int freq)
509 if ((!res_name) || (freq < 0))
512 snprintf(path, PATH_MAX, "%s%s%s",
513 DEVFREQ_BUS_PATH_PREFIX,
515 DEVFREQ_BUS_MIN_FREQ_PATH_SUFFIX);
517 ret = sysfs_write_int(path, freq);
524 static int devfreq_dvfs_get_max_freq(char *res_name)
532 snprintf(path, PATH_MAX, "%s%s%s",
533 DEVFREQ_BUS_PATH_PREFIX,
535 DEVFREQ_BUS_MAX_FREQ_PATH_SUFFIX);
537 ret = sysfs_read_int(path, &freq);
544 static int devfreq_dvfs_set_max_freq(char *res_name, int freq)
549 if ((!res_name) || (freq < 0))
552 snprintf(path, PATH_MAX, "%s%s%s",
553 DEVFREQ_BUS_PATH_PREFIX,
555 DEVFREQ_BUS_MAX_FREQ_PATH_SUFFIX);
557 ret = sysfs_write_int(path, freq);
563 static int devfreq_dvfs_get_available_min_freq(char *res_name)
566 char buf[MAX_BUF_SIZE + 1];
573 snprintf(path, PATH_MAX, "%s%s%s",
574 DEVFREQ_BUS_PATH_PREFIX,
576 DEVFREQ_BUS_AVAILABLE_FREQ_PATH_SUFFIX);
578 ret = sysfs_read_str(path, buf, MAX_BUF_SIZE);
582 p = strchr(buf, ' ');
586 ret = strtoul(buf, NULL, 10);
593 static int devfreq_dvfs_get_available_max_freq(char *res_name)
596 char buf[MAX_BUF_SIZE + 1];
603 snprintf(path, PATH_MAX, "%s%s%s",
604 DEVFREQ_BUS_PATH_PREFIX,
606 DEVFREQ_BUS_AVAILABLE_FREQ_PATH_SUFFIX);
608 ret = sysfs_read_str(path, buf, MAX_BUF_SIZE);
612 p = strrchr(buf, ' ');
615 ret = strtoul(p, NULL, 10);
622 static struct pass_resource_dvfs_ops devfreq_dvfs_ops = {
623 .get_curr_governor = devfreq_dvfs_get_curr_governor,
624 .set_curr_governor = devfreq_dvfs_set_curr_governor,
625 .get_curr_freq = devfreq_dvfs_get_curr_freq,
626 .get_min_freq = devfreq_dvfs_get_min_freq,
627 .set_min_freq = devfreq_dvfs_set_min_freq,
628 .get_max_freq = devfreq_dvfs_get_max_freq,
629 .set_max_freq = devfreq_dvfs_set_max_freq,
630 .get_available_min_freq = devfreq_dvfs_get_available_min_freq,
631 .get_available_max_freq = devfreq_dvfs_get_available_max_freq,
634 /****************************************************
635 * HAL backend implementation for Memory H/W Resource
637 static int memory_get_fault_around_bytes(char *res_name)
639 int ret, fault_around_bytes;
644 ret = sysfs_read_int(FAULT_AROUND_BYTES_PATH, &fault_around_bytes);
648 return fault_around_bytes;
651 static int memory_set_fault_around_bytes(char *res_name,
652 int fault_around_bytes)
656 if ((!res_name) || (fault_around_bytes <= 0))
659 ret = sysfs_write_int(FAULT_AROUND_BYTES_PATH, fault_around_bytes);
666 /************************
667 * HAL backend power data
669 static int power_init(void **data)
671 hal_backend_power_funcs *power_funcs = NULL;
672 struct pass_resource_cpu *cpu = NULL;
673 struct pass_resource_bus *bus = NULL;
674 struct pass_resource_gpu *gpu = NULL;
675 struct pass_resource_memory *memory = NULL;
678 /* Allocate memory */
679 power_funcs = calloc(1, sizeof(hal_backend_power_funcs));
683 cpu = calloc(1, sizeof(struct pass_resource_cpu));
689 bus = calloc(1, sizeof(struct pass_resource_bus));
695 gpu = calloc(1, sizeof(struct pass_resource_gpu));
701 memory = calloc(1, sizeof(struct pass_resource_memory));
707 /* Initialize each h/w resource */
708 cpu->dvfs = cpufreq_dvfs_ops;
709 cpu->hotplug = cpu_hotplus_ops;
712 bus->dvfs = devfreq_dvfs_ops;
715 gpu->dvfs = devfreq_dvfs_ops;
718 memory->get_fault_around_bytes = memory_get_fault_around_bytes;
719 memory->set_fault_around_bytes = memory_set_fault_around_bytes;
721 /* Initialize hal_backend_power_funcs */
722 power_funcs->cpu = cpu;
723 power_funcs->bus = bus;
724 power_funcs->gpu = gpu;
725 power_funcs->memory = memory;
727 *data = (void *)power_funcs;
746 static int power_exit(void *data)
748 hal_backend_power_funcs *funcs;
753 funcs = (hal_backend_power_funcs *)data;
769 hal_backend hal_backend_power_data = {
772 .abi_version = HAL_ABI_VERSION_TIZEN_6_5,