diff options
author | Ben Skeggs <bskeggs@redhat.com> | 2014-06-28 20:44:07 +1000 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2014-08-05 09:08:29 +1000 |
commit | 4e43849f271b9b6c5301f2549789d82461dd973f (patch) | |
tree | cf54ac6189e4c954159c7c5a7a931ab470b8fc33 | |
parent | 195159f111b03221837eace8f3f45f497fb5e21e (diff) | |
download | nouveau-4e43849f271b9b6c5301f2549789d82461dd973f.tar.gz |
kms: take more care when pulling down accelerated fbcon
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r-- | drm/dispnv04/crtc.c | 4 | ||||
-rw-r--r-- | drm/nouveau_fbcon.c | 92 | ||||
-rw-r--r-- | drm/nouveau_fbcon.h | 4 |
3 files changed, 61 insertions, 39 deletions
diff --git a/drm/dispnv04/crtc.c b/drm/dispnv04/crtc.c index 41be3424c..8b17d7d49 100644 --- a/drm/dispnv04/crtc.c +++ b/drm/dispnv04/crtc.c @@ -915,9 +915,9 @@ nv04_crtc_mode_set_base_atomic(struct drm_crtc *crtc, struct drm_device *dev = drm->dev; if (state == ENTER_ATOMIC_MODE_SET) - nouveau_fbcon_save_disable_accel(dev); + nouveau_fbcon_accel_save_disable(dev); else - nouveau_fbcon_restore_accel(dev); + nouveau_fbcon_accel_restore(dev); return nv04_crtc_do_mode_set_base(crtc, fb, x, y, true); } diff --git a/drm/nouveau_fbcon.c b/drm/nouveau_fbcon.c index 758c11cb9..ba0049324 100644 --- a/drm/nouveau_fbcon.c +++ b/drm/nouveau_fbcon.c @@ -212,6 +212,58 @@ static struct fb_ops nouveau_fbcon_sw_ops = { .fb_debug_leave = drm_fb_helper_debug_leave, }; +void +nouveau_fbcon_accel_save_disable(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; + drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + } +} + +void +nouveau_fbcon_accel_restore(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + if (drm->fbcon) { + drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; + } +} + +void +nouveau_fbcon_accel_fini(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + if (fbcon && drm->channel) { + console_lock(); + fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; + console_unlock(); + nouveau_channel_idle(drm->channel); + } +} + +void +nouveau_fbcon_accel_init(struct drm_device *dev) +{ + struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_fbdev *fbcon = drm->fbcon; + struct fb_info *info = fbcon->helper.fbdev; + int ret; + + if (nv_device(drm->device)->card_type < NV_50) + ret = nv04_fbcon_accel_init(info); + else + if (nv_device(drm->device)->card_type < NV_C0) + ret = nv50_fbcon_accel_init(info); + else + ret = nvc0_fbcon_accel_init(info); + + if (ret == 0) + info->fbops = &nouveau_fbcon_ops; +} + static void nouveau_fbcon_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, u16 blue, int regno) { @@ -357,20 +409,8 @@ nouveau_fbcon_create(struct drm_fb_helper *helper, mutex_unlock(&dev->struct_mutex); - if (chan) { - ret = -ENODEV; - if (device->card_type < NV_50) - ret = nv04_fbcon_accel_init(info); - else - if (device->card_type < NV_C0) - ret = nv50_fbcon_accel_init(info); - else - ret = nvc0_fbcon_accel_init(info); - - if (ret == 0) - info->fbops = &nouveau_fbcon_ops; - } - + if (chan) + nouveau_fbcon_accel_init(dev); nouveau_fbcon_zfill(dev, fbcon); /* To allow resizeing without swapping buffers */ @@ -499,41 +539,23 @@ nouveau_fbcon_fini(struct drm_device *dev) if (!drm->fbcon) return; + nouveau_fbcon_accel_fini(dev); nouveau_fbcon_destroy(dev, drm->fbcon); kfree(drm->fbcon); drm->fbcon = NULL; } void -nouveau_fbcon_save_disable_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon) { - drm->fbcon->saved_flags = drm->fbcon->helper.fbdev->flags; - drm->fbcon->helper.fbdev->flags |= FBINFO_HWACCEL_DISABLED; - } -} - -void -nouveau_fbcon_restore_accel(struct drm_device *dev) -{ - struct nouveau_drm *drm = nouveau_drm(dev); - if (drm->fbcon) { - drm->fbcon->helper.fbdev->flags = drm->fbcon->saved_flags; - } -} - -void nouveau_fbcon_set_suspend(struct drm_device *dev, int state) { struct nouveau_drm *drm = nouveau_drm(dev); if (drm->fbcon) { console_lock(); if (state == 1) - nouveau_fbcon_save_disable_accel(dev); + nouveau_fbcon_accel_save_disable(dev); fb_set_suspend(drm->fbcon->helper.fbdev, state); if (state == 0) { - nouveau_fbcon_restore_accel(dev); + nouveau_fbcon_accel_restore(dev); nouveau_fbcon_zfill(dev, drm->fbcon); } console_unlock(); diff --git a/drm/nouveau_fbcon.h b/drm/nouveau_fbcon.h index fcff797d2..6d857e286 100644 --- a/drm/nouveau_fbcon.h +++ b/drm/nouveau_fbcon.h @@ -61,8 +61,8 @@ void nouveau_fbcon_gpu_lockup(struct fb_info *info); int nouveau_fbcon_init(struct drm_device *dev); void nouveau_fbcon_fini(struct drm_device *dev); void nouveau_fbcon_set_suspend(struct drm_device *dev, int state); -void nouveau_fbcon_save_disable_accel(struct drm_device *dev); -void nouveau_fbcon_restore_accel(struct drm_device *dev); +void nouveau_fbcon_accel_save_disable(struct drm_device *dev); +void nouveau_fbcon_accel_restore(struct drm_device *dev); void nouveau_fbcon_output_poll_changed(struct drm_device *dev); #endif /* __NV50_FBCON_H__ */ |