From f62b27db6b5479efe376b408802a081a834ef50e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 9 Nov 2011 15:18:47 +1000 Subject: [PATCH] drm/nouveau: shutdown display on suspend/hibernate Known to fix some serious issues with hibernate on a couple of systems. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_display.c | 42 ++++++++++++++++++++--- drivers/gpu/drm/nouveau/nouveau_drv.c | 6 ++-- drivers/gpu/drm/nouveau/nouveau_drv.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_state.c | 6 ++-- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 803248d467fb..6ac6931624f4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -206,6 +206,31 @@ static struct drm_prop_enum_list dither_depth[] = { } \ } while(0) +int +nouveau_display_init(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_display_engine *disp = &dev_priv->engine.display; + int ret; + + ret = disp->init(dev); + if (ret == 0) { + drm_kms_helper_poll_enable(dev); + } + + return ret; +} + +void +nouveau_display_fini(struct drm_device *dev) +{ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_display_engine *disp = &dev_priv->engine.display; + + drm_kms_helper_poll_disable(dev); + disp->fini(dev); +} + int nouveau_display_create(struct drm_device *dev) { @@ -258,13 +283,19 @@ nouveau_display_create(struct drm_device *dev) dev->mode_config.max_height = 8192; } + drm_kms_helper_poll_init(dev); + drm_kms_helper_poll_disable(dev); + ret = disp->create(dev); if (ret) return ret; - ret = disp->init(dev); - if (ret) - disp->destroy(dev); + if (dev->mode_config.num_crtc) { + ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + if (ret) + return ret; + } + return ret; } @@ -274,8 +305,11 @@ nouveau_display_destroy(struct drm_device *dev) struct drm_nouveau_private *dev_priv = dev->dev_private; struct nouveau_display_engine *disp = &dev_priv->engine.display; - disp->fini(dev); + drm_vblank_cleanup(dev); + disp->destroy(dev); + + drm_kms_helper_poll_fini(dev); drm_mode_config_cleanup(dev); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.c b/drivers/gpu/drm/nouveau/nouveau_drv.c index cb357ab3670c..e4485404892e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.c +++ b/drivers/gpu/drm/nouveau/nouveau_drv.c @@ -178,7 +178,8 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - drm_kms_helper_poll_disable(dev); + NV_INFO(dev, "Disabling display...\n"); + nouveau_display_fini(dev); NV_INFO(dev, "Disabling fbcon...\n"); nouveau_fbcon_set_suspend(dev, 1); @@ -357,8 +358,7 @@ nouveau_pci_resume(struct pci_dev *pdev) nouveau_fbcon_set_suspend(dev, 0); nouveau_fbcon_zfill_all(dev); - engine->display.init(dev); - drm_kms_helper_poll_enable(dev); + nouveau_display_init(dev); /* Force CLUT to get re-loaded during modeset */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index a22ca4735943..c13918588034 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -1449,6 +1449,8 @@ extern int nouveau_gem_ioctl_info(struct drm_device *, void *, /* nouveau_display.c */ int nouveau_display_create(struct drm_device *dev); void nouveau_display_destroy(struct drm_device *dev); +int nouveau_display_init(struct drm_device *dev); +void nouveau_display_fini(struct drm_device *dev); int nouveau_vblank_enable(struct drm_device *dev, int crtc); void nouveau_vblank_disable(struct drm_device *dev, int crtc); int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c index 0c3368b36e6c..013b33bac302 100644 --- a/drivers/gpu/drm/nouveau/nouveau_state.c +++ b/drivers/gpu/drm/nouveau/nouveau_state.c @@ -763,12 +763,11 @@ nouveau_card_init(struct drm_device *dev) } if (dev->mode_config.num_crtc) { - ret = drm_vblank_init(dev, dev->mode_config.num_crtc); + ret = nouveau_display_init(dev); if (ret) goto out_chan; nouveau_fbcon_init(dev); - drm_kms_helper_poll_init(dev); } return 0; @@ -829,9 +828,8 @@ static void nouveau_card_takedown(struct drm_device *dev) int e; if (dev->mode_config.num_crtc) { - drm_kms_helper_poll_fini(dev); nouveau_fbcon_fini(dev); - drm_vblank_cleanup(dev); + nouveau_display_fini(dev); } if (dev_priv->channel) {