2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <hal/hal-common.h>
24 #include "hal-power-interface.h"
25 #include "hal-power.h"
29 #define EXPORT __attribute__ ((visibility("default")))
32 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
33 #define FAULT_AROUND_BYTES_4K 4096
35 static hal_backend_power_funcs *g_power_funcs = NULL;
36 static unsigned int g_power_funcs_count = 0;
38 static int is_supported_from_backend(hal_backend_power_funcs *funcs, int res_type)
41 case PASS_RESOURCE_CPU_ID:
42 if (funcs && funcs->cpu)
45 case PASS_RESOURCE_BUS_ID:
46 if (funcs && funcs->bus)
49 case PASS_RESOURCE_GPU_ID:
50 if (funcs && funcs->gpu)
53 case PASS_RESOURCE_MEMORY_ID:
54 if (funcs && funcs->memory)
57 case PASS_RESOURCE_BATTERY_ID:
58 if (funcs && funcs->battery)
61 case PASS_RESOURCE_NONSTANDARD_ID:
62 if (funcs && funcs->nonstandard)
65 case PASS_RESOURCE_PROCESS_ID:
66 case PASS_RESOURCE_DISPLAY_ID:
67 case PASS_RESOURCE_SYSTEM_ID:
68 case PASS_RESOURCE_PROCESS_GROUP_ID:
69 case PASS_RESOURCE_DISK_ID:
70 case PASS_RESOURCE_NETWORK_ID:
72 * These resource types have not yet needed any hal backend.
73 * But, these resource types might need the resource
74 * configuration according to hardware device.
82 static int get_dvfs(hal_backend_power_funcs *funcs, int res_type, char *res_name,
83 struct pass_resource_dvfs_ops **dvfs)
91 case PASS_RESOURCE_CPU_ID:
92 if (funcs && funcs->cpu)
93 *dvfs = &(funcs->cpu->dvfs);
95 case PASS_RESOURCE_BUS_ID:
96 if (funcs && funcs->bus)
97 *dvfs = &(funcs->bus->dvfs);
99 case PASS_RESOURCE_GPU_ID:
100 if (funcs && funcs->gpu)
101 *dvfs = &(funcs->gpu->dvfs);
110 static int get_tmu(hal_backend_power_funcs *funcs, int res_type, char *res_name,
111 struct pass_resource_tmu_ops **tmu)
119 case PASS_RESOURCE_CPU_ID:
120 if (funcs && funcs->cpu)
121 *tmu = &(funcs->cpu->tmu);
123 case PASS_RESOURCE_BUS_ID:
124 if (funcs && funcs->bus)
125 *tmu = &(funcs->bus->tmu);
127 case PASS_RESOURCE_GPU_ID:
128 if (funcs && funcs->gpu)
129 *tmu = &(funcs->gpu->tmu);
131 case PASS_RESOURCE_BATTERY_ID:
132 if (funcs && funcs->battery)
133 *tmu = &(funcs->battery->tmu);
135 case PASS_RESOURCE_NONSTANDARD_ID:
136 if (funcs && funcs->nonstandard)
137 *tmu = &(funcs->nonstandard->tmu);
146 static int get_hotplug(hal_backend_power_funcs *funcs, int res_type, char *res_name,
147 struct pass_resource_hotplug_ops **hotplug)
155 case PASS_RESOURCE_CPU_ID:
156 if (funcs && funcs->cpu)
157 *hotplug = &(funcs->cpu->hotplug);
166 static int get_charging(hal_backend_power_funcs *funcs, int res_type, char *res_name,
167 struct pass_resource_battery_ops **charging)
175 case PASS_RESOURCE_BATTERY_ID:
176 if (funcs && funcs->battery)
177 *charging = &(funcs->battery->battery);
179 case PASS_RESOURCE_NONSTANDARD_ID:
180 if (funcs && funcs->nonstandard)
181 *charging = &(funcs->nonstandard->battery);
190 EXPORT int hal_power_get_backend(unsigned int res_type)
192 g_power_funcs_count++;
194 if (!g_power_funcs) {
197 ret = hal_common_get_backend(HAL_MODULE_POWER,
198 (void **)&g_power_funcs);
200 _E("Failed to get backend of HAL_MODULE_POWER\n");
205 if (!is_supported_from_backend(g_power_funcs, res_type)) {
206 _E("Don't support resource(%d) from HAL_MODULE_POWER backend\n",
214 EXPORT int hal_power_put_backend(void)
216 if (!g_power_funcs_count)
219 if (--g_power_funcs_count > 0)
222 hal_common_put_backend(HAL_MODULE_POWER, (void *)g_power_funcs);
223 g_power_funcs = NULL;
228 static int is_valid_param_with_str(char *res_name, char *str)
232 else if (!res_name || !str)
237 static int is_valid_param_with_int(char *res_name, int val)
241 else if (!res_name || val < 0)
246 static inline int exec_func(int (*func)(char *res_name), char *res_name)
250 return func(res_name);
253 static inline int exec_func_with_str(int (*func)(char *res_name, char *str),
254 char *res_name, char *str)
258 return func(res_name, str);
261 static inline int exec_func_with_int(int (*func)(char *res_name, int val),
262 char *res_name, int val)
266 return func(res_name, val);
269 /* Get and set the current governor. */
270 EXPORT int hal_power_dvfs_get_curr_governor(unsigned int res_type,
271 char *res_name, char *governor)
273 struct pass_resource_dvfs_ops *dvfs;
279 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
280 if (ret < 0 || !dvfs)
283 return exec_func_with_str(dvfs->get_curr_governor, res_name, governor);
286 EXPORT int hal_power_dvfs_set_curr_governor(unsigned int res_type, char *res_name, char *governor)
288 struct pass_resource_dvfs_ops *dvfs;
294 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
295 if (ret < 0 || !dvfs)
298 return exec_func_with_str(dvfs->set_curr_governor, res_name, governor);
301 EXPORT int hal_power_dvfs_get_avail_governor(unsigned int res_type, char *res_name, char **avail_governor)
303 struct pass_resource_dvfs_ops *dvfs;
306 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
307 if (ret < 0 || !dvfs)
310 if (!dvfs->get_avail_governor)
313 return dvfs->get_avail_governor(res_name, avail_governor);
316 /* Get the current frequency. */
317 EXPORT int hal_power_dvfs_get_curr_freq(unsigned int res_type, char *res_name)
319 struct pass_resource_dvfs_ops *dvfs;
322 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
323 if (ret < 0 || !dvfs)
326 return exec_func(dvfs->get_curr_freq, res_name);
329 /* Get and set the minimum frequency. */
330 EXPORT int hal_power_dvfs_get_min_freq(unsigned int res_type, char *res_name)
332 struct pass_resource_dvfs_ops *dvfs;
335 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
336 if (ret < 0 || !dvfs)
339 return exec_func(dvfs->get_min_freq, res_name);
342 EXPORT int hal_power_dvfs_set_min_freq(unsigned int res_type, char *res_name, int freq)
344 struct pass_resource_dvfs_ops *dvfs;
350 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
351 if (ret < 0 || !dvfs)
354 return exec_func_with_int(dvfs->set_min_freq, res_name, freq);
357 /* Get and set the maximum frequency. */
358 EXPORT int hal_power_dvfs_get_max_freq(unsigned int res_type, char *res_name)
360 struct pass_resource_dvfs_ops *dvfs;
363 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
364 if (ret < 0 || !dvfs)
367 return exec_func(dvfs->get_max_freq, res_name);
370 EXPORT int hal_power_dvfs_set_max_freq(unsigned int res_type, char *res_name, int freq)
372 struct pass_resource_dvfs_ops *dvfs;
378 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
379 if (ret < 0 || !dvfs)
382 return exec_func_with_int(dvfs->set_max_freq, res_name, freq);
385 /* Get the minimum/maximum frequency which can be set to resource. */
386 EXPORT int hal_power_dvfs_get_available_min_freq(unsigned int res_type, char *res_name)
388 struct pass_resource_dvfs_ops *dvfs;
391 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
392 if (ret < 0 || !dvfs)
395 return exec_func(dvfs->get_available_min_freq, res_name);
398 EXPORT int hal_power_dvfs_get_available_max_freq(unsigned int res_type, char *res_name)
400 struct pass_resource_dvfs_ops *dvfs;
403 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
404 if (ret < 0 || !dvfs)
407 return exec_func(dvfs->get_available_max_freq, res_name);
410 /* Get and set the up_threshold to support boosting. */
411 EXPORT int hal_power_dvfs_get_up_threshold(unsigned int res_type, char *res_name)
413 struct pass_resource_dvfs_ops *dvfs;
416 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
417 if (ret < 0 || !dvfs)
420 return exec_func(dvfs->get_up_threshold, res_name);
423 EXPORT int hal_power_dvfs_set_up_threshold(unsigned int res_type, char *res_name, int up_threshold)
425 struct pass_resource_dvfs_ops *dvfs;
428 if (up_threshold < 0)
431 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
432 if (ret < 0 || !dvfs)
435 return exec_func_with_int(dvfs->set_up_threshold, res_name, up_threshold);
438 /* Get the load_table of each resource to estimate the system load. */
439 EXPORT int hal_power_dvfs_get_load_table(unsigned int res_type, char *res_name, void *pass_cpu_load_table)
441 struct pass_resource_dvfs_ops *dvfs;
444 ret = get_dvfs(g_power_funcs, res_type, res_name, &dvfs);
445 if (ret < 0 || !dvfs)
448 if (!dvfs->get_load_table)
451 return dvfs->get_load_table(res_name, pass_cpu_load_table);
455 * CPU Hotplug Operation for CPU H/W
457 /* Get and set the online status of resource. */
458 EXPORT int hal_power_hotplug_get_online_state(unsigned int res_type, char *res_name, int cpu)
460 struct pass_resource_hotplug_ops *hotplug;
466 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
467 if (ret < 0 || !hotplug)
470 return exec_func_with_int(hotplug->get_online_state, res_name, cpu);
473 EXPORT int hal_power_hotplug_set_online_state(unsigned int res_type, char *res_name, int cpu, int on)
475 struct pass_resource_hotplug_ops *hotplug;
478 if (cpu < 0 || on < 0)
481 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
482 if (ret < 0 || !hotplug)
485 if (!hotplug->set_online_state)
488 return hotplug->set_online_state(res_name, cpu, on);
491 /* Get and set the minimum number of online CPUs */
492 EXPORT int hal_power_hotplug_get_online_min_num(unsigned int res_type, char *res_name)
494 struct pass_resource_hotplug_ops *hotplug;
497 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
498 if (ret < 0 || !hotplug)
501 return exec_func(hotplug->get_online_min_num, res_name);
504 EXPORT int hal_power_hotplug_set_online_min_num(unsigned int res_type,
505 char *res_name, int min_num)
507 struct pass_resource_hotplug_ops *hotplug;
513 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
514 if (ret < 0 || !hotplug)
517 return exec_func_with_int(hotplug->set_online_min_num, res_name, min_num);
520 /* Get and set the maximum number of online CPUs */
521 EXPORT int hal_power_hotplug_get_online_max_num(unsigned int res_type,
524 struct pass_resource_hotplug_ops *hotplug;
527 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
528 if (ret < 0 || !hotplug)
531 return exec_func(hotplug->get_online_max_num, res_name);
534 EXPORT int hal_power_hotplug_set_online_max_num(unsigned int res_type,
535 char *res_name, int max_num)
537 struct pass_resource_hotplug_ops *hotplug;
543 ret = get_hotplug(g_power_funcs, res_type, res_name, &hotplug);
544 if (ret < 0 || !hotplug)
547 return exec_func_with_int(hotplug->set_online_max_num, res_name, max_num);
551 * Thermal Operation for CPU/BUS/GPU H/W
553 /* Get the current temperature of resource. */
554 EXPORT int hal_power_thermal_get_temp(unsigned int res_type,
555 char *res_thermal_name)
557 struct pass_resource_tmu_ops *tmu;
560 ret = get_tmu(g_power_funcs, res_type, res_thermal_name, &tmu);
565 * In the case of the HAL TMU ops, res_thermal_name is used
566 * as the first argument instead of res_name.
568 return exec_func(tmu->get_temp, res_thermal_name);
571 /* Get the policy of thermal management unit. */
572 EXPORT int hal_power_thermal_get_policy(unsigned int res_type,
573 char *res_thermal_name,
576 struct pass_resource_tmu_ops *tmu;
582 ret = get_tmu(g_power_funcs, res_type, res_thermal_name, &tmu);
587 * In the case of the HAL TMU ops, res_thermal_name is used
588 * as the first argument instead of res_name.
590 return exec_func_with_str(tmu->get_policy, res_thermal_name, policy);
593 /* Get and set the state of thermal cooling-device */
594 EXPORT int hal_power_thermal_set_cooling_device_state(unsigned int device_type,
595 char *cooling_device_name,
598 struct pass_resource_tmu_ops *tmu;
604 ret = get_tmu(g_power_funcs, device_type, cooling_device_name, &tmu);
609 * In the case of the HAL TMU ops, cooling_device_name is used
610 * as the first argument instead of res_name.
612 return exec_func_with_int(tmu->set_cooling_device_state, cooling_device_name, state);
615 EXPORT int hal_power_thermal_get_cooling_device_state(unsigned int device_type,
616 char *cooling_device_name)
618 struct pass_resource_tmu_ops *tmu;
621 ret= get_tmu(g_power_funcs, device_type, cooling_device_name, &tmu);
626 * In the case of the HAL TMU ops, cooling_device_name is used
627 * as the first argument instead of res_name.
629 return exec_func(tmu->get_cooling_device_state, cooling_device_name);
632 EXPORT int hal_power_thermal_get_cooling_device_max_state(unsigned int device_type,
633 char *cooling_device_name)
635 struct pass_resource_tmu_ops *tmu;
638 ret = get_tmu(g_power_funcs, device_type, cooling_device_name, &tmu);
643 * In the case of the HAL TMU ops, cooling_device_name is used
644 * as the first argument instead of res_name.
646 return exec_func(tmu->get_cooling_device_max_state, cooling_device_name);
649 EXPORT int hal_power_battery_set_charging_status(unsigned int device_type,
653 struct pass_resource_battery_ops *charging;
659 ret = get_charging(g_power_funcs, device_type, res_name, &charging);
660 if (ret < 0 || !charging)
663 return exec_func_with_int(charging->set_charging_status, res_name, state);
666 EXPORT int hal_power_battery_get_charging_status(unsigned int device_type,
669 struct pass_resource_battery_ops *charging;
672 ret = get_charging(g_power_funcs, device_type, res_name, &charging);
673 if (ret < 0 || !charging)
676 return exec_func(charging->get_charging_status, res_name);
679 EXPORT int hal_power_battery_set_charging_current(unsigned int device_type,
681 int charing_current_uA)
683 struct pass_resource_battery_ops *charging;
686 if (charing_current_uA < 0)
689 ret = get_charging(g_power_funcs, device_type, res_name, &charging);
690 if (ret < 0 || !charging)
693 return exec_func_with_int(charging->set_charging_current, res_name, charing_current_uA);
696 EXPORT int hal_power_battery_get_charging_current(unsigned int device_type,
699 struct pass_resource_battery_ops *charging;
702 ret = get_charging(g_power_funcs, device_type, res_name, &charging);
703 if (ret < 0 || !charging)
706 return exec_func(charging->get_charging_current, res_name);
710 * Memory Operation for Memory H/W
712 /* Get and set the /sys/kernel/debug/fault_around_bytes */
713 EXPORT int hal_power_memory_get_fault_around_bytes(unsigned int res_type,
716 struct pass_resource_memory *memory;
723 case PASS_RESOURCE_MEMORY_ID:
724 memory = g_power_funcs->memory;
730 return exec_func(memory->get_fault_around_bytes, res_name);
733 EXPORT int hal_power_memory_set_fault_around_bytes(unsigned int res_type,
735 int fault_around_bytes)
737 struct pass_resource_memory *memory;
740 ret = is_valid_param_with_int(res_name, fault_around_bytes);
745 * fault_around_bytes should be multiply of page size in order to
746 * prevent the confusion of user. Even if user uses any integer value,
747 * the entered fauled_around_bytes value is rounded by kernel and then
748 * use it. In order to clarify the usage of fauld_around_bytes,
749 * limit the range of value.
751 if (fault_around_bytes == 0 || (fault_around_bytes % FAULT_AROUND_BYTES_4K))
755 case PASS_RESOURCE_MEMORY_ID:
756 memory = g_power_funcs->memory;
762 return exec_func_with_int(memory->set_fault_around_bytes, res_name, fault_around_bytes);
766 * Miscellaneous Operation for CPU/BUS/GPU H/W
769 * NOTE: It is not propper method. But PASS must need to keep
770 * the backwards compatibility, set the PMQoS's data from
771 * platform to hal. So, It is not recommended to use it.
773 * This function will be removed after finding the proper method.
775 EXPORT int hal_power_misc_set_pmqos_data(unsigned int res_type,
776 char *res_name, void *data)
778 struct pass_resource_nonstandard *nonstandard = NULL;
783 if (!res_name || !data)
787 case PASS_RESOURCE_NONSTANDARD_ID:
788 nonstandard = g_power_funcs->nonstandard;
794 if (!nonstandard->set_pmqos_data)
797 return nonstandard->set_pmqos_data(res_name, data);