]> Git Repo - linux.git/blob - drivers/gpu/drm/panthor/panthor_devfreq.c
Merge tag 'sound-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai...
[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 dev_pm_opp *opp;
66
67         opp = devfreq_recommended_opp(dev, freq, flags);
68         if (IS_ERR(opp))
69                 return PTR_ERR(opp);
70         dev_pm_opp_put(opp);
71
72         return dev_pm_opp_set_rate(dev, *freq);
73 }
74
75 static void panthor_devfreq_reset(struct panthor_devfreq *pdevfreq)
76 {
77         pdevfreq->busy_time = 0;
78         pdevfreq->idle_time = 0;
79         pdevfreq->time_last_update = ktime_get();
80 }
81
82 static int panthor_devfreq_get_dev_status(struct device *dev,
83                                           struct devfreq_dev_status *status)
84 {
85         struct panthor_device *ptdev = dev_get_drvdata(dev);
86         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
87         unsigned long irqflags;
88
89         status->current_frequency = clk_get_rate(ptdev->clks.core);
90
91         spin_lock_irqsave(&pdevfreq->lock, irqflags);
92
93         panthor_devfreq_update_utilization(pdevfreq);
94
95         status->total_time = ktime_to_ns(ktime_add(pdevfreq->busy_time,
96                                                    pdevfreq->idle_time));
97
98         status->busy_time = ktime_to_ns(pdevfreq->busy_time);
99
100         panthor_devfreq_reset(pdevfreq);
101
102         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
103
104         drm_dbg(&ptdev->base, "busy %lu total %lu %lu %% freq %lu MHz\n",
105                 status->busy_time, status->total_time,
106                 status->busy_time / (status->total_time / 100),
107                 status->current_frequency / 1000 / 1000);
108
109         return 0;
110 }
111
112 static struct devfreq_dev_profile panthor_devfreq_profile = {
113         .timer = DEVFREQ_TIMER_DELAYED,
114         .polling_ms = 50, /* ~3 frames */
115         .target = panthor_devfreq_target,
116         .get_dev_status = panthor_devfreq_get_dev_status,
117 };
118
119 int panthor_devfreq_init(struct panthor_device *ptdev)
120 {
121         /* There's actually 2 regulators (mali and sram), but the OPP core only
122          * supports one.
123          *
124          * We assume the sram regulator is coupled with the mali one and let
125          * the coupling logic deal with voltage updates.
126          */
127         static const char * const reg_names[] = { "mali", NULL };
128         struct thermal_cooling_device *cooling;
129         struct device *dev = ptdev->base.dev;
130         struct panthor_devfreq *pdevfreq;
131         struct dev_pm_opp *opp;
132         unsigned long cur_freq;
133         int ret;
134
135         pdevfreq = drmm_kzalloc(&ptdev->base, sizeof(*ptdev->devfreq), GFP_KERNEL);
136         if (!pdevfreq)
137                 return -ENOMEM;
138
139         ptdev->devfreq = pdevfreq;
140
141         ret = devm_pm_opp_set_regulators(dev, reg_names);
142         if (ret) {
143                 if (ret != -EPROBE_DEFER)
144                         DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
145
146                 return ret;
147         }
148
149         ret = devm_pm_opp_of_add_table(dev);
150         if (ret)
151                 return ret;
152
153         spin_lock_init(&pdevfreq->lock);
154
155         panthor_devfreq_reset(pdevfreq);
156
157         cur_freq = clk_get_rate(ptdev->clks.core);
158
159         opp = devfreq_recommended_opp(dev, &cur_freq, 0);
160         if (IS_ERR(opp))
161                 return PTR_ERR(opp);
162
163         panthor_devfreq_profile.initial_freq = cur_freq;
164
165         /* Regulator coupling only takes care of synchronizing/balancing voltage
166          * updates, but the coupled regulator needs to be enabled manually.
167          *
168          * We use devm_regulator_get_enable_optional() and keep the sram supply
169          * enabled until the device is removed, just like we do for the mali
170          * supply, which is enabled when dev_pm_opp_set_opp(dev, opp) is called,
171          * and disabled when the opp_table is torn down, using the devm action.
172          *
173          * If we really care about disabling regulators on suspend, we should:
174          * - use devm_regulator_get_optional() here
175          * - call dev_pm_opp_set_opp(dev, NULL) before leaving this function
176          *   (this disables the regulator passed to the OPP layer)
177          * - call dev_pm_opp_set_opp(dev, NULL) and
178          *   regulator_disable(ptdev->regulators.sram) in
179          *   panthor_devfreq_suspend()
180          * - call dev_pm_opp_set_opp(dev, default_opp) and
181          *   regulator_enable(ptdev->regulators.sram) in
182          *   panthor_devfreq_resume()
183          *
184          * But without knowing if it's beneficial or not (in term of power
185          * consumption), or how much it slows down the suspend/resume steps,
186          * let's just keep regulators enabled for the device lifetime.
187          */
188         ret = devm_regulator_get_enable_optional(dev, "sram");
189         if (ret && ret != -ENODEV) {
190                 if (ret != -EPROBE_DEFER)
191                         DRM_DEV_ERROR(dev, "Couldn't retrieve/enable sram supply\n");
192                 return ret;
193         }
194
195         /*
196          * Set the recommend OPP this will enable and configure the regulator
197          * if any and will avoid a switch off by regulator_late_cleanup()
198          */
199         ret = dev_pm_opp_set_opp(dev, opp);
200         if (ret) {
201                 DRM_DEV_ERROR(dev, "Couldn't set recommended OPP\n");
202                 return ret;
203         }
204
205         dev_pm_opp_put(opp);
206
207         /*
208          * Setup default thresholds for the simple_ondemand governor.
209          * The values are chosen based on experiments.
210          */
211         pdevfreq->gov_data.upthreshold = 45;
212         pdevfreq->gov_data.downdifferential = 5;
213
214         pdevfreq->devfreq = devm_devfreq_add_device(dev, &panthor_devfreq_profile,
215                                                     DEVFREQ_GOV_SIMPLE_ONDEMAND,
216                                                     &pdevfreq->gov_data);
217         if (IS_ERR(pdevfreq->devfreq)) {
218                 DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
219                 ret = PTR_ERR(pdevfreq->devfreq);
220                 pdevfreq->devfreq = NULL;
221                 return ret;
222         }
223
224         cooling = devfreq_cooling_em_register(pdevfreq->devfreq, NULL);
225         if (IS_ERR(cooling))
226                 DRM_DEV_INFO(dev, "Failed to register cooling device\n");
227
228         return 0;
229 }
230
231 int panthor_devfreq_resume(struct panthor_device *ptdev)
232 {
233         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
234
235         if (!pdevfreq->devfreq)
236                 return 0;
237
238         panthor_devfreq_reset(pdevfreq);
239
240         return devfreq_resume_device(pdevfreq->devfreq);
241 }
242
243 int panthor_devfreq_suspend(struct panthor_device *ptdev)
244 {
245         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
246
247         if (!pdevfreq->devfreq)
248                 return 0;
249
250         return devfreq_suspend_device(pdevfreq->devfreq);
251 }
252
253 void panthor_devfreq_record_busy(struct panthor_device *ptdev)
254 {
255         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
256         unsigned long irqflags;
257
258         if (!pdevfreq->devfreq)
259                 return;
260
261         spin_lock_irqsave(&pdevfreq->lock, irqflags);
262
263         panthor_devfreq_update_utilization(pdevfreq);
264         pdevfreq->last_busy_state = true;
265
266         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
267 }
268
269 void panthor_devfreq_record_idle(struct panthor_device *ptdev)
270 {
271         struct panthor_devfreq *pdevfreq = ptdev->devfreq;
272         unsigned long irqflags;
273
274         if (!pdevfreq->devfreq)
275                 return;
276
277         spin_lock_irqsave(&pdevfreq->lock, irqflags);
278
279         panthor_devfreq_update_utilization(pdevfreq);
280         pdevfreq->last_busy_state = false;
281
282         spin_unlock_irqrestore(&pdevfreq->lock, irqflags);
283 }
This page took 0.050065 seconds and 4 git commands to generate.