Skip to content

Commit 4408c6f

Browse files
committed
drm/v3d: Clock V3D down when not in use.
My various attempts at re-enabling runtime PM have failed, so just crank the clock down when V3D is idle to reduce power consumption. Signed-off-by: Eric Anholt <[email protected]> drm/v3d: Plug dma_fence leak The irq_fence and done_fence are given a reference that is never released. The necessary dma_fence_put()s seem to have been deleted in error in an earlier commit. Fixes: 0b73676 ("drm/v3d: Clock V3D down when not in use.") Signed-off-by: Phil Elwell <[email protected]> v3d_drv: Handle missing clock more gracefully Signed-off-by: popcornmix <[email protected]> v3d_gem: Kick the clock so firmware knows we are using firmware clock interface Setting the v3d clock to low value allows firmware to handle dvfs in case where v3d hardware is not being actively used (e.g. console use). Signed-off-by: popcornmix <[email protected]>
1 parent c506955 commit 4408c6f

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

drivers/gpu/drm/v3d/v3d_drv.c

+17
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
321321
}
322322
}
323323

324+
v3d->clk = devm_clk_get(dev, NULL);
325+
if (IS_ERR_OR_NULL(v3d->clk)) {
326+
if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
327+
dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
328+
return PTR_ERR(v3d->clk);
329+
}
330+
v3d->clk_up_rate = clk_get_rate(v3d->clk);
331+
/* For downclocking, drop it to the minimum frequency we can get from
332+
* the CPRMAN clock generator dividing off our parent. The divider is
333+
* 4 bits, but ask for just higher than that so that rounding doesn't
334+
* make cprman reject our rate.
335+
*/
336+
v3d->clk_down_rate =
337+
(clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
338+
324339
if (v3d->ver < 41) {
325340
ret = map_regs(v3d, &v3d->gca_regs, "gca");
326341
if (ret)
@@ -349,6 +364,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
349364
ret = v3d_sysfs_init(dev);
350365
if (ret)
351366
goto drm_unregister;
367+
ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
368+
WARN_ON_ONCE(ret != 0);
352369

353370
return 0;
354371

drivers/gpu/drm/v3d/v3d_drv.h

+7
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ struct v3d_dev {
113113
void __iomem *bridge_regs;
114114
void __iomem *gca_regs;
115115
struct clk *clk;
116+
struct delayed_work clk_down_work;
117+
unsigned long clk_up_rate, clk_down_rate;
118+
struct mutex clk_lock;
119+
u32 clk_refcount;
120+
bool clk_up;
121+
116122
struct reset_control *reset;
117123

118124
/* Virtual and DMA addresses of the single shared page table. */
@@ -589,3 +595,4 @@ int v3d_perfmon_get_counter_ioctl(struct drm_device *dev, void *data,
589595
/* v3d_sysfs.c */
590596
int v3d_sysfs_init(struct device *dev);
591597
void v3d_sysfs_destroy(struct device *dev);
598+
void v3d_submit_init(struct drm_device *dev);

drivers/gpu/drm/v3d/v3d_gem.c

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/device.h>
55
#include <linux/dma-mapping.h>
66
#include <linux/io.h>
7+
#include <linux/clk.h>
78
#include <linux/module.h>
89
#include <linux/platform_device.h>
910
#include <linux/reset.h>
@@ -269,6 +270,8 @@ v3d_gem_init(struct drm_device *dev)
269270
if (ret)
270271
return ret;
271272

273+
v3d_submit_init(dev);
274+
272275
/* Note: We don't allocate address 0. Various bits of HW
273276
* treat 0 as special, such as the occlusion query counters
274277
* where 0 means "disabled".

drivers/gpu/drm/v3d/v3d_submit.c

+56
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,52 @@
55
*/
66

77
#include <drm/drm_syncobj.h>
8+
#include <linux/clk.h>
89

910
#include "v3d_drv.h"
1011
#include "v3d_regs.h"
1112
#include "v3d_trace.h"
1213

14+
static void
15+
v3d_clock_down_work(struct work_struct *work)
16+
{
17+
struct v3d_dev *v3d =
18+
container_of(work, struct v3d_dev, clk_down_work.work);
19+
int ret;
20+
21+
ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
22+
v3d->clk_up = false;
23+
WARN_ON_ONCE(ret != 0);
24+
}
25+
26+
static void
27+
v3d_clock_up_get(struct v3d_dev *v3d)
28+
{
29+
mutex_lock(&v3d->clk_lock);
30+
if (v3d->clk_refcount++ == 0) {
31+
cancel_delayed_work_sync(&v3d->clk_down_work);
32+
if (!v3d->clk_up) {
33+
int ret;
34+
35+
ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
36+
WARN_ON_ONCE(ret != 0);
37+
v3d->clk_up = true;
38+
}
39+
}
40+
mutex_unlock(&v3d->clk_lock);
41+
}
42+
43+
static void
44+
v3d_clock_up_put(struct v3d_dev *v3d)
45+
{
46+
mutex_lock(&v3d->clk_lock);
47+
if (--v3d->clk_refcount == 0) {
48+
schedule_delayed_work(&v3d->clk_down_work,
49+
msecs_to_jiffies(100));
50+
}
51+
mutex_unlock(&v3d->clk_lock);
52+
}
53+
1354
/* Takes the reservation lock on all the BOs being referenced, so that
1455
* at queue submit time we can update the reservations.
1556
*
@@ -87,6 +128,7 @@ static void
87128
v3d_job_free(struct kref *ref)
88129
{
89130
struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
131+
struct v3d_dev *v3d = job->v3d;
90132
int i;
91133

92134
if (job->bo) {
@@ -98,6 +140,8 @@ v3d_job_free(struct kref *ref)
98140
dma_fence_put(job->irq_fence);
99141
dma_fence_put(job->done_fence);
100142

143+
v3d_clock_up_put(v3d);
144+
101145
if (job->perfmon)
102146
v3d_perfmon_put(job->perfmon);
103147

@@ -199,6 +243,7 @@ v3d_job_init(struct v3d_dev *v3d, struct drm_file *file_priv,
199243
goto fail_deps;
200244
}
201245

246+
v3d_clock_up_get(v3d);
202247
kref_init(&job->refcount);
203248

204249
return 0;
@@ -1393,3 +1438,14 @@ v3d_submit_cpu_ioctl(struct drm_device *dev, void *data,
13931438

13941439
return ret;
13951440
}
1441+
1442+
void v3d_submit_init(struct drm_device *dev) {
1443+
struct v3d_dev *v3d = to_v3d_dev(dev);
1444+
1445+
mutex_init(&v3d->clk_lock);
1446+
INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
1447+
1448+
/* kick the clock so firmware knows we are using firmware clock interface */
1449+
v3d_clock_up_get(v3d);
1450+
v3d_clock_up_put(v3d);
1451+
}

0 commit comments

Comments
 (0)