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"
38 * The cpuinfo_cur_freq indicates the actual operating CPU freqeuncy
39 * and scaling_cur_freq is the CPU frequency set by the CPUFREQ policy.
41 #define CPUFREQ_CURR_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_cur_freq"
42 #define CPUFREQ_AVAILABLE_MIN_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_min_freq"
43 #define CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_max_freq"
44 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq"
45 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq"
46 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold"
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"
56 #define TMU_MAX_TEMP_MASK 0xFFFFF
58 #define FAULT_AROUND_BYTES_PATH "/sys/kernel/debug/fault_around_bytes"
60 static int get_path(char *path, char *prefix, char *res_name, char *suffix)
64 if (!path || !prefix || !res_name || !suffix)
67 ret = snprintf(path, PATH_MAX, "%s%s%s", prefix, res_name, suffix);
71 path[PATH_MAX - 1] = '\0';
76 static int __handle_value_string(int is_write, char *prefix, char *res_name, char *suffix, char *buf)
84 ret = get_path(path, prefix, res_name, suffix);
89 ret = sysfs_write_str(path, buf);
91 ret = sysfs_read_str(path, buf, BUFF_MAX);
93 return (ret < 0) ? ret : 0;
96 static int get_value_string(char *prefix, char *res_name, char *suffix, char *buf)
98 return __handle_value_string(0, prefix, res_name, suffix, buf);
101 static int set_value_string(char *prefix, char *res_name, char *suffix, char *buf)
103 return __handle_value_string(1, prefix, res_name, suffix, buf);
106 static int get_value_integer(char *prefix, char *res_name, char *suffix, int *value)
114 ret = get_path(path, prefix, res_name, suffix);
118 ret = sysfs_read_int(path, value);
125 static int set_value_integer(char *prefix, char *res_name, char *suffix, int value)
130 ret = get_path(path, prefix, res_name, suffix);
134 ret = sysfs_write_int(path, value);
141 /*************************************************
142 * HAL backend implementation for CPU H/W Resource
144 static int cpufreq_dvfs_get_curr_governor(char *res_name, char *governor)
148 ret = get_value_string(CPUFREQ_PATH_PREFIX, res_name,
149 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX, governor);
150 return (ret < 0) ? ret : 0;
153 static int cpufreq_dvfs_set_curr_governor(char *res_name, char *governor)
157 ret = set_value_string(CPUFREQ_PATH_PREFIX, res_name,
158 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX, governor);
159 return (ret < 0) ? ret : 0;
162 static int cpufreq_dvfs_get_curr_freq(char *res_name)
166 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
167 CPUFREQ_CURR_FREQ_PATH_SUFFIX, &freq);
168 return (ret < 0) ? ret : freq;
171 static int cpufreq_dvfs_get_min_freq(char *res_name)
175 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
176 CPUFREQ_MIN_FREQ_PATH_SUFFIX, &freq);
177 return (ret < 0) ? ret : freq;
180 static int cpufreq_dvfs_set_min_freq(char *res_name, int freq)
187 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
188 CPUFREQ_MIN_FREQ_PATH_SUFFIX, freq);
189 return (ret < 0) ? ret : 0;
192 static int cpufreq_dvfs_get_max_freq(char *res_name)
196 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
197 CPUFREQ_MAX_FREQ_PATH_SUFFIX, &freq);
198 return (ret < 0) ? ret : freq;
201 static int cpufreq_dvfs_set_max_freq(char *res_name, int freq)
208 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
209 CPUFREQ_MAX_FREQ_PATH_SUFFIX, freq);
210 return (ret < 0) ? ret : 0;
213 static int cpufreq_dvfs_get_available_min_freq(char *res_name)
217 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
218 CPUFREQ_AVAILABLE_MIN_FREQ_PATH_SUFFIX, &val);
219 return (ret < 0) ? ret : val;
222 static int cpufreq_dvfs_get_available_max_freq(char *res_name)
226 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
227 CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX, &val);
228 return (ret < 0) ? ret : val;
231 static int cpufreq_dvfs_get_up_threshold(char *res_name)
235 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
236 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX, &val);
237 return (ret < 0) ? ret : val;
240 static int cpufreq_dvfs_set_up_threshold(char *res_name, int up_threshold)
244 if (up_threshold < 0)
247 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
248 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX, up_threshold);
249 return (ret < 0) ? ret : 0;
252 static struct pass_resource_dvfs_ops cpufreq_dvfs_ops = {
253 .get_curr_governor = cpufreq_dvfs_get_curr_governor,
254 .set_curr_governor = cpufreq_dvfs_set_curr_governor,
255 .get_curr_freq = cpufreq_dvfs_get_curr_freq,
256 .get_min_freq = cpufreq_dvfs_get_min_freq,
257 .set_min_freq = cpufreq_dvfs_set_min_freq,
258 .get_max_freq = cpufreq_dvfs_get_max_freq,
259 .set_max_freq = cpufreq_dvfs_set_max_freq,
260 .get_available_min_freq = cpufreq_dvfs_get_available_min_freq,
261 .get_available_max_freq = cpufreq_dvfs_get_available_max_freq,
262 .get_up_threshold = cpufreq_dvfs_get_up_threshold,
263 .set_up_threshold = cpufreq_dvfs_set_up_threshold,
266 static int cpu_hotplug_get_online_state(char *res_name, int cpu)
274 snprintf(path, PATH_MAX, "%s%d%s",
275 CPU_ONLINE_PATH_PREFIX,
277 CPU_ONLINE_PATH_SUFFIX);
279 ret = sysfs_read_int(path, &online);
286 static int cpu_hotplug_set_online_state(char *res_name, int cpu, int on)
293 if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
297 * NOTE: Exynos SoC series cannot turn off the CPU0
298 * because of h/w design. To prevent the critical problem,
299 * if someone try to turn off the CPU0, just return without any
302 if (on == 0 && cpu == 0) {
306 snprintf(path, PATH_MAX, "%s%d%s",
307 CPU_ONLINE_PATH_PREFIX,
309 CPU_ONLINE_PATH_SUFFIX);
311 ret = sysfs_write_int(path, on);
318 static struct pass_resource_hotplug_ops cpu_hotplus_ops = {
319 .get_online_state = cpu_hotplug_get_online_state,
320 .set_online_state = cpu_hotplug_set_online_state,
323 static int tmu_get_temp(char *res_thermal_name)
327 ret = get_value_integer(TMU_PATH_PREFIX, res_thermal_name,
328 TMU_TEMP_PATH_SUFFIX, &temp);
333 * Thermal framework provides the current temperature
334 * as five digits interger like 54430 when temperature is 54.430
335 * degrees centigrade. But, Thermal Monitor in Tizen usually
336 * use two digits interger without decimal point.
337 * So that round temperature value. It constraints the maximume
338 * temperature as 1048 degrees centigrade for preventing integer
339 * overflow. Usually, the embedded device never over 1000 degrees
342 return (((temp & TMU_MAX_TEMP_MASK) + 500) / 1000);
345 static int tmu_get_policy(char *res_thermal_name, char *policy)
352 ret = get_value_string(TMU_PATH_PREFIX, res_thermal_name,
353 TMU_POLICY_PATH_SUFFIX, policy);
354 return (ret < 0) ? ret : 0;
357 static struct pass_resource_tmu_ops tmu_ops = {
358 .get_temp = tmu_get_temp,
359 .get_policy = tmu_get_policy,
362 /*****************************************************
363 * HAL backend implementation for BUS/GPU H/W Resource
366 static int bus_dvfs_get_curr_freq(char *res_name)
368 char buf[BUFF_MAX + 1];
369 char unit[BUFF_MAX + 1];
372 ret = sysfs_read_str("/sys/class/aml_ddr/freq", buf, BUFF_MAX);
376 sscanf(buf, "%d %s", &freq, unit);
378 return (freq * 1000);
381 static int gpu_freq_table[] = {
389 static int gpu_dvfs_get_min_freq(char *res_name)
393 ret = sysfs_read_int("/sys/class/mpgpu/min_freq", &freq);
396 return (ret < 0) ? ret : (gpu_freq_table[freq]);
399 static int gpu_dvfs_get_max_freq(char *res_name)
403 ret = sysfs_read_int("/sys/class/mpgpu/max_freq", &freq);
406 return (ret < 0) ? ret : gpu_freq_table[freq];
409 static int gpu_dvfs_get_curr_freq(char *res_name)
413 ret = sysfs_read_int("/sys/class/mpgpu/cur_freq", &freq);
416 return (ret < 0) ? ret : (freq * 1000);
419 static struct pass_resource_dvfs_ops bus_dvfs_ops = {
420 .get_curr_freq = bus_dvfs_get_curr_freq,
421 .get_min_freq = bus_dvfs_get_curr_freq,
422 .get_max_freq = bus_dvfs_get_curr_freq,
425 static struct pass_resource_dvfs_ops gpu_dvfs_ops = {
426 .get_curr_freq = gpu_dvfs_get_curr_freq,
427 .get_min_freq = gpu_dvfs_get_min_freq,
428 .get_max_freq = gpu_dvfs_get_max_freq,
431 /****************************************************
432 * HAL backend implementation for Memory H/W Resource
434 static int memory_get_fault_around_bytes(char *res_name)
436 int ret, fault_around_bytes;
441 ret = sysfs_read_int(FAULT_AROUND_BYTES_PATH, &fault_around_bytes);
445 return fault_around_bytes;
448 static int memory_set_fault_around_bytes(char *res_name,
449 int fault_around_bytes)
453 if ((!res_name) || (fault_around_bytes <= 0))
456 ret = sysfs_write_int(FAULT_AROUND_BYTES_PATH, fault_around_bytes);
463 /************************
464 * HAL backend power data
466 static int power_init(void **data)
468 hal_backend_power_funcs *power_funcs = NULL;
469 struct pass_resource_cpu *cpu = NULL;
470 struct pass_resource_bus *bus = NULL;
471 struct pass_resource_gpu *gpu = NULL;
472 struct pass_resource_memory *memory = NULL;
475 /* Allocate memory */
476 power_funcs = calloc(1, sizeof(hal_backend_power_funcs));
480 cpu = calloc(1, sizeof(struct pass_resource_cpu));
486 bus = calloc(1, sizeof(struct pass_resource_bus));
492 gpu = calloc(1, sizeof(struct pass_resource_gpu));
498 memory = calloc(1, sizeof(struct pass_resource_memory));
504 /* Initialize each h/w resource */
505 cpu->dvfs = cpufreq_dvfs_ops;
506 cpu->hotplug = cpu_hotplus_ops;
509 bus->dvfs = bus_dvfs_ops;
512 gpu->dvfs = gpu_dvfs_ops;
515 memory->get_fault_around_bytes = memory_get_fault_around_bytes;
516 memory->set_fault_around_bytes = memory_set_fault_around_bytes;
518 /* Initialize hal_backend_power_funcs */
519 power_funcs->cpu = cpu;
520 power_funcs->bus = bus;
521 power_funcs->gpu = gpu;
522 power_funcs->memory = memory;
524 *data = (void *)power_funcs;
543 static int power_exit(void *data)
545 hal_backend_power_funcs *funcs;
550 funcs = (hal_backend_power_funcs *)data;
566 hal_backend hal_backend_power_data = {
567 .name = "hal-backend-power-vim3",
569 .abi_version = HAL_ABI_VERSION_TIZEN_6_5,