Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f87cd8b6 authored by Ilia Mirkin's avatar Ilia Mirkin Committed by Ben Skeggs
Browse files

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: default avatarIlia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent d5c1e84b
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -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;
	if (dev->card_type < NV_50)
		nv_wrvgac(obj, 0, 0x1f, data);
	if (nv_device(obj)->chipset == 0x11) {
	else
		nv_wrvgac(obj, 0, 0x3f, data);
	if (dev->chipset == 0x11) {
		if (!(nv_rd32(obj, 0x001084) & 0x10000000))
			nv_wrvgac(obj, 1, 0x1f, data);
	}
+15 −0
Original line number Diff line number Diff line
@@ -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,
+8 −5
Original line number Diff line number Diff line
@@ -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);
}
+5 −3
Original line number Diff line number Diff line
@@ -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);