summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorIlia Mirkin <imirkin@alum.mit.edu>2014-01-19 13:18:15 +0400
committerBen Skeggs <bskeggs@redhat.com>2014-01-23 07:39:15 +0400
commitf87cd8b695d372087685976460fac1ec6ba2fca9 (patch)
tree8c46a2f23bc25618beb134bf3d7a11f0cf228e28 /drivers/gpu
parentd5c1e84b3a130f0743b218b33ff7d9cb493ab5b4 (diff)
downloadlinux-f87cd8b695d372087685976460fac1ec6ba2fca9.tar.xz
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 <imirkin@alum.mit.edu> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/vga.c9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/base.c15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c13
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h8
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 <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,
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);