drm/nouveau/devinit: lock/unlock crtc regs for all devices, not just pre-nv50
authorIlia Mirkin <imirkin@alum.mit.edu>
Sun, 19 Jan 2014 09:18:15 +0000 (04:18 -0500)
committerBen Skeggs <bskeggs@redhat.com>
Thu, 23 Jan 2014 03:39:15 +0000 (13:39 +1000)
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 <imirkin@alum.mit.edu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
drivers/gpu/drm/nouveau/core/engine/disp/vga.c
drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h

index 5a1c68474597cbc979eb216735941714b1ce4901..8836c3cb99c3862a84ed2b946e6c3e34c47e520d 100644 (file)
@@ -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);
        }
index 6b23d9a0b95364008d53d6b166c06627ede333bf..8fa34e8152c20b6ae90f2ca020f6c49a077f2cdd 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <subdev/bios.h>
 #include <subdev/bios/init.h>
+#include <subdev/vga.h>
 
 #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,
index 24025e4e882a211a9ec9e548f3e9da42afa87bc3..7037eae46e445bd5d3278dfc70119dac180cadbb 100644 (file)
@@ -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);
 }
index c4179b6d6ecafbb40f29a6c64193c364a5ab8c99..822a2fbf44a5b3d601d5c79eedb7b2af68654d86 100644 (file)
@@ -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);