aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiviu Dudau <Liviu.Dudau@arm.com>2016-05-17 05:06:54 -0400
committerLiviu Dudau <Liviu.Dudau@arm.com>2016-06-02 12:43:59 -0400
commita95acec16d932ac78c2f70dc95a83bd162595d6c (patch)
treec9144809601a1940ec951bb0a2779f23a4529f6b
parent1a695a905c18548062509178b98bc91e67510864 (diff)
drm: hdlcd: Revamp runtime power management
Because the HDLCD driver acts as a component master it can end up enabling the runtime PM functionality before the encoders are initialised. This can cause crashes if the component slave never probes (missing module) or if the PM operations kick in before the probe finishes. Move the enabling of the runtime PM after the component master has finished collecting the slave components and use the DRM atomic helpers to suspend and resume the device. Tested-by: Robin Murphy <Robin.Murphy@arm.com> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
-rw-r--r--drivers/gpu/drm/arm/hdlcd_crtc.c23
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.c48
-rw-r--r--drivers/gpu/drm/arm/hdlcd_drv.h3
3 files changed, 39 insertions, 35 deletions
diff --git a/drivers/gpu/drm/arm/hdlcd_crtc.c b/drivers/gpu/drm/arm/hdlcd_crtc.c
index fef1b04c2aab..d1e8d31e37ee 100644
--- a/drivers/gpu/drm/arm/hdlcd_crtc.c
+++ b/drivers/gpu/drm/arm/hdlcd_crtc.c
@@ -33,8 +33,17 @@
33 * 33 *
34 */ 34 */
35 35
36static void hdlcd_crtc_cleanup(struct drm_crtc *crtc)
37{
38 struct hdlcd_drm_private *hdlcd = crtc_to_hdlcd_priv(crtc);
39
40 /* stop the controller on cleanup */
41 hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
42 drm_crtc_cleanup(crtc);
43}
44
36static const struct drm_crtc_funcs hdlcd_crtc_funcs = { 45static const struct drm_crtc_funcs hdlcd_crtc_funcs = {
37 .destroy = drm_crtc_cleanup, 46 .destroy = hdlcd_crtc_cleanup,
38 .set_config = drm_atomic_helper_set_config, 47 .set_config = drm_atomic_helper_set_config,
39 .page_flip = drm_atomic_helper_page_flip, 48 .page_flip = drm_atomic_helper_page_flip,
40 .reset = drm_atomic_helper_crtc_reset, 49 .reset = drm_atomic_helper_crtc_reset,
@@ -155,8 +164,8 @@ static void hdlcd_crtc_disable(struct drm_crtc *crtc)
155 if (!crtc->primary->fb) 164 if (!crtc->primary->fb)
156 return; 165 return;
157 166
158 clk_disable_unprepare(hdlcd->clk);
159 hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0); 167 hdlcd_write(hdlcd, HDLCD_REG_COMMAND, 0);
168 clk_disable_unprepare(hdlcd->clk);
160 drm_crtc_vblank_off(crtc); 169 drm_crtc_vblank_off(crtc);
161} 170}
162 171
@@ -294,16 +303,6 @@ static struct drm_plane *hdlcd_plane_init(struct drm_device *drm)
294 return plane; 303 return plane;
295} 304}
296 305
297void hdlcd_crtc_suspend(struct drm_crtc *crtc)
298{
299 hdlcd_crtc_disable(crtc);
300}
301
302void hdlcd_crtc_resume(struct drm_crtc *crtc)
303{
304 hdlcd_crtc_enable(crtc);
305}
306
307int hdlcd_setup_crtc(struct drm_device *drm) 306int hdlcd_setup_crtc(struct drm_device *drm)
308{ 307{
309 struct hdlcd_drm_private *hdlcd = drm->dev_private; 308 struct hdlcd_drm_private *hdlcd = drm->dev_private;
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index b987c63ba8d6..21b1427fc918 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -84,11 +84,7 @@ static int hdlcd_load(struct drm_device *drm, unsigned long flags)
84 goto setup_fail; 84 goto setup_fail;
85 } 85 }
86 86
87 pm_runtime_enable(drm->dev);
88
89 pm_runtime_get_sync(drm->dev);
90 ret = drm_irq_install(drm, platform_get_irq(pdev, 0)); 87 ret = drm_irq_install(drm, platform_get_irq(pdev, 0));
91 pm_runtime_put_sync(drm->dev);
92 if (ret < 0) { 88 if (ret < 0) {
93 DRM_ERROR("failed to install IRQ handler\n"); 89 DRM_ERROR("failed to install IRQ handler\n");
94 goto irq_fail; 90 goto irq_fail;
@@ -357,6 +353,8 @@ static int hdlcd_drm_bind(struct device *dev)
357 return -ENOMEM; 353 return -ENOMEM;
358 354
359 drm->dev_private = hdlcd; 355 drm->dev_private = hdlcd;
356 dev_set_drvdata(dev, drm);
357
360 hdlcd_setup_mode_config(drm); 358 hdlcd_setup_mode_config(drm);
361 ret = hdlcd_load(drm, 0); 359 ret = hdlcd_load(drm, 0);
362 if (ret) 360 if (ret)
@@ -366,14 +364,18 @@ static int hdlcd_drm_bind(struct device *dev)
366 if (ret) 364 if (ret)
367 goto err_unload; 365 goto err_unload;
368 366
369 dev_set_drvdata(dev, drm);
370
371 ret = component_bind_all(dev, drm); 367 ret = component_bind_all(dev, drm);
372 if (ret) { 368 if (ret) {
373 DRM_ERROR("Failed to bind all components\n"); 369 DRM_ERROR("Failed to bind all components\n");
374 goto err_unregister; 370 goto err_unregister;
375 } 371 }
376 372
373 ret = pm_runtime_set_active(dev);
374 if (ret)
375 goto err_pm_active;
376
377 pm_runtime_enable(dev);
378
377 ret = drm_vblank_init(drm, drm->mode_config.num_crtc); 379 ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
378 if (ret < 0) { 380 if (ret < 0) {
379 DRM_ERROR("failed to initialise vblank\n"); 381 DRM_ERROR("failed to initialise vblank\n");
@@ -399,16 +401,16 @@ err_fbdev:
399 drm_mode_config_cleanup(drm); 401 drm_mode_config_cleanup(drm);
400 drm_vblank_cleanup(drm); 402 drm_vblank_cleanup(drm);
401err_vblank: 403err_vblank:
404 pm_runtime_disable(drm->dev);
405err_pm_active:
402 component_unbind_all(dev, drm); 406 component_unbind_all(dev, drm);
403err_unregister: 407err_unregister:
404 drm_dev_unregister(drm); 408 drm_dev_unregister(drm);
405err_unload: 409err_unload:
406 pm_runtime_get_sync(drm->dev);
407 drm_irq_uninstall(drm); 410 drm_irq_uninstall(drm);
408 pm_runtime_put_sync(drm->dev);
409 pm_runtime_disable(drm->dev);
410 of_reserved_mem_device_release(drm->dev); 411 of_reserved_mem_device_release(drm->dev);
411err_free: 412err_free:
413 dev_set_drvdata(dev, NULL);
412 drm_dev_unref(drm); 414 drm_dev_unref(drm);
413 415
414 return ret; 416 return ret;
@@ -495,30 +497,34 @@ MODULE_DEVICE_TABLE(of, hdlcd_of_match);
495static int __maybe_unused hdlcd_pm_suspend(struct device *dev) 497static int __maybe_unused hdlcd_pm_suspend(struct device *dev)
496{ 498{
497 struct drm_device *drm = dev_get_drvdata(dev); 499 struct drm_device *drm = dev_get_drvdata(dev);
498 struct drm_crtc *crtc; 500 struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL;
499 501
500 if (pm_runtime_suspended(dev)) 502 if (!hdlcd)
501 return 0; 503 return 0;
502 504
503 drm_modeset_lock_all(drm); 505 drm_kms_helper_poll_disable(drm);
504 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 506
505 hdlcd_crtc_suspend(crtc); 507 hdlcd->state = drm_atomic_helper_suspend(drm);
506 drm_modeset_unlock_all(drm); 508 if (IS_ERR(hdlcd->state)) {
509 drm_kms_helper_poll_enable(drm);
510 return PTR_ERR(hdlcd->state);
511 }
512
507 return 0; 513 return 0;
508} 514}
509 515
510static int __maybe_unused hdlcd_pm_resume(struct device *dev) 516static int __maybe_unused hdlcd_pm_resume(struct device *dev)
511{ 517{
512 struct drm_device *drm = dev_get_drvdata(dev); 518 struct drm_device *drm = dev_get_drvdata(dev);
513 struct drm_crtc *crtc; 519 struct hdlcd_drm_private *hdlcd = drm ? drm->dev_private : NULL;
514 520
515 if (!pm_runtime_suspended(dev)) 521 if (!hdlcd)
516 return 0; 522 return 0;
517 523
518 drm_modeset_lock_all(drm); 524 drm_atomic_helper_resume(drm, hdlcd->state);
519 list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) 525 drm_kms_helper_poll_enable(drm);
520 hdlcd_crtc_resume(crtc); 526 pm_runtime_set_active(dev);
521 drm_modeset_unlock_all(drm); 527
522 return 0; 528 return 0;
523} 529}
524 530
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
index aa234784f053..e7cea8233958 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.h
+++ b/drivers/gpu/drm/arm/hdlcd_drv.h
@@ -13,6 +13,7 @@ struct hdlcd_drm_private {
13 struct list_head event_list; 13 struct list_head event_list;
14 struct drm_crtc crtc; 14 struct drm_crtc crtc;
15 struct drm_plane *plane; 15 struct drm_plane *plane;
16 struct drm_atomic_state *state;
16#ifdef CONFIG_DEBUG_FS 17#ifdef CONFIG_DEBUG_FS
17 atomic_t buffer_underrun_count; 18 atomic_t buffer_underrun_count;
18 atomic_t bus_error_count; 19 atomic_t bus_error_count;
@@ -36,7 +37,5 @@ static inline u32 hdlcd_read(struct hdlcd_drm_private *hdlcd, unsigned int reg)
36 37
37int hdlcd_setup_crtc(struct drm_device *dev); 38int hdlcd_setup_crtc(struct drm_device *dev);
38void hdlcd_set_scanout(struct hdlcd_drm_private *hdlcd); 39void hdlcd_set_scanout(struct hdlcd_drm_private *hdlcd);
39void hdlcd_crtc_suspend(struct drm_crtc *crtc);
40void hdlcd_crtc_resume(struct drm_crtc *crtc);
41 40
42#endif /* __HDLCD_DRV_H__ */ 41#endif /* __HDLCD_DRV_H__ */