Commit b14617aa authored by Ben Skeggs's avatar Ben Skeggs Committed by Luis Henriques

drm/nouveau/kms: take more care when pulling down accelerated fbcon

commit 4b5098f3 upstream.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Cc: Sven Joachim <svenjoac@gmx.de>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent fa379a7b
......@@ -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);
}
......
......@@ -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 */
......@@ -498,30 +538,12 @@ 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)
{
......@@ -529,10 +551,10 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
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();
......
......@@ -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__ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment