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
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);
}

View 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,

View 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);
}

View 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);