forked from Minki/linux
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:
parent
d5c1e84b3a
commit
f87cd8b695
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user