From f87cd8b695d372087685976460fac1ec6ba2fca9 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Sun, 19 Jan 2014 04:18:15 -0500 Subject: [PATCH] drm/nouveau/devinit: lock/unlock crtc regs for all devices, not just pre-nv50 Also make nv_lockvgac work for nv50+ devices. This should fix IO_CONDITION and related VBIOS opcodes that read/write the crtc regs. See https://bugs.freedesktop.org/show_bug.cgi?id=60680 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/core/engine/disp/vga.c | 9 +++++++-- .../gpu/drm/nouveau/core/subdev/devinit/base.c | 15 +++++++++++++++ .../gpu/drm/nouveau/core/subdev/devinit/nv04.c | 13 ++++++++----- .../gpu/drm/nouveau/core/subdev/devinit/priv.h | 8 +++++--- 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c index 5a1c68474597..8836c3cb99c3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c @@ -138,10 +138,15 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) bool nv_lockvgac(void *obj, bool lock) { + struct nouveau_device *dev = nv_device(obj); + bool locked = !nv_rdvgac(obj, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; - nv_wrvgac(obj, 0, 0x1f, data); - if (nv_device(obj)->chipset == 0x11) { + if (dev->card_type < NV_50) + nv_wrvgac(obj, 0, 0x1f, data); + else + nv_wrvgac(obj, 0, 0x3f, data); + if (dev->chipset == 0x11) { if (!(nv_rd32(obj, 0x001084) & 0x10000000)) nv_wrvgac(obj, 1, 0x1f, data); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 6b23d9a0b953..8fa34e8152c2 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -26,6 +26,7 @@ #include #include +#include #include "priv.h" @@ -38,6 +39,9 @@ _nouveau_devinit_fini(struct nouveau_object *object, bool suspend) if (suspend) devinit->post = true; + /* unlock the extended vga crtc regs */ + nv_lockvgac(devinit, false); + return nouveau_subdev_fini(&devinit->base, suspend); } @@ -61,6 +65,17 @@ _nouveau_devinit_init(struct nouveau_object *object) return 0; } +void +_nouveau_devinit_dtor(struct nouveau_object *object) +{ + struct nouveau_devinit *devinit = (void *)object; + + /* lock crtc regs */ + nv_lockvgac(devinit, true); + + nouveau_subdev_destroy(&devinit->base); +} + int nouveau_devinit_create_(struct nouveau_object *parent, struct nouveau_object *engine, diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index 24025e4e882a..7037eae46e44 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -388,17 +388,21 @@ int nv04_devinit_fini(struct nouveau_object *object, bool suspend) { struct nv04_devinit_priv *priv = (void *)object; + int ret; /* make i2c busses accessible */ nv_mask(priv, 0x000200, 0x00000001, 0x00000001); - /* unlock extended vga crtc regs, and unslave crtcs */ - nv_lockvgac(priv, false); + ret = nouveau_devinit_fini(&priv->base, suspend); + if (ret) + return ret; + + /* unslave crtcs */ if (priv->owner < 0) priv->owner = nv_rdvgaowner(priv); nv_wrvgaowner(priv, 0); - return nouveau_devinit_fini(&priv->base, suspend); + return 0; } int @@ -426,9 +430,8 @@ nv04_devinit_dtor(struct nouveau_object *object) { struct nv04_devinit_priv *priv = (void *)object; - /* restore vga owner saved at first init, and lock crtc regs */ + /* restore vga owner saved at first init */ nv_wrvgaowner(priv, priv->owner); - nv_lockvgac(priv, true); nouveau_devinit_destroy(&priv->base); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h index c4179b6d6eca..822a2fbf44a5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h @@ -15,8 +15,10 @@ struct nouveau_devinit_impl { #define nouveau_devinit_create(p,e,o,d) \ nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nouveau_devinit_destroy(p) \ - nouveau_subdev_destroy(&(p)->base) +#define nouveau_devinit_destroy(p) ({ \ + struct nouveau_devinit *d = (p); \ + _nouveau_devinit_dtor(nv_object(d)); \ +}) #define nouveau_devinit_init(p) ({ \ struct nouveau_devinit *d = (p); \ _nouveau_devinit_init(nv_object(d)); \ @@ -28,7 +30,7 @@ struct nouveau_devinit_impl { int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, int, void **); -#define _nouveau_devinit_dtor _nouveau_subdev_dtor +void _nouveau_devinit_dtor(struct nouveau_object *); int _nouveau_devinit_init(struct nouveau_object *); int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);