From 2f285a04f97d5e221192e403b3dc2c7a805be1c0 Mon Sep 17 00:00:00 2001 From: wangjianyu3 Date: Tue, 7 Nov 2023 20:09:01 +0800 Subject: [PATCH] Thermal: Support cpufreq cooling device Signed-off-by: wangjianyu3 --- drivers/thermal/Kconfig | 7 + drivers/thermal/Make.defs | 4 + drivers/thermal/thermal_core.c | 7 + drivers/thermal/thermal_core.h | 5 + drivers/thermal/thermal_cpufreq_cooling.c | 234 ++++++++++++++++++++++ 5 files changed, 257 insertions(+) create mode 100644 drivers/thermal/thermal_cpufreq_cooling.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 148a5fe08a..d02327b6eb 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -23,4 +23,11 @@ config THERMAL_GOVERNOR_STEP_WISE ---help--- Enable step wise governor. +config THERMAL_CDEV_CPUFREQ + bool "Thermal cpufreq cooling device" + default n + depends on CPUFREQ + ---help--- + Enable thermal cpufreq cooling device. + endif # THERMAL diff --git a/drivers/thermal/Make.defs b/drivers/thermal/Make.defs index be098588d5..fe2e806860 100644 --- a/drivers/thermal/Make.defs +++ b/drivers/thermal/Make.defs @@ -28,6 +28,10 @@ ifeq ($(CONFIG_THERMAL_GOVERNOR_STEP_WISE),y) CSRCS += thermal_step_wise.c endif +ifeq ($(CONFIG_THERMAL_CDEV_CPUFREQ),y) +CSRCS += thermal_cpufreq_cooling.c +endif + DEPPATH += --dep-path thermal VPATH += thermal diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index fe4d03de8c..221260a733 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -848,5 +848,12 @@ int thermal_init(void) } #endif +#ifdef CONFIG_THERMAL_CDEV_CPUFREQ + if (NULL == thermal_cpufreq_cooling_register()) + { + return -ENOTSUP; + } +#endif + return ret; } diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index d55eff4530..46537dff7d 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -57,6 +57,11 @@ struct thermal_instance_s void thermal_cooling_device_update (FAR struct thermal_cooling_device_s *cdev); +#ifdef CONFIG_THERMAL_CDEV_CPUFREQ +FAR struct thermal_cooling_device_s *thermal_cpufreq_cooling_register(void); +void thermal_cpufreq_cooling_unregister( + FAR struct thermal_cooling_device_s *cdev); +#endif /* CONFIG_THERMAL_CDEV_CPUFREQ */ /* Zone Device */ diff --git a/drivers/thermal/thermal_cpufreq_cooling.c b/drivers/thermal/thermal_cpufreq_cooling.c new file mode 100644 index 0000000000..dd826fbd09 --- /dev/null +++ b/drivers/thermal/thermal_cpufreq_cooling.c @@ -0,0 +1,234 @@ +/**************************************************************************** + * drivers/thermal/thermal_cpufreq_cooling.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "thermal_core.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct cpufreq_cooling_device_s +{ + FAR const struct cpufreq_frequency_table *table; + FAR struct cpufreq_policy *policy; + FAR struct cpufreq_qos *qos; + unsigned int cur_state; + unsigned int max_state; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int cpufreq_get_max_state(FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state); +static int cpufreq_get_state (FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state); +static int cpufreq_set_state (FAR struct thermal_cooling_device_s *cdev, + unsigned int state); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct thermal_cooling_device_ops_s g_cpufreq_cdev_ops = +{ + .set_state = cpufreq_set_state, + .get_state = cpufreq_get_state, + .get_max_state = cpufreq_get_max_state, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int cpufreq_get_max_state(FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state) +{ + struct cpufreq_cooling_device_s *cpufreq_cdev = cdev->devdata; + + *state = cpufreq_cdev->max_state; + return OK; +} + +static int cpufreq_get_state(FAR struct thermal_cooling_device_s *cdev, + FAR unsigned int *state) +{ + struct cpufreq_cooling_device_s *cpufreq_cdev = cdev->devdata; + + *state = cpufreq_cdev->cur_state; + return OK; +} + +static int cpufreq_set_state(FAR struct thermal_cooling_device_s *cdev, + unsigned int state) +{ + struct cpufreq_cooling_device_s *cpufreq_cdev = cdev->devdata; + unsigned int index = cpufreq_cdev->max_state - state; + int ret; + + thinfo("CPU Freq cooling %u %u \n", + cpufreq_cdev->table[index].frequency, + cpufreq_cdev->table[index + 1].frequency); + + if (cpufreq_cdev->qos == NULL) + { + cpufreq_cdev->qos = cpufreq_qos_add_request( + cpufreq_cdev->policy, + cpufreq_cdev->table[index].frequency, + cpufreq_cdev->table[index + 1].frequency); + if (!cpufreq_cdev->qos) + { + therr("Add qos request failed!"); + return -EINVAL; + } + } + else + { + ret = cpufreq_qos_update_request( + cpufreq_cdev->qos, + cpufreq_cdev->table[index].frequency, + cpufreq_cdev->table[index + 1].frequency); + if (ret < 0) + { + therr("Update qos request failed!"); + return ret; + } + } + + cpufreq_cdev->cur_state = state; + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: thermal_cpufreq_cooling_register + * + * Description: + * Register cpufreq cooling device + * + * Input Parameters: + * policy - cpufreq policy + * + * Returned Value: + * Addr of created cooling device entry + ****************************************************************************/ + +FAR struct thermal_cooling_device_s *thermal_cpufreq_cooling_register(void) +{ + FAR struct cpufreq_cooling_device_s *cpufreq_cdev; + FAR const struct cpufreq_frequency_table *table; + FAR struct thermal_cooling_device_s *cdev; + FAR struct cpufreq_driver **driver; + FAR struct cpufreq_policy *policy; + unsigned int count; + + policy = cpufreq_policy_get(); + if (policy == NULL) + { + therr("Get cpufreq policy failed!\n"); + return NULL; + } + + driver = (FAR struct cpufreq_driver **)policy; + + table = (*driver)->get_table(policy); + if (table == NULL) + { + therr("Get cpufreq table failed!\n"); + return NULL; + } + + for (count = 0; table[count].frequency != CPUFREQ_TABLE_END; count++) + { + } + + if (count < 2) + { + therr("Invalid cpufreq table!\n"); + return NULL; + } + + cpufreq_cdev = kmm_zalloc(sizeof(*cpufreq_cdev)); + if (cpufreq_cdev == NULL) + { + therr("No memory for cpufreq cooling device registering!\n"); + return NULL; + } + + cpufreq_cdev->table = table; + cpufreq_cdev->policy = policy; + cpufreq_cdev->max_state = count - 2; + thinfo("max level of cpufreq is %d \n", cpufreq_cdev->max_state); + + cdev = thermal_cooling_device_register("cpufreq", cpufreq_cdev, + &g_cpufreq_cdev_ops); + if (cdev == NULL) + { + kmm_free(cpufreq_cdev); + } + + return cdev; +} + +/**************************************************************************** + * Name: thermal_cpufreq_cooling_unregister + * + * Description: + * Unregister cpufreq cooling device + * + * Input Parameters: + * cdev - Addr of cpufre cooling devcie entry + * + * Returned Value: + * None + ****************************************************************************/ + +void +thermal_cpufreq_cooling_unregister(FAR struct thermal_cooling_device_s *cdev) +{ + struct cpufreq_cooling_device_s *cpufreq_cdev; + int ret; + + cpufreq_cdev = cdev->devdata; + + if (cpufreq_cdev->qos) + { + ret = cpufreq_qos_remove_request(cpufreq_cdev->qos); + if (ret < 0) + { + thinfo("ret=%d\n", ret); + therr("Remove cpufreq qos failed!\n"); + } + } + + thermal_cooling_device_unregister(cdev); + kmm_free(cpufreq_cdev); +}