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>
This commit is contained in:
Ilia Mirkin 2014-01-19 04:18:15 -05:00 committed by Ben Skeggs
parent d5c1e84b3a
commit f87cd8b695
4 changed files with 35 additions and 10 deletions

View File

@ -138,10 +138,15 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
bool bool
nv_lockvgac(void *obj, bool lock) nv_lockvgac(void *obj, bool lock)
{ {
struct nouveau_device *dev = nv_device(obj);
bool locked = !nv_rdvgac(obj, 0, 0x1f); bool locked = !nv_rdvgac(obj, 0, 0x1f);
u8 data = lock ? 0x99 : 0x57; u8 data = lock ? 0x99 : 0x57;
nv_wrvgac(obj, 0, 0x1f, data); if (dev->card_type < NV_50)
if (nv_device(obj)->chipset == 0x11) { nv_wrvgac(obj, 0, 0x1f, data);
else
nv_wrvgac(obj, 0, 0x3f, data);
if (dev->chipset == 0x11) {
if (!(nv_rd32(obj, 0x001084) & 0x10000000)) if (!(nv_rd32(obj, 0x001084) & 0x10000000))
nv_wrvgac(obj, 1, 0x1f, data); nv_wrvgac(obj, 1, 0x1f, data);
} }

View File

@ -26,6 +26,7 @@
#include <subdev/bios.h> #include <subdev/bios.h>
#include <subdev/bios/init.h> #include <subdev/bios/init.h>
#include <subdev/vga.h>
#include "priv.h" #include "priv.h"
@ -38,6 +39,9 @@ _nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
if (suspend) if (suspend)
devinit->post = true; devinit->post = true;
/* unlock the extended vga crtc regs */
nv_lockvgac(devinit, false);
return nouveau_subdev_fini(&devinit->base, suspend); return nouveau_subdev_fini(&devinit->base, suspend);
} }
@ -61,6 +65,17 @@ _nouveau_devinit_init(struct nouveau_object *object)
return 0; 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 int
nouveau_devinit_create_(struct nouveau_object *parent, nouveau_devinit_create_(struct nouveau_object *parent,
struct nouveau_object *engine, struct nouveau_object *engine,

View File

@ -388,17 +388,21 @@ int
nv04_devinit_fini(struct nouveau_object *object, bool suspend) nv04_devinit_fini(struct nouveau_object *object, bool suspend)
{ {
struct nv04_devinit_priv *priv = (void *)object; struct nv04_devinit_priv *priv = (void *)object;
int ret;
/* make i2c busses accessible */ /* make i2c busses accessible */
nv_mask(priv, 0x000200, 0x00000001, 0x00000001); nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
/* unlock extended vga crtc regs, and unslave crtcs */ ret = nouveau_devinit_fini(&priv->base, suspend);
nv_lockvgac(priv, false); if (ret)
return ret;
/* unslave crtcs */
if (priv->owner < 0) if (priv->owner < 0)
priv->owner = nv_rdvgaowner(priv); priv->owner = nv_rdvgaowner(priv);
nv_wrvgaowner(priv, 0); nv_wrvgaowner(priv, 0);
return nouveau_devinit_fini(&priv->base, suspend); return 0;
} }
int int
@ -426,9 +430,8 @@ nv04_devinit_dtor(struct nouveau_object *object)
{ {
struct nv04_devinit_priv *priv = (void *)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_wrvgaowner(priv, priv->owner);
nv_lockvgac(priv, true);
nouveau_devinit_destroy(&priv->base); nouveau_devinit_destroy(&priv->base);
} }

View File

@ -15,8 +15,10 @@ struct nouveau_devinit_impl {
#define nouveau_devinit_create(p,e,o,d) \ #define nouveau_devinit_create(p,e,o,d) \
nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
#define nouveau_devinit_destroy(p) \ #define nouveau_devinit_destroy(p) ({ \
nouveau_subdev_destroy(&(p)->base) struct nouveau_devinit *d = (p); \
_nouveau_devinit_dtor(nv_object(d)); \
})
#define nouveau_devinit_init(p) ({ \ #define nouveau_devinit_init(p) ({ \
struct nouveau_devinit *d = (p); \ struct nouveau_devinit *d = (p); \
_nouveau_devinit_init(nv_object(d)); \ _nouveau_devinit_init(nv_object(d)); \
@ -28,7 +30,7 @@ struct nouveau_devinit_impl {
int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *, int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
struct nouveau_oclass *, int, void **); 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_init(struct nouveau_object *);
int _nouveau_devinit_fini(struct nouveau_object *, bool suspend); int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);