File Index
Files and directories
Sign in
FILE

panthor_devfreq.c

File preview with syntax highlighting.

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