1 // SPDX-License-Identifier: GPL-2.0
5 * Based on panfrost_devfreq.c:
6 * Copyright 2019 Collabora ltd.
9 #include <linux/devfreq.h>
10 #include <linux/devfreq_cooling.h>
11 #include <linux/device.h>
12 #include <linux/platform_device.h>
13 #include <linux/pm_opp.h>
14 #include <linux/property.h>
16 #include "lima_device.h"
17 #include "lima_devfreq.h"
19 static void lima_devfreq_update_utilization(struct lima_devfreq *devfreq)
24 last = devfreq->time_last_update;
26 if (devfreq->busy_count > 0)
27 devfreq->busy_time += ktime_sub(now, last);
29 devfreq->idle_time += ktime_sub(now, last);
31 devfreq->time_last_update = now;
34 static int lima_devfreq_target(struct device *dev, unsigned long *freq,
37 struct dev_pm_opp *opp;
40 opp = devfreq_recommended_opp(dev, freq, flags);
45 err = dev_pm_opp_set_rate(dev, *freq);
52 static void lima_devfreq_reset(struct lima_devfreq *devfreq)
54 devfreq->busy_time = 0;
55 devfreq->idle_time = 0;
56 devfreq->time_last_update = ktime_get();
59 static int lima_devfreq_get_dev_status(struct device *dev,
60 struct devfreq_dev_status *status)
62 struct lima_device *ldev = dev_get_drvdata(dev);
63 struct lima_devfreq *devfreq = &ldev->devfreq;
64 unsigned long irqflags;
66 status->current_frequency = clk_get_rate(ldev->clk_gpu);
68 spin_lock_irqsave(&devfreq->lock, irqflags);
70 lima_devfreq_update_utilization(devfreq);
72 status->total_time = ktime_to_ns(ktime_add(devfreq->busy_time,
74 status->busy_time = ktime_to_ns(devfreq->busy_time);
76 lima_devfreq_reset(devfreq);
78 spin_unlock_irqrestore(&devfreq->lock, irqflags);
80 dev_dbg(ldev->dev, "busy %lu total %lu %lu %% freq %lu MHz\n",
81 status->busy_time, status->total_time,
82 status->busy_time / (status->total_time / 100),
83 status->current_frequency / 1000 / 1000);
88 static struct devfreq_dev_profile lima_devfreq_profile = {
89 .polling_ms = 50, /* ~3 frames */
90 .target = lima_devfreq_target,
91 .get_dev_status = lima_devfreq_get_dev_status,
94 void lima_devfreq_fini(struct lima_device *ldev)
96 struct lima_devfreq *devfreq = &ldev->devfreq;
98 if (devfreq->cooling) {
99 devfreq_cooling_unregister(devfreq->cooling);
100 devfreq->cooling = NULL;
103 if (devfreq->devfreq) {
104 devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
105 devfreq->devfreq = NULL;
108 if (devfreq->opp_of_table_added) {
109 dev_pm_opp_of_remove_table(ldev->dev);
110 devfreq->opp_of_table_added = false;
113 if (devfreq->regulators_opp_table) {
114 dev_pm_opp_put_regulators(devfreq->regulators_opp_table);
115 devfreq->regulators_opp_table = NULL;
118 if (devfreq->clkname_opp_table) {
119 dev_pm_opp_put_clkname(devfreq->clkname_opp_table);
120 devfreq->clkname_opp_table = NULL;
124 int lima_devfreq_init(struct lima_device *ldev)
126 struct thermal_cooling_device *cooling;
127 struct device *dev = ldev->dev;
128 struct opp_table *opp_table;
129 struct devfreq *devfreq;
130 struct lima_devfreq *ldevfreq = &ldev->devfreq;
131 struct dev_pm_opp *opp;
132 unsigned long cur_freq;
135 if (!device_property_present(dev, "operating-points-v2"))
136 /* Optional, continue without devfreq */
139 spin_lock_init(&ldevfreq->lock);
141 opp_table = dev_pm_opp_set_clkname(dev, "core");
142 if (IS_ERR(opp_table)) {
143 ret = PTR_ERR(opp_table);
147 ldevfreq->clkname_opp_table = opp_table;
149 opp_table = dev_pm_opp_set_regulators(dev,
150 (const char *[]){ "mali" },
152 if (IS_ERR(opp_table)) {
153 ret = PTR_ERR(opp_table);
155 /* Continue if the optional regulator is missing */
159 ldevfreq->regulators_opp_table = opp_table;
162 ret = dev_pm_opp_of_add_table(dev);
165 ldevfreq->opp_of_table_added = true;
167 lima_devfreq_reset(ldevfreq);
169 cur_freq = clk_get_rate(ldev->clk_gpu);
171 opp = devfreq_recommended_opp(dev, &cur_freq, 0);
177 lima_devfreq_profile.initial_freq = cur_freq;
180 devfreq = devm_devfreq_add_device(dev, &lima_devfreq_profile,
181 DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
182 if (IS_ERR(devfreq)) {
183 dev_err(dev, "Couldn't initialize GPU devfreq\n");
184 ret = PTR_ERR(devfreq);
188 ldevfreq->devfreq = devfreq;
190 cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
192 dev_info(dev, "Failed to register cooling device\n");
194 ldevfreq->cooling = cooling;
199 lima_devfreq_fini(ldev);
203 void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
205 unsigned long irqflags;
207 if (!devfreq->devfreq)
210 spin_lock_irqsave(&devfreq->lock, irqflags);
212 lima_devfreq_update_utilization(devfreq);
214 devfreq->busy_count++;
216 spin_unlock_irqrestore(&devfreq->lock, irqflags);
219 void lima_devfreq_record_idle(struct lima_devfreq *devfreq)
221 unsigned long irqflags;
223 if (!devfreq->devfreq)
226 spin_lock_irqsave(&devfreq->lock, irqflags);
228 lima_devfreq_update_utilization(devfreq);
230 WARN_ON(--devfreq->busy_count < 0);
232 spin_unlock_irqrestore(&devfreq->lock, irqflags);
235 int lima_devfreq_resume(struct lima_devfreq *devfreq)
237 unsigned long irqflags;
239 if (!devfreq->devfreq)
242 spin_lock_irqsave(&devfreq->lock, irqflags);
244 lima_devfreq_reset(devfreq);
246 spin_unlock_irqrestore(&devfreq->lock, irqflags);
248 return devfreq_resume_device(devfreq->devfreq);
251 int lima_devfreq_suspend(struct lima_devfreq *devfreq)
253 if (!devfreq->devfreq)
256 return devfreq_suspend_device(devfreq->devfreq);