Skip to content

Commit

Permalink
drm/nouveau/devinit: lock/unlock crtc regs for all devices, not just …
Browse files Browse the repository at this point in the history
…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>
  • Loading branch information
Ilia Mirkin authored and Ben Skeggs committed Jan 23, 2014
1 parent d5c1e84 commit f87cd8b
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
9 changes: 7 additions & 2 deletions drivers/gpu/drm/nouveau/core/engine/disp/vga.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
15 changes: 15 additions & 0 deletions drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <subdev/bios.h>
#include <subdev/bios/init.h>
#include <subdev/vga.h>

#include "priv.h"

Expand All @@ -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);
}

Expand All @@ -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,
Expand Down
13 changes: 8 additions & 5 deletions drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
8 changes: 5 additions & 3 deletions drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)); \
Expand All @@ -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);

Expand Down

0 comments on commit f87cd8b

Please sign in to comment.