]> Git Repo - linux.git/blob - drivers/gpu/drm/panthor/panthor_devfreq.c
Merge tag 'linux-watchdog-6.14-rc1' of git://www.linux-watchdog.org/linux-watchdog
[linux.git] / drivers / gpu / drm / panthor / panthor_devfreq.c
1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 /* Copyright 2019 Collabora ltd. */
3
4 #include <linux/clk.h>
5 #include <linux/devfreq.h>
6 #include <linux/devfreq_cooling.h>
7 #include <linux/platform_device.h>
8 #include <linux/pm_opp.h>
9
10 #include <drm/drm_managed.h>
11
12 #include "panthor_devfreq.h"
13 #include "panthor_device.h"
14
15 /**
16  * struct panthor_devfreq - Device frequency management
17  */
18 struct panthor_devfreq {
19         /** @devfreq: devfreq device. */
20         struct devfreq *devfreq;
21
22         /** @gov_data: Governor data. */
23         struct devfreq_simple_ondemand_data gov_data;
24
25         /** @busy_time: Busy time. */
26         ktime_t busy_time;
27
28         /** @idle_time: Idle time. */
29         ktime_t idle_time;
30
31         /** @time_last_update: Last update time. */
32         ktime_t time_last_update;
33
34         /** @last_busy_state: True if the GPU was busy last time we updated the state. */
35         bool last_busy_state;
36
37         /**
38          * @lock: Lock used to protect busy_time, idle_time, time_last_update and
39          * last_busy_state.
40          *
41          * These fields can be accessed concurrently by panthor_devfreq_get_dev_status()
42          * and panthor_devfreq_record_{busy,idle}().
43          */
44         spinlock_t lock;
45 };
46
47 static void panthor_devfreq_update_utilization(struct panthor_devfreq *pdevfreq)
48 {
49         ktime_t now, last;
50
51         now = ktime_get();
52         last = pdevfreq->time_last_update;
53
54         if (pdevfreq->last_busy_state)
55                 pdevfreq->busy_time += ktime_sub(now, last);
56         else
57                 pdevfreq->idle_time += ktime_sub(now, last);
58
59         pdevfreq->time_last_update = now;
60 }
61
62 static int panthor_devfreq_target(struct device *dev, unsigned long *freq,
63                                   u32 flags)
64 {
65         struct panthor_device *ptdev = dev_get_drvdata(dev);
66         struct dev_pm_opp *opp;
67         int err;
68
69         opp = devfreq_recommended_opp(dev, freq, flags);
70         if (IS_ERR(opp))
71                 return PTR_ERR(opp);
72         dev_pm_opp_put(opp);
73
74         err = dev_pm_opp_set_rate(dev, *freq);
75         if (!err)
76                 ptdev->current_frequency = *freq;
77
78         return err;
79 }
80
81 static void panthor_devfreq_reset(struct panthor_devfreq *pdevfreq)
82 {
83         pdevfreq->busy_time = 0;
84         pdevfreq->idle_time = 0;
85         pdevfreq->time_last_update = ktime_get();
86 }
87
88 static int panthor_devfreq_get_dev_status(struct device *dev,
89                                           struct devfreq_dev_status *status)
90 {
91         struct panthor_device *ptdev = dev_get_drvdata(dev);
92         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
93         unsigned long irqflags;
94
95         status->current_frequency = clk_get_rate(ptdev->clks.core);
96
97         spin_lock_irqsave(&pdevfreq->lock, irqflags);
98
99         panthor_devfreq_update_utilization(pdevfreq);
100
101         status->total_time = ktime_to_ns(ktime_add(pdevfreq->busy_time,
102                                                    pdevfreq->idle_time));
103
104         status->busy_time = ktime_to_ns(pdevfreq->busy_time);
105
106         panthor_devfreq_reset(pdevfreq);
107
108         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
109
110         drm_dbg(&ptdev->base, "busy %lu total %lu %lu %% freq %lu MHz\n",
111                 status->busy_time, status->total_time,
112                 status->busy_time / (status->total_time / 100),
113                 status->current_frequency / 1000 / 1000);
114
115         return 0;
116 }
117
118 static struct devfreq_dev_profile panthor_devfreq_profile = {
119         .timer = DEVFREQ_TIMER_DELAYED,
120         .polling_ms = 50, /* ~3 frames */
121         .target = panthor_devfreq_target,
122         .get_dev_status = panthor_devfreq_get_dev_status,
123 };
124
125 int panthor_devfreq_init(struct panthor_device *ptdev)
126 {
127         /* There's actually 2 regulators (mali and sram), but the OPP core only
128          * supports one.
129          *
130          * We assume the sram regulator is coupled with the mali one and let
131          * the coupling logic deal with voltage updates.
132          */
133         static const char * const reg_names[] = { "mali", NULL };
134         struct thermal_cooling_device *cooling;
135         struct device *dev = ptdev->base.dev;
136         struct panthor_devfreq *pdevfreq;
137         struct dev_pm_opp *opp;
138         unsigned long cur_freq;
139         unsigned long freq = ULONG_MAX;
140         int ret;
141
142         pdevfreq = drmm_kzalloc(&ptdev->base, sizeof(*ptdev->devfreq), GFP_KERNEL);
143         if (!pdevfreq)
144                 return -ENOMEM;
145
146         ptdev->devfreq = pdevfreq;
147
148         ret = devm_pm_opp_set_regulators(dev, reg_names);
149         if (ret) {
150                 if (ret != -EPROBE_DEFER)
151                         DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
152
153                 return ret;
154         }
155
156         ret = devm_pm_opp_of_add_table(dev);
157         if (ret)
158                 return ret;
159
160         spin_lock_init(&pdevfreq->lock);
161
162         panthor_devfreq_reset(pdevfreq);
163
164         cur_freq = clk_get_rate(ptdev->clks.core);
165
166         /* Regulator coupling only takes care of synchronizing/balancing voltage
167          * updates, but the coupled regulator needs to be enabled manually.
168          *
169          * We use devm_regulator_get_enable_optional() and keep the sram supply
170          * enabled until the device is removed, just like we do for the mali
171          * supply, which is enabled when dev_pm_opp_set_opp(dev, opp) is called,
172          * and disabled when the opp_table is torn down, using the devm action.
173          *
174          * If we really care about disabling regulators on suspend, we should:
175          * - use devm_regulator_get_optional() here
176          * - call dev_pm_opp_set_opp(dev, NULL) before leaving this function
177          *   (this disables the regulator passed to the OPP layer)
178          * - call dev_pm_opp_set_opp(dev, NULL) and
179          *   regulator_disable(ptdev->regulators.sram) in
180          *   panthor_devfreq_suspend()
181          * - call dev_pm_opp_set_opp(dev, default_opp) and
182          *   regulator_enable(ptdev->regulators.sram) in
183          *   panthor_devfreq_resume()
184          *
185          * But without knowing if it's beneficial or not (in term of power
186          * consumption), or how much it slows down the suspend/resume steps,
187          * let's just keep regulators enabled for the device lifetime.
188          */
189         ret = devm_regulator_get_enable_optional(dev, "sram");
190         if (ret && ret != -ENODEV) {
191                 if (ret != -EPROBE_DEFER)
192                         DRM_DEV_ERROR(dev, "Couldn't retrieve/enable sram supply\n");
193                 return ret;
194         }
195
196         opp = devfreq_recommended_opp(dev, &cur_freq, 0);
197         if (IS_ERR(opp))
198                 return PTR_ERR(opp);
199
200         panthor_devfreq_profile.initial_freq = cur_freq;
201         ptdev->current_frequency = cur_freq;
202
203         /*
204          * Set the recommend OPP this will enable and configure the regulator
205          * if any and will avoid a switch off by regulator_late_cleanup()
206          */
207         ret = dev_pm_opp_set_opp(dev, opp);
208         dev_pm_opp_put(opp);
209         if (ret) {
210                 DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n");
211                 return ret;
212         }
213
214         /* Find the fastest defined rate  */
215         opp = dev_pm_opp_find_freq_floor(dev, &freq);
216         if (IS_ERR(opp))
217                 return PTR_ERR(opp);
218         ptdev->fast_rate = freq;
219
220         dev_pm_opp_put(opp);
221
222         /*
223          * Setup default thresholds for the simple_ondemand governor.
224          * The values are chosen based on experiments.
225          */
226         pdevfreq->gov_data.upthreshold = 45;
227         pdevfreq->gov_data.downdifferential = 5;
228
229         pdevfreq->devfreq = devm_devfreq_add_device(dev, &panthor_devfreq_profile,
230                                                     DEVFREQ_GOV_SIMPLE_ONDEMAND,
231                                                     &pdevfreq->gov_data);
232         if (IS_ERR(pdevfreq->devfreq)) {
233                 DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
234                 ret = PTR_ERR(pdevfreq->devfreq);
235                 pdevfreq->devfreq = NULL;
236                 return ret;
237         }
238
239         cooling = devfreq_cooling_em_register(pdevfreq->devfreq, NULL);
240         if (IS_ERR(cooling))
241                 DRM_DEV_INFO(dev, "Failed to register cooling device\n");
242
243         return 0;
244 }
245
246 void panthor_devfreq_resume(struct panthor_device *ptdev)
247 {
248         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
249
250         if (!pdevfreq->devfreq)
251                 return;
252
253         panthor_devfreq_reset(pdevfreq);
254
255         drm_WARN_ON(&ptdev->base, devfreq_resume_device(pdevfreq->devfreq));
256 }
257
258 void panthor_devfreq_suspend(struct panthor_device *ptdev)
259 {
260         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
261
262         if (!pdevfreq->devfreq)
263                 return;
264
265         drm_WARN_ON(&ptdev->base, devfreq_suspend_device(pdevfreq->devfreq));
266 }
267
268 void panthor_devfreq_record_busy(struct panthor_device *ptdev)
269 {
270         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
271         unsigned long irqflags;
272
273         if (!pdevfreq->devfreq)
274                 return;
275
276         spin_lock_irqsave(&pdevfreq->lock, irqflags);
277
278         panthor_devfreq_update_utilization(pdevfreq);
279         pdevfreq->last_busy_state = true;
280
281         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
282 }
283
284 void panthor_devfreq_record_idle(struct panthor_device *ptdev)
285 {
286         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
287         unsigned long irqflags;
288
289         if (!pdevfreq->devfreq)
290                 return;
291
292         spin_lock_irqsave(&pdevfreq->lock, irqflags);
293
294         panthor_devfreq_update_utilization(pdevfreq);
295         pdevfreq->last_busy_state = false;
296
297         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
298 }
This page took 0.050159 seconds and 4 git commands to generate.