ath79/mikrotik: use routerbootpart partitions
[oweals/openwrt.git] / target / linux / layerscape / patches-5.4 / 818-thermal-0001-thermal-Add-generic-device-cooling-support.patch
1 From 97abcfc5219149ff7d4883b295c80257f0315b5e Mon Sep 17 00:00:00 2001
2 From: Anson Huang <Anson.Huang@nxp.com>
3 Date: Wed, 7 Aug 2019 08:40:59 +0800
4 Subject: [PATCH] thermal: Add generic device cooling support
5
6 To compatible with previous implementation, add generic device
7 cooling support, each thermal zone will register a cooling
8 device, and when temperature exceed passive trip, the device
9 cooling driver will send out a system wide notification, each
10 device supporting cooling will need to register device cooling
11 and takes action when passive trip is exceeded;
12
13 Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
14 [rebase]
15 Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
16 ---
17  drivers/thermal/Kconfig          |   7 ++
18  drivers/thermal/Makefile         |   1 +
19  drivers/thermal/device_cooling.c | 152 +++++++++++++++++++++++++++++++++++++++
20  include/linux/device_cooling.h   |  45 ++++++++++++
21  4 files changed, 205 insertions(+)
22  create mode 100644 drivers/thermal/device_cooling.c
23  create mode 100644 include/linux/device_cooling.h
24
25 --- a/drivers/thermal/Kconfig
26 +++ b/drivers/thermal/Kconfig
27 @@ -233,6 +233,13 @@ config IMX_THERMAL
28           cpufreq is used as the cooling device to throttle CPUs when the
29           passive trip is crossed.
30  
31 +config DEVICE_THERMAL
32 +       tristate "generic device cooling support"
33 +       help
34 +         Support for device cooling.
35 +         It supports notification of crossing passive trip for devices,
36 +         devices need to do their own actions to cool down the SOC.
37 +
38  config MAX77620_THERMAL
39         tristate "Temperature sensor driver for Maxim MAX77620 PMIC"
40         depends on MFD_MAX77620
41 --- a/drivers/thermal/Makefile
42 +++ b/drivers/thermal/Makefile
43 @@ -41,6 +41,7 @@ obj-$(CONFIG_DB8500_THERMAL)  += db8500_t
44  obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
45  obj-$(CONFIG_TANGO_THERMAL)    += tango_thermal.o
46  obj-$(CONFIG_IMX_THERMAL)      += imx_thermal.o
47 +obj-$(CONFIG_DEVICE_THERMAL)   += device_cooling.o
48  obj-$(CONFIG_MAX77620_THERMAL) += max77620_thermal.o
49  obj-$(CONFIG_QORIQ_THERMAL)    += qoriq_thermal.o
50  obj-$(CONFIG_DA9062_THERMAL)   += da9062-thermal.o
51 --- /dev/null
52 +++ b/drivers/thermal/device_cooling.c
53 @@ -0,0 +1,152 @@
54 +/*
55 + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
56 + *
57 + * This program is free software; you can redistribute it and/or modify
58 + * it under the terms of the GNU General Public License version 2 as
59 + * published by the Free Software Foundation.
60 + *
61 + */
62 +
63 +#include <linux/module.h>
64 +#include <linux/thermal.h>
65 +#include <linux/err.h>
66 +#include <linux/slab.h>
67 +
68 +struct devfreq_cooling_device {
69 +       int id;
70 +       struct thermal_cooling_device *cool_dev;
71 +       unsigned int devfreq_state;
72 +};
73 +
74 +static DEFINE_IDR(devfreq_idr);
75 +static DEFINE_MUTEX(devfreq_cooling_lock);
76 +
77 +#define        MAX_STATE       1
78 +
79 +static BLOCKING_NOTIFIER_HEAD(devfreq_cooling_chain_head);
80 +
81 +int register_devfreq_cooling_notifier(struct notifier_block *nb)
82 +{
83 +       return blocking_notifier_chain_register(
84 +               &devfreq_cooling_chain_head, nb);
85 +}
86 +EXPORT_SYMBOL_GPL(register_devfreq_cooling_notifier);
87 +
88 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
89 +{
90 +       return blocking_notifier_chain_unregister(
91 +               &devfreq_cooling_chain_head, nb);
92 +}
93 +EXPORT_SYMBOL_GPL(unregister_devfreq_cooling_notifier);
94 +
95 +static int devfreq_cooling_notifier_call_chain(unsigned long val)
96 +{
97 +       return (blocking_notifier_call_chain(
98 +               &devfreq_cooling_chain_head, val, NULL)
99 +               == NOTIFY_BAD) ? -EINVAL : 0;
100 +}
101 +
102 +static int devfreq_set_cur_state(struct thermal_cooling_device *cdev,
103 +                                unsigned long state)
104 +{
105 +       struct devfreq_cooling_device *devfreq_device = cdev->devdata;
106 +       int ret;
107 +
108 +       ret = devfreq_cooling_notifier_call_chain(state);
109 +       if (ret)
110 +               return -EINVAL;
111 +
112 +       devfreq_device->devfreq_state = state;
113 +
114 +       return 0;
115 +}
116 +
117 +static int devfreq_get_max_state(struct thermal_cooling_device *cdev,
118 +                                unsigned long *state)
119 +{
120 +       *state = MAX_STATE;
121 +
122 +       return 0;
123 +}
124 +
125 +static int devfreq_get_cur_state(struct thermal_cooling_device *cdev,
126 +                                unsigned long *state)
127 +{
128 +       struct devfreq_cooling_device *devfreq_device = cdev->devdata;
129 +
130 +       *state = devfreq_device->devfreq_state;
131 +
132 +       return 0;
133 +}
134 +
135 +static struct thermal_cooling_device_ops const devfreq_cooling_ops = {
136 +       .get_max_state = devfreq_get_max_state,
137 +       .get_cur_state = devfreq_get_cur_state,
138 +       .set_cur_state = devfreq_set_cur_state,
139 +};
140 +
141 +static int get_idr(struct idr *idr, int *id)
142 +{
143 +       int ret;
144 +
145 +       mutex_lock(&devfreq_cooling_lock);
146 +       ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
147 +       mutex_unlock(&devfreq_cooling_lock);
148 +       if (unlikely(ret < 0))
149 +               return ret;
150 +       *id = ret;
151 +
152 +       return 0;
153 +}
154 +
155 +static void release_idr(struct idr *idr, int id)
156 +{
157 +       mutex_lock(&devfreq_cooling_lock);
158 +       idr_remove(idr, id);
159 +       mutex_unlock(&devfreq_cooling_lock);
160 +}
161 +
162 +struct thermal_cooling_device *devfreq_cooling_register(void)
163 +{
164 +       struct thermal_cooling_device *cool_dev;
165 +       struct devfreq_cooling_device *devfreq_dev = NULL;
166 +       char dev_name[THERMAL_NAME_LENGTH];
167 +       int ret = 0;
168 +
169 +       devfreq_dev = kzalloc(sizeof(struct devfreq_cooling_device),
170 +                             GFP_KERNEL);
171 +       if (!devfreq_dev)
172 +               return ERR_PTR(-ENOMEM);
173 +
174 +       ret = get_idr(&devfreq_idr, &devfreq_dev->id);
175 +       if (ret) {
176 +               kfree(devfreq_dev);
177 +               return ERR_PTR(-EINVAL);
178 +       }
179 +
180 +       snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d",
181 +                devfreq_dev->id);
182 +
183 +       cool_dev = thermal_cooling_device_register(dev_name, devfreq_dev,
184 +                                                  &devfreq_cooling_ops);
185 +       if (!cool_dev) {
186 +               release_idr(&devfreq_idr, devfreq_dev->id);
187 +               kfree(devfreq_dev);
188 +               return ERR_PTR(-EINVAL);
189 +       }
190 +       devfreq_dev->cool_dev = cool_dev;
191 +       devfreq_dev->devfreq_state = 0;
192 +
193 +       return cool_dev;
194 +}
195 +EXPORT_SYMBOL_GPL(devfreq_cooling_register);
196 +
197 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
198 +{
199 +       struct devfreq_cooling_device *devfreq_dev = cdev->devdata;
200 +
201 +       thermal_cooling_device_unregister(devfreq_dev->cool_dev);
202 +       release_idr(&devfreq_idr, devfreq_dev->id);
203 +       kfree(devfreq_dev);
204 +}
205 +EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
206 --- /dev/null
207 +++ b/include/linux/device_cooling.h
208 @@ -0,0 +1,45 @@
209 +/*
210 + * Copyright (C) 2013-2015 Freescale Semiconductor, Inc.
211 + *
212 + * This program is free software; you can redistribute it and/or modify
213 + * it under the terms of the GNU General Public License version 2 as
214 + * published by the Free Software Foundation.
215 + *
216 + */
217 +
218 +#ifndef __DEVICE_THERMAL_H__
219 +#define __DEVICE_THERMAL_H__
220 +
221 +#include <linux/thermal.h>
222 +
223 +#ifdef CONFIG_DEVICE_THERMAL
224 +int register_devfreq_cooling_notifier(struct notifier_block *nb);
225 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb);
226 +struct thermal_cooling_device *devfreq_cooling_register(void);
227 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev);
228 +#else
229 +static inline
230 +int register_devfreq_cooling_notifier(struct notifier_block *nb)
231 +{
232 +       return 0;
233 +}
234 +
235 +static inline
236 +int unregister_devfreq_cooling_notifier(struct notifier_block *nb)
237 +{
238 +       return 0;
239 +}
240 +
241 +static inline
242 +struct thermal_cooling_device *devfreq_cooling_register(void)
243 +{
244 +       return NULL;
245 +}
246 +
247 +static inline
248 +void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
249 +{
250 +       return;
251 +}
252 +#endif
253 +#endif /* __DEVICE_THERMAL_H__ */