diff options
Diffstat (limited to 'target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch')
-rw-r--r-- | target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch b/target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch new file mode 100644 index 0000000000..f947eb6e32 --- /dev/null +++ b/target/linux/layerscape/patches-5.4/818-thermal-0001-thermal-Add-generic-device-cooling-support.patch @@ -0,0 +1,253 @@ +From 97abcfc5219149ff7d4883b295c80257f0315b5e Mon Sep 17 00:00:00 2001 +From: Anson Huang <Anson.Huang@nxp.com> +Date: Wed, 7 Aug 2019 08:40:59 +0800 +Subject: [PATCH] thermal: Add generic device cooling support + +To compatible with previous implementation, add generic device +cooling support, each thermal zone will register a cooling +device, and when temperature exceed passive trip, the device +cooling driver will send out a system wide notification, each +device supporting cooling will need to register device cooling +and takes action when passive trip is exceeded; + +Signed-off-by: Anson Huang <Anson.Huang@nxp.com> +[rebase] +Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com> +--- + drivers/thermal/Kconfig | 7 ++ + drivers/thermal/Makefile | 1 + + drivers/thermal/device_cooling.c | 152 +++++++++++++++++++++++++++++++++++++++ + include/linux/device_cooling.h | 45 ++++++++++++ + 4 files changed, 205 insertions(+) + create mode 100644 drivers/thermal/device_cooling.c + create mode 100644 include/linux/device_cooling.h + +--- a/drivers/thermal/Kconfig ++++ b/drivers/thermal/Kconfig +@@ -233,6 +233,13 @@ config IMX_THERMAL + cpufreq is used as the cooling device to throttle CPUs when the + passive trip is crossed. + ++config DEVICE_THERMAL ++ tristate "generic device cooling support" ++ help ++ Support for device cooling. ++ It supports notification of crossing passive trip for devices, ++ devices need to do their own actions to cool down the SOC. ++ + config MAX77620_THERMAL + tristate "Temperature sensor driver for Maxim MAX77620 PMIC" + depends on MFD_MAX77620 +--- a/drivers/thermal/Makefile ++++ b/drivers/thermal/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_DB8500_THERMAL) += db8500_t + obj-$(CONFIG_ARMADA_THERMAL) += armada_thermal.o + obj-$(CONFIG_TANGO_THERMAL) += tango_thermal.o + obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o ++obj-$(CONFIG_DEVICE_THERMAL) += device_cooling.o + obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o + obj-$(CONFIG_QORIQ_THERMAL) += qoriq_thermal.o + obj-$(CONFIG_DA9062_THERMAL) += da9062-thermal.o +--- /dev/null ++++ b/drivers/thermal/device_cooling.c +@@ -0,0 +1,152 @@ ++/* ++ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#include <linux/module.h> ++#include <linux/thermal.h> ++#include <linux/err.h> ++#include <linux/slab.h> ++ ++struct devfreq_cooling_device { ++ int id; ++ struct thermal_cooling_device *cool_dev; ++ unsigned int devfreq_state; ++}; ++ ++static DEFINE_IDR(devfreq_idr); ++static DEFINE_MUTEX(devfreq_cooling_lock); ++ ++#define MAX_STATE 1 ++ ++static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head); ++ ++int register_devfreq_cooling_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_register( ++ &devfreq_cooling_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier); ++ ++int unregister_devfreq_cooling_notifier(struct notifier_block *nb) ++{ ++ return blocking_notifier_chain_unregister( ++ &devfreq_cooling_chain_head, nb); ++} ++EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier); ++ ++static int devfreq_cooling_notifier_call_chain(unsigned long val) ++{ ++ return (blocking_notifier_call_chain( ++ &devfreq_cooling_chain_head, val, NULL) ++ == NOTIFY_BAD) ? -EINVAL : 0; ++} ++ ++static int devfreq_set_cur_state(struct thermal_cooling_device *cdev, ++ unsigned long state) ++{ ++ struct devfreq_cooling_device *devfreq_device = cdev->devdata; ++ int ret; ++ ++ ret = devfreq_cooling_notifier_call_chain(state); ++ if (ret) ++ return -EINVAL; ++ ++ devfreq_device->devfreq_state = state; ++ ++ return 0; ++} ++ ++static int devfreq_get_max_state(struct thermal_cooling_device *cdev, ++ unsigned long *state) ++{ ++ *state = MAX_STATE; ++ ++ return 0; ++} ++ ++static int devfreq_get_cur_state(struct thermal_cooling_device *cdev, ++ unsigned long *state) ++{ ++ struct devfreq_cooling_device *devfreq_device = cdev->devdata; ++ ++ *state = devfreq_device->devfreq_state; ++ ++ return 0; ++} ++ ++static struct thermal_cooling_device_ops const devfreq_cooling_ops = { ++ .get_max_state = devfreq_get_max_state, ++ .get_cur_state = devfreq_get_cur_state, ++ .set_cur_state = devfreq_set_cur_state, ++}; ++ ++static int get_idr(struct idr *idr, int *id) ++{ ++ int ret; ++ ++ mutex_lock(&devfreq_cooling_lock); ++ ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL); ++ mutex_unlock(&devfreq_cooling_lock); ++ if (unlikely(ret < 0)) ++ return ret; ++ *id = ret; ++ ++ return 0; ++} ++ ++static void release_idr(struct idr *idr, int id) ++{ ++ mutex_lock(&devfreq_cooling_lock); ++ idr_remove(idr, id); ++ mutex_unlock(&devfreq_cooling_lock); ++} ++ ++struct thermal_cooling_device *devfreq_cooling_register(void) ++{ ++ struct thermal_cooling_device *cool_dev; ++ struct devfreq_cooling_device *devfreq_dev = NULL; ++ char dev_name[THERMAL_NAME_LENGTH]; ++ int ret = 0; ++ ++ devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device), ++ GFP_KERNEL); ++ if (!devfreq_dev) ++ return ERR_PTR(-ENOMEM); ++ ++ ret = get_idr(&devfreq_idr, &devfreq_dev->id); ++ if (ret) { ++ kfree(devfreq_dev); ++ return ERR_PTR(-EINVAL); ++ } ++ ++ snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", ++ devfreq_dev->id); ++ ++ cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev, ++ &devfreq_cooling_ops); ++ if (!cool_dev) { ++ release_idr(&devfreq_idr, devfreq_dev->id); ++ kfree(devfreq_dev); ++ return ERR_PTR(-EINVAL); ++ } ++ devfreq_dev->cool_dev = cool_dev; ++ devfreq_dev->devfreq_state = 0; ++ ++ return cool_dev; ++} ++EXPORT_SYMBOL_GPL(devfreq_cooling_register); ++ ++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) ++{ ++ struct devfreq_cooling_device *devfreq_dev = cdev->devdata; ++ ++ thermal_cooling_device_unregister(devfreq_dev->cool_dev); ++ release_idr(&devfreq_idr, devfreq_dev->id); ++ kfree(devfreq_dev); ++} ++EXPORT_SYMBOL_GPL(devfreq_cooling_unregister); +--- /dev/null ++++ b/include/linux/device_cooling.h +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ */ ++ ++#ifndef __DEVICE_THERMAL_H__ ++#define __DEVICE_THERMAL_H__ ++ ++#include <linux/thermal.h> ++ ++#ifdef CONFIG_DEVICE_THERMAL ++int register_devfreq_cooling_notifier(struct notifier_block *nb); ++int unregister_devfreq_cooling_notifier(struct notifier_block *nb); ++struct thermal_cooling_device *devfreq_cooling_register(void); ++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev); ++#else ++static inline ++int register_devfreq_cooling_notifier(struct notifier_block *nb) ++{ ++ return 0; ++} ++ ++static inline ++int unregister_devfreq_cooling_notifier(struct notifier_block *nb) ++{ ++ return 0; ++} ++ ++static inline ++struct thermal_cooling_device *devfreq_cooling_register(void) ++{ ++ return NULL; ++} ++ ++static inline ++void devfreq_cooling_unregister(struct thermal_cooling_device *cdev) ++{ ++ return; ++} ++#endif ++#endif /* __DEVICE_THERMAL_H__ */ |