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 */
18struct 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
47static 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
62static 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
75static 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
82static 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
112static 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
119int 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
231int 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
243int 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
253void 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
269void 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}
284