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.
24 #include <hal/hal-power-interface.h>
30 /*************************
31 * H/W Resource Defintions
33 #define CPUFREQ_PATH_PREFIX "/sys/devices/system/cpu/"
34 #define CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX "/cpufreq/scaling_governor"
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_AVAILABLE_MIN_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_min_freq"
42 #define CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX "/cpufreq/cpuinfo_max_freq"
43 #define CPUFREQ_MIN_FREQ_PATH_SUFFIX "/cpufreq/scaling_min_freq"
44 #define CPUFREQ_MAX_FREQ_PATH_SUFFIX "/cpufreq/scaling_max_freq"
45 #define CPUFREQ_UP_THRESHOLD_PATH_SUFFIX "/cpufreq/ondemand/up_threshold"
47 #define CPU_ONLINE_PATH_PREFIX "/sys/devices/system/cpu/cpu"
48 #define CPU_ONLINE_PATH_SUFFIX "/online"
49 #define CPU_ONLINE_STATE_ON 1
50 #define CPU_ONLINE_STATE_OFF 0
52 #define TMU_PATH_PREFIX "/sys/class/thermal/"
53 #define TMU_TEMP_PATH_SUFFIX "/temp"
54 #define TMU_POLICY_PATH_SUFFIX "/policy"
55 #define TMU_MAX_TEMP_MASK 0xFFFFF
57 #define FAULT_AROUND_BYTES_PATH "/sys/kernel/debug/fault_around_bytes"
59 static int get_path(char *path, char *prefix, char *res_name, char *suffix)
63 if (!path || !prefix || !res_name || !suffix)
66 ret = snprintf(path, PATH_MAX, "%s%s%s", prefix, res_name, suffix);
70 path[PATH_MAX - 1] = '\0';
75 static int __handle_value_string(int is_write, char *prefix, char *res_name, char *suffix, char *buf)
83 ret = get_path(path, prefix, res_name, suffix);
88 ret = sysfs_write_str(path, buf);
90 ret = sysfs_read_str(path, buf, BUFF_MAX);
92 return (ret < 0) ? ret : 0;
95 static int get_value_string(char *prefix, char *res_name, char *suffix, char *buf)
97 return __handle_value_string(0, prefix, res_name, suffix, buf);
100 static int set_value_string(char *prefix, char *res_name, char *suffix, char *buf)
102 return __handle_value_string(1, prefix, res_name, suffix, buf);
105 static int get_value_integer(char *prefix, char *res_name, char *suffix, int *value)
113 ret = get_path(path, prefix, res_name, suffix);
117 ret = sysfs_read_int(path, value);
124 static int set_value_integer(char *prefix, char *res_name, char *suffix, int value)
129 ret = get_path(path, prefix, res_name, suffix);
133 ret = sysfs_write_int(path, value);
140 /*************************************************
141 * HAL backend implementation for CPU H/W Resource
143 static int cpufreq_dvfs_get_curr_governor(char *res_name, char *governor)
147 ret = get_value_string(CPUFREQ_PATH_PREFIX, res_name,
148 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX, governor);
149 return (ret < 0) ? ret : 0;
152 static int cpufreq_dvfs_set_curr_governor(char *res_name, char *governor)
156 ret = set_value_string(CPUFREQ_PATH_PREFIX, res_name,
157 CPUFREQ_CURR_GOVERNOR_PATH_SUFFIX, governor);
158 return (ret < 0) ? ret : 0;
161 static int cpufreq_dvfs_get_curr_freq(char *res_name)
165 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
166 CPUFREQ_CURR_FREQ_PATH_SUFFIX, &freq);
167 return (ret < 0) ? ret : freq;
170 static int cpufreq_dvfs_get_min_freq(char *res_name)
174 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
175 CPUFREQ_MIN_FREQ_PATH_SUFFIX, &freq);
176 return (ret < 0) ? ret : freq;
179 static int cpufreq_dvfs_set_min_freq(char *res_name, int freq)
186 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
187 CPUFREQ_MIN_FREQ_PATH_SUFFIX, freq);
188 return (ret < 0) ? ret : 0;
191 static int cpufreq_dvfs_get_max_freq(char *res_name)
195 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
196 CPUFREQ_MAX_FREQ_PATH_SUFFIX, &freq);
197 return (ret < 0) ? ret : freq;
200 static int cpufreq_dvfs_set_max_freq(char *res_name, int freq)
207 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
208 CPUFREQ_MAX_FREQ_PATH_SUFFIX, freq);
209 return (ret < 0) ? ret : 0;
212 static int cpufreq_dvfs_get_available_min_freq(char *res_name)
216 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
217 CPUFREQ_AVAILABLE_MIN_FREQ_PATH_SUFFIX, &val);
218 return (ret < 0) ? ret : val;
221 static int cpufreq_dvfs_get_available_max_freq(char *res_name)
225 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
226 CPUFREQ_AVAILABLE_MAX_FREQ_PATH_SUFFIX, &val);
227 return (ret < 0) ? ret : val;
230 static int cpufreq_dvfs_get_up_threshold(char *res_name)
234 ret = get_value_integer(CPUFREQ_PATH_PREFIX, res_name,
235 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX, &val);
236 return (ret < 0) ? ret : val;
239 static int cpufreq_dvfs_set_up_threshold(char *res_name, int up_threshold)
243 if (up_threshold < 0)
246 ret = set_value_integer(CPUFREQ_PATH_PREFIX, res_name,
247 CPUFREQ_UP_THRESHOLD_PATH_SUFFIX, up_threshold);
248 return (ret < 0) ? ret : 0;
251 static struct pass_resource_dvfs_ops cpufreq_dvfs_ops = {
252 .get_curr_governor = cpufreq_dvfs_get_curr_governor,
253 .set_curr_governor = cpufreq_dvfs_set_curr_governor,
254 .get_curr_freq = cpufreq_dvfs_get_curr_freq,
255 .get_min_freq = cpufreq_dvfs_get_min_freq,
256 .set_min_freq = cpufreq_dvfs_set_min_freq,
257 .get_max_freq = cpufreq_dvfs_get_max_freq,
258 .set_max_freq = cpufreq_dvfs_set_max_freq,
259 .get_available_min_freq = cpufreq_dvfs_get_available_min_freq,
260 .get_available_max_freq = cpufreq_dvfs_get_available_max_freq,
261 .get_up_threshold = cpufreq_dvfs_get_up_threshold,
262 .set_up_threshold = cpufreq_dvfs_set_up_threshold,
265 static int cpu_hotplug_get_online_state(char *res_name, int cpu)
273 snprintf(path, PATH_MAX, "%s%d%s",
274 CPU_ONLINE_PATH_PREFIX,
276 CPU_ONLINE_PATH_SUFFIX);
278 ret = sysfs_read_int(path, &online);
285 static int cpu_hotplug_set_online_state(char *res_name, int cpu, int on)
292 if ((on != CPU_ONLINE_STATE_ON) && (on != CPU_ONLINE_STATE_OFF))
296 * NOTE: Exynos SoC series cannot turn off the CPU0
297 * because of h/w design. To prevent the critical problem,
298 * if someone try to turn off the CPU0, just return without any
301 if (on == 0 && cpu == 0) {
305 snprintf(path, PATH_MAX, "%s%d%s",
306 CPU_ONLINE_PATH_PREFIX,
308 CPU_ONLINE_PATH_SUFFIX);
310 ret = sysfs_write_int(path, on);
317 static struct pass_resource_hotplug_ops cpu_hotplus_ops = {
318 .get_online_state = cpu_hotplug_get_online_state,
319 .set_online_state = cpu_hotplug_set_online_state,
322 static int tmu_get_temp(char *res_thermal_name)
326 ret = get_value_integer(TMU_PATH_PREFIX, res_thermal_name,
327 TMU_TEMP_PATH_SUFFIX, &temp);
332 * Thermal framework provides the current temperature
333 * as five digits interger like 54430 when temperature is 54.430
334 * degrees centigrade. But, Thermal Monitor in Tizen usually
335 * use two digits interger without decimal point.
336 * So that round temperature value. It constraints the maximume
337 * temperature as 1048 degrees centigrade for preventing integer
338 * overflow. Usually, the embedded device never over 1000 degrees
341 return (((temp & TMU_MAX_TEMP_MASK) + 500) / 1000);
344 static int tmu_get_policy(char *res_thermal_name, char *policy)
351 ret = get_value_string(TMU_PATH_PREFIX, res_thermal_name,
352 TMU_POLICY_PATH_SUFFIX, policy);
353 return (ret < 0) ? ret : 0;
356 static struct pass_resource_tmu_ops tmu_ops = {
357 .get_temp = tmu_get_temp,
358 .get_policy = tmu_get_policy,
361 /*****************************************************
362 * HAL backend implementation for BUS/GPU H/W Resource
365 static int bus_dvfs_get_curr_freq(char *res_name)
367 char buf[BUFF_MAX + 1];
370 ret = sysfs_read_str("/sys/class/aml_ddr/freq", buf, BUFF_MAX);
374 if (sscanf(buf, "%d %*s", &freq) != 1)
377 if (freq < 0 || freq > INT_MAX/1000)
380 return (freq * 1000);
383 static int gpu_freq_table[] = {
391 #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
393 static int gpu_dvfs_get_min_freq(char *res_name)
397 ret = sysfs_read_int("/sys/class/mpgpu/min_freq", &freq);
399 if (freq < 0 || freq >= ARRAY_LENGTH(gpu_freq_table))
402 return (ret < 0) ? ret : (gpu_freq_table[freq]);
405 static int gpu_dvfs_get_max_freq(char *res_name)
409 ret = sysfs_read_int("/sys/class/mpgpu/max_freq", &freq);
410 if (freq < 0 || freq >= ARRAY_LENGTH(gpu_freq_table))
413 return (ret < 0) ? ret : gpu_freq_table[freq];
416 static int gpu_dvfs_get_curr_freq(char *res_name)
420 ret = sysfs_read_int("/sys/class/mpgpu/cur_freq", &freq);
422 return (ret < 0) ? ret : (freq * 1000);
425 static struct pass_resource_dvfs_ops bus_dvfs_ops = {
426 .get_curr_freq = bus_dvfs_get_curr_freq,
427 .get_min_freq = bus_dvfs_get_curr_freq,
428 .get_max_freq = bus_dvfs_get_curr_freq,
431 static struct pass_resource_dvfs_ops gpu_dvfs_ops = {
432 .get_curr_freq = gpu_dvfs_get_curr_freq,
433 .get_min_freq = gpu_dvfs_get_min_freq,
434 .get_max_freq = gpu_dvfs_get_max_freq,
437 /****************************************************
438 * HAL backend implementation for Memory H/W Resource
440 static int memory_get_fault_around_bytes(char *res_name)
442 int ret, fault_around_bytes;
447 ret = sysfs_read_int(FAULT_AROUND_BYTES_PATH, &fault_around_bytes);
451 return fault_around_bytes;
454 static int memory_set_fault_around_bytes(char *res_name,
455 int fault_around_bytes)
459 if ((!res_name) || (fault_around_bytes <= 0))
462 ret = sysfs_write_int(FAULT_AROUND_BYTES_PATH, fault_around_bytes);
469 /************************
470 * HAL backend power data
472 static int power_init(void **data)
474 hal_backend_power_funcs *power_funcs = NULL;
475 struct pass_resource_cpu *cpu = NULL;
476 struct pass_resource_bus *bus = NULL;
477 struct pass_resource_gpu *gpu = NULL;
478 struct pass_resource_memory *memory = NULL;
481 /* Allocate memory */
482 power_funcs = calloc(1, sizeof(hal_backend_power_funcs));
486 cpu = calloc(1, sizeof(struct pass_resource_cpu));
492 bus = calloc(1, sizeof(struct pass_resource_bus));
498 gpu = calloc(1, sizeof(struct pass_resource_gpu));
504 memory = calloc(1, sizeof(struct pass_resource_memory));
510 /* Initialize each h/w resource */
511 cpu->dvfs = cpufreq_dvfs_ops;
512 cpu->hotplug = cpu_hotplus_ops;
515 bus->dvfs = bus_dvfs_ops;
518 gpu->dvfs = gpu_dvfs_ops;
521 memory->get_fault_around_bytes = memory_get_fault_around_bytes;
522 memory->set_fault_around_bytes = memory_set_fault_around_bytes;
524 /* Initialize hal_backend_power_funcs */
525 power_funcs->cpu = cpu;
526 power_funcs->bus = bus;
527 power_funcs->gpu = gpu;
528 power_funcs->memory = memory;
530 *data = (void *)power_funcs;
549 static int power_exit(void *data)
551 hal_backend_power_funcs *funcs;
556 funcs = (hal_backend_power_funcs *)data;
572 hal_backend hal_backend_power_data = {
573 .name = "hal-backend-power-vim3",
575 .abi_version = HAL_ABI_VERSION_TIZEN_6_5,