brcm2708: add linux 4.19 support
[oweals/openwrt.git] / target / linux / brcm2708 / patches-4.19 / 950-0617-drm-v3d-Clock-V3D-down-when-not-in-use.patch
1 From 167429373da6ab4f3f498013277eb5545d6f0c64 Mon Sep 17 00:00:00 2001
2 From: Eric Anholt <eric@anholt.net>
3 Date: Thu, 2 May 2019 13:22:53 -0700
4 Subject: [PATCH 617/703] drm/v3d: Clock V3D down when not in use.
5
6 My various attempts at re-enabling runtime PM have failed, so just
7 crank the clock down when V3D is idle to reduce power consumption.
8
9 Signed-off-by: Eric Anholt <eric@anholt.net>
10 ---
11  drivers/gpu/drm/v3d/v3d_drv.c | 18 +++++++++++++
12  drivers/gpu/drm/v3d/v3d_drv.h |  6 +++++
13  drivers/gpu/drm/v3d/v3d_gem.c | 49 +++++++++++++++++++++++++++++++++++
14  3 files changed, 73 insertions(+)
15
16 --- a/drivers/gpu/drm/v3d/v3d_drv.c
17 +++ b/drivers/gpu/drm/v3d/v3d_drv.c
18 @@ -297,6 +297,21 @@ static int v3d_platform_drm_probe(struct
19                 }
20         }
21  
22 +       v3d->clk = devm_clk_get(dev, NULL);
23 +       if (IS_ERR(v3d->clk)) {
24 +               if (ret != -EPROBE_DEFER)
25 +                       dev_err(dev, "Failed to get clock\n");
26 +               goto dev_free;
27 +       }
28 +       v3d->clk_up_rate = clk_get_rate(v3d->clk);
29 +       /* For downclocking, drop it to the minimum frequency we can get from
30 +        * the CPRMAN clock generator dividing off our parent.  The divider is
31 +        * 4 bits, but ask for just higher than that so that rounding doesn't
32 +        * make cprman reject our rate.
33 +        */
34 +       v3d->clk_down_rate =
35 +               (clk_get_rate(clk_get_parent(v3d->clk)) / (1 << 4)) + 10000;
36 +
37         if (v3d->ver < 41) {
38                 ret = map_regs(v3d, &v3d->gca_regs, "gca");
39                 if (ret)
40 @@ -331,6 +346,9 @@ static int v3d_platform_drm_probe(struct
41         if (ret)
42                 goto irq_disable;
43  
44 +       ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
45 +       WARN_ON_ONCE(ret != 0);
46 +
47         return 0;
48  
49  irq_disable:
50 --- a/drivers/gpu/drm/v3d/v3d_drv.h
51 +++ b/drivers/gpu/drm/v3d/v3d_drv.h
52 @@ -45,6 +45,12 @@ struct v3d_dev {
53         void __iomem *bridge_regs;
54         void __iomem *gca_regs;
55         struct clk *clk;
56 +       struct delayed_work clk_down_work;
57 +       unsigned long clk_up_rate, clk_down_rate;
58 +       struct mutex clk_lock;
59 +       u32 clk_refcount;
60 +       bool clk_up;
61 +
62         struct reset_control *reset;
63  
64         /* Virtual and DMA addresses of the single shared page table. */
65 --- a/drivers/gpu/drm/v3d/v3d_gem.c
66 +++ b/drivers/gpu/drm/v3d/v3d_gem.c
67 @@ -3,6 +3,7 @@
68  
69  #include <drm/drmP.h>
70  #include <drm/drm_syncobj.h>
71 +#include <linux/clk.h>
72  #include <linux/module.h>
73  #include <linux/platform_device.h>
74  #include <linux/pm_runtime.h>
75 @@ -17,6 +18,47 @@
76  #include "v3d_trace.h"
77  
78  static void
79 +v3d_clock_down_work(struct work_struct *work)
80 +{
81 +       struct v3d_dev *v3d =
82 +               container_of(work, struct v3d_dev, clk_down_work.work);
83 +       int ret;
84 +
85 +       ret = clk_set_rate(v3d->clk, v3d->clk_down_rate);
86 +       v3d->clk_up = false;
87 +       WARN_ON_ONCE(ret != 0);
88 +}
89 +
90 +static void
91 +v3d_clock_up_get(struct v3d_dev *v3d)
92 +{
93 +       mutex_lock(&v3d->clk_lock);
94 +       if (v3d->clk_refcount++ == 0) {
95 +               cancel_delayed_work_sync(&v3d->clk_down_work);
96 +               if (!v3d->clk_up)  {
97 +                       int ret;
98 +
99 +                       ret = clk_set_rate(v3d->clk, v3d->clk_up_rate);
100 +                       WARN_ON_ONCE(ret != 0);
101 +                       v3d->clk_up = true;
102 +               }
103 +       }
104 +       mutex_unlock(&v3d->clk_lock);
105 +}
106 +
107 +static void
108 +v3d_clock_up_put(struct v3d_dev *v3d)
109 +{
110 +       mutex_lock(&v3d->clk_lock);
111 +       if (--v3d->clk_refcount == 0) {
112 +               schedule_delayed_work(&v3d->clk_down_work,
113 +                                     msecs_to_jiffies(100));
114 +       }
115 +       mutex_unlock(&v3d->clk_lock);
116 +}
117 +
118 +
119 +static void
120  v3d_init_core(struct v3d_dev *v3d, int core)
121  {
122         /* Set OVRTMUOUT, which means that the texture sampler uniform
123 @@ -490,6 +532,7 @@ static void
124  v3d_job_free(struct kref *ref)
125  {
126         struct v3d_job *job = container_of(ref, struct v3d_job, refcount);
127 +       struct v3d_dev *v3d = job->v3d;
128         int i;
129  
130         for (i = 0; i < job->bo_count; i++) {
131 @@ -505,6 +548,8 @@ v3d_job_free(struct kref *ref)
132         dma_fence_put(job->irq_fence);
133         dma_fence_put(job->done_fence);
134  
135 +       v3d_clock_up_put(v3d);
136 +
137         kfree(job);
138  }
139  
140 @@ -596,6 +641,7 @@ v3d_job_init(struct v3d_dev *v3d, struct
141         if (ret)
142                 return ret;
143  
144 +       v3d_clock_up_get(v3d);
145         kref_init(&job->refcount);
146  
147         return 0;
148 @@ -963,6 +1009,9 @@ v3d_gem_init(struct drm_device *dev)
149         mutex_init(&v3d->sched_lock);
150         mutex_init(&v3d->cache_clean_lock);
151  
152 +       mutex_init(&v3d->clk_lock);
153 +       INIT_DELAYED_WORK(&v3d->clk_down_work, v3d_clock_down_work);
154 +
155         /* Note: We don't allocate address 0.  Various bits of HW
156          * treat 0 as special, such as the occlusion query counters
157          * where 0 means "disabled".