Skip to content

Commit e594049

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 851e817 commit e594049

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
@@ -331,6 +331,21 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
331331
}
332332
}
333333

334+
v3d->clk = devm_clk_get(dev, NULL);
335+
if (IS_ERR_OR_NULL(v3d->clk)) {
336+
if (PTR_ERR(v3d->clk) != -EPROBE_DEFER)
337+
dev_err(dev, "Failed to get clock (%ld)\n", PTR_ERR(v3d->clk));
338+
return PTR_ERR(v3d->clk);
339+
}
340+
v3d->clk_up_rate = clk_get_rate(v3d->clk);
341+
/* For downclocking, drop it to the minimum frequency we can get from
342+
* the CPRMAN clock generator dividing off our parent. The divider is
343+
* 4 bits, but ask for just higher than that so that rounding doesn't
344+
* make cprman reject our rate.
345+
*/
346+
v3d->clk_down_rate =
347+
(clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
348+
334349
if (v3d->ver < 41) {
335350
ret = map_regs(v3d, &v3d->gca_regs, "gca");
336351
if (ret)
@@ -359,6 +374,8 @@ static int v3d_platform_drm_probe(struct platform_device *pdev)
359374
ret = v3d_sysfs_init(dev);
360375
if (ret)
361376
goto drm_unregister;
377+
ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
378+
WARN_ON_ONCE(ret != 0);
362379

363380
return 0;
364381

drivers/gpu/drm/v3d/v3d_drv.h

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

117123
/* Virtual and DMA addresses of the single shared page table. */
@@ -598,3 +604,4 @@ int v3d_perfmon_get_counter_ioctl(struct drm_device *dev, void *data,
598604
/* v3d_sysfs.c */
599605
int v3d_sysfs_init(struct device *dev);
600606
void v3d_sysfs_destroy(struct device *dev);
607+
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)