aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2016-02-05 20:41:49 -0500
committerEric Anholt <eric@anholt.net>2016-02-16 15:21:00 -0500
commit001bdb55d9eb72a9e2d5b623bacfc52da74ae03e (patch)
tree3a980e9aa3985a91c16e65c4ec24a04e589cac37
parentc4ce60dc30912df09b2438f1e5594eae1ef64d1e (diff)
drm/vc4: Enable runtime PM.
This may actually get us a feature that the closed driver didn't have: turning off the GPU in between rendering jobs, while the V3D device is still opened by the client. There may be some tuning to be applied here to use autosuspend so that we don't bounce the device's power so much, but in steady-state GPU-bound rendering we keep the power on (since we keep multiple jobs outstanding) and even if we power cycle on every job we can still manage at least 680 fps. More importantly, though, runtime PM will allow us to power off the device to do a GPU reset. v2: Switch #ifdef to CONFIG_PM not CONFIG_PM_SLEEP (caught by kbuild test robot) Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.h1
-rw-r--r--drivers/gpu/drm/vc4/vc4_gem.c10
-rw-r--r--drivers/gpu/drm/vc4/vc4_v3d.c36
3 files changed, 47 insertions, 0 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index b6ccf8181643..8ac3788846ce 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -141,6 +141,7 @@ struct vc4_seqno_cb {
141}; 141};
142 142
143struct vc4_v3d { 143struct vc4_v3d {
144 struct vc4_dev *vc4;
144 struct platform_device *pdev; 145 struct platform_device *pdev;
145 void __iomem *regs; 146 void __iomem *regs;
146}; 147};
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
index 1a819dd826f8..4e0391cbf9d0 100644
--- a/drivers/gpu/drm/vc4/vc4_gem.c
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
@@ -23,6 +23,7 @@
23 23
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/pm_runtime.h>
26#include <linux/device.h> 27#include <linux/device.h>
27#include <linux/io.h> 28#include <linux/io.h>
28 29
@@ -621,6 +622,7 @@ fail:
621static void 622static void
622vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec) 623vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
623{ 624{
625 struct vc4_dev *vc4 = to_vc4_dev(dev);
624 unsigned i; 626 unsigned i;
625 627
626 /* Need the struct lock for drm_gem_object_unreference(). */ 628 /* Need the struct lock for drm_gem_object_unreference(). */
@@ -639,6 +641,8 @@ vc4_complete_exec(struct drm_device *dev, struct vc4_exec_info *exec)
639 } 641 }
640 mutex_unlock(&dev->struct_mutex); 642 mutex_unlock(&dev->struct_mutex);
641 643
644 pm_runtime_put(&vc4->v3d->pdev->dev);
645
642 kfree(exec); 646 kfree(exec);
643} 647}
644 648
@@ -792,6 +796,12 @@ vc4_submit_cl_ioctl(struct drm_device *dev, void *data,
792 return -ENOMEM; 796 return -ENOMEM;
793 } 797 }
794 798
799 ret = pm_runtime_get_sync(&vc4->v3d->pdev->dev);
800 if (ret < 0) {
801 kfree(exec);
802 return ret;
803 }
804
795 exec->args = args; 805 exec->args = args;
796 INIT_LIST_HEAD(&exec->unref_list); 806 INIT_LIST_HEAD(&exec->unref_list);
797 807
diff --git a/drivers/gpu/drm/vc4/vc4_v3d.c b/drivers/gpu/drm/vc4/vc4_v3d.c
index 314ff71db978..cb38b6bf4119 100644
--- a/drivers/gpu/drm/vc4/vc4_v3d.c
+++ b/drivers/gpu/drm/vc4/vc4_v3d.c
@@ -17,6 +17,7 @@
17 */ 17 */
18 18
19#include "linux/component.h" 19#include "linux/component.h"
20#include "linux/pm_runtime.h"
20#include "vc4_drv.h" 21#include "vc4_drv.h"
21#include "vc4_regs.h" 22#include "vc4_regs.h"
22 23
@@ -167,6 +168,29 @@ static void vc4_v3d_init_hw(struct drm_device *dev)
167 V3D_WRITE(V3D_VPMBASE, 0); 168 V3D_WRITE(V3D_VPMBASE, 0);
168} 169}
169 170
171#ifdef CONFIG_PM
172static int vc4_v3d_runtime_suspend(struct device *dev)
173{
174 struct vc4_v3d *v3d = dev_get_drvdata(dev);
175 struct vc4_dev *vc4 = v3d->vc4;
176
177 vc4_irq_uninstall(vc4->dev);
178
179 return 0;
180}
181
182static int vc4_v3d_runtime_resume(struct device *dev)
183{
184 struct vc4_v3d *v3d = dev_get_drvdata(dev);
185 struct vc4_dev *vc4 = v3d->vc4;
186
187 vc4_v3d_init_hw(vc4->dev);
188 vc4_irq_postinstall(vc4->dev);
189
190 return 0;
191}
192#endif
193
170static int vc4_v3d_bind(struct device *dev, struct device *master, void *data) 194static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
171{ 195{
172 struct platform_device *pdev = to_platform_device(dev); 196 struct platform_device *pdev = to_platform_device(dev);
@@ -179,6 +203,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
179 if (!v3d) 203 if (!v3d)
180 return -ENOMEM; 204 return -ENOMEM;
181 205
206 dev_set_drvdata(dev, v3d);
207
182 v3d->pdev = pdev; 208 v3d->pdev = pdev;
183 209
184 v3d->regs = vc4_ioremap_regs(pdev, 0); 210 v3d->regs = vc4_ioremap_regs(pdev, 0);
@@ -186,6 +212,7 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
186 return PTR_ERR(v3d->regs); 212 return PTR_ERR(v3d->regs);
187 213
188 vc4->v3d = v3d; 214 vc4->v3d = v3d;
215 v3d->vc4 = vc4;
189 216
190 if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) { 217 if (V3D_READ(V3D_IDENT0) != V3D_EXPECTED_IDENT0) {
191 DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n", 218 DRM_ERROR("V3D_IDENT0 read 0x%08x instead of 0x%08x\n",
@@ -207,6 +234,8 @@ static int vc4_v3d_bind(struct device *dev, struct device *master, void *data)
207 return ret; 234 return ret;
208 } 235 }
209 236
237 pm_runtime_enable(dev);
238
210 return 0; 239 return 0;
211} 240}
212 241
@@ -216,6 +245,8 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
216 struct drm_device *drm = dev_get_drvdata(master); 245 struct drm_device *drm = dev_get_drvdata(master);
217 struct vc4_dev *vc4 = to_vc4_dev(drm); 246 struct vc4_dev *vc4 = to_vc4_dev(drm);
218 247
248 pm_runtime_disable(dev);
249
219 drm_irq_uninstall(drm); 250 drm_irq_uninstall(drm);
220 251
221 /* Disable the binner's overflow memory address, so the next 252 /* Disable the binner's overflow memory address, so the next
@@ -228,6 +259,10 @@ static void vc4_v3d_unbind(struct device *dev, struct device *master,
228 vc4->v3d = NULL; 259 vc4->v3d = NULL;
229} 260}
230 261
262static const struct dev_pm_ops vc4_v3d_pm_ops = {
263 SET_RUNTIME_PM_OPS(vc4_v3d_runtime_suspend, vc4_v3d_runtime_resume, NULL)
264};
265
231static const struct component_ops vc4_v3d_ops = { 266static const struct component_ops vc4_v3d_ops = {
232 .bind = vc4_v3d_bind, 267 .bind = vc4_v3d_bind,
233 .unbind = vc4_v3d_unbind, 268 .unbind = vc4_v3d_unbind,
@@ -255,5 +290,6 @@ struct platform_driver vc4_v3d_driver = {
255 .driver = { 290 .driver = {
256 .name = "vc4_v3d", 291 .name = "vc4_v3d",
257 .of_match_table = vc4_v3d_dt_match, 292 .of_match_table = vc4_v3d_dt_match,
293 .pm = &vc4_v3d_pm_ops,
258 }, 294 },
259}; 295};