diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 568c762edd..148a5fe08a 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -17,4 +17,10 @@ config THERMAL_DEFAULT_GOVERNOR ---help--- Default governor name. +config THERMAL_GOVERNOR_STEP_WISE + bool "Enable step wise governor" + default y + ---help--- + Enable step wise governor. + endif # THERMAL diff --git a/drivers/thermal/Make.defs b/drivers/thermal/Make.defs index 20c8c4f054..be098588d5 100644 --- a/drivers/thermal/Make.defs +++ b/drivers/thermal/Make.defs @@ -24,6 +24,10 @@ ifeq ($(CONFIG_THERMAL),y) CSRCS += thermal_core.c +ifeq ($(CONFIG_THERMAL_GOVERNOR_STEP_WISE),y) +CSRCS += thermal_step_wise.c +endif + DEPPATH += --dep-path thermal VPATH += thermal diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index a7de5fc86c..fe4d03de8c 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -839,5 +839,14 @@ int thermal_init(void) { int ret = OK; +#ifdef CONFIG_THERMAL_GOVERNOR_STEP_WISE + ret = thermal_register_step_wise_governor(); + if (ret < 0) + { + therr("Register step wise governor failed!\n"); + return ret; + } +#endif + return ret; } diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 3ea97df9db..d55eff4530 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -73,4 +73,8 @@ int thermal_zone_get_trip_hyst(FAR struct thermal_zone_device_s *zdev, int trip, FAR int *hyst); +/* Governor */ + +int thermal_register_step_wise_governor(void); + #endif /* __DRIVERS_THERMAL_THERMAL_CORE_H */ diff --git a/drivers/thermal/thermal_step_wise.c b/drivers/thermal/thermal_step_wise.c new file mode 100644 index 0000000000..283f782267 --- /dev/null +++ b/drivers/thermal/thermal_step_wise.c @@ -0,0 +1,182 @@ +/**************************************************************************** + * drivers/thermal/thermal_step_wise.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 "thermal_core.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static unsigned int get_target_state(FAR struct thermal_instance_s *instance, + enum thermal_trend_e trend, + bool throttle); +static int step_wise_throttle(FAR struct thermal_zone_device_s *zdev, + int trip); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct thermal_governor_s g_step_wise_governor = +{ + .name = "step_wise", + .throttle = step_wise_throttle, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline unsigned int +validate_state(FAR struct thermal_instance_s *instance, bool throttle, + unsigned int state, int value) +{ + if ((state == THERMAL_TARGET_MIN && value == -1) || + (state == THERMAL_TARGET_MAX && value == 1)) + { + value = 0; + } + + if (state == THERMAL_NO_TARGET) + { + state = 0; + } + + state += value; + + if (state > instance->upper) + { + state = instance->upper; + } + else if(state < instance->lower && throttle) + { + state = instance->lower; + } + + return state; +} + +static unsigned int get_target_state(FAR struct thermal_instance_s *instance, + enum thermal_trend_e trend, + bool throttle) +{ + FAR struct thermal_cooling_device_s *cdev = instance->cdev; + unsigned int next_state = THERMAL_NO_TARGET; + unsigned int cur_state = instance->target; + + if (!cdev->ops || !cdev->ops->get_state) + { + return next_state; + } + + if (cur_state == THERMAL_NO_TARGET) + { + if (throttle) + { + next_state = validate_state(instance, throttle, cur_state, 1); + } + + return next_state; + } + + /* Update Cooling State */ + + switch (trend) + { + case THERMAL_TREND_RAISING: + if (throttle) + { + next_state = validate_state(instance, throttle, cur_state, 1); + } + break; + + case THERMAL_TREND_DROPPING: + if (!throttle) + { + next_state = validate_state(instance, throttle, cur_state, -1); + } + break; + + case THERMAL_TREND_STABLE: + break; + + default: + break; + } + + return next_state; +} + +/* step_wise */ + +static int step_wise_throttle(FAR struct thermal_zone_device_s *zdev, + int trip) +{ + FAR struct thermal_instance_s *instance; + enum thermal_trend_e trend; + unsigned int next_state; + bool throttle = false; + int trip_temp; + + thermal_zone_get_trip_temp(zdev, trip, &trip_temp); + + trend = thermal_zone_get_trend(zdev); + + if (zdev->temperature > trip_temp) + { + throttle = true; + } + + list_for_every_entry(&zdev->instance_list, instance, + struct thermal_instance_s, zdev_node) + { + if (instance->trip != trip) + { + continue; + } + + next_state = get_target_state(instance, trend, throttle); + + if (next_state == THERMAL_NO_TARGET || next_state == instance->target) + { + continue; + } + + instance->target = next_state; + thermal_cooling_device_update(instance->cdev); + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int thermal_register_step_wise_governor(void) +{ + return thermal_register_governor(&g_step_wise_governor); +}