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

Commit b38a2322 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nv50-/disp: add support for completion events



Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 996f5a08
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -68,6 +68,10 @@ gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	if (ret)
	if (ret)
		return ret;
		return ret;


	ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
	if (ret)
		return ret;

	nv_engine(priv)->sclass = gm107_disp_base_oclass;
	nv_engine(priv)->sclass = gm107_disp_base_oclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_subdev(priv)->intr = nvd0_disp_intr;
	nv_subdev(priv)->intr = nvd0_disp_intr;
+85 −4
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@
#include <core/enum.h>
#include <core/enum.h>
#include <nvif/unpack.h>
#include <nvif/unpack.h>
#include <nvif/class.h>
#include <nvif/class.h>
#include <nvif/event.h>


#include <subdev/bios.h>
#include <subdev/bios.h>
#include <subdev/bios/dcb.h>
#include <subdev/bios/dcb.h>
@@ -82,6 +83,71 @@ nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
	nouveau_namedb_destroy(&chan->base);
	nouveau_namedb_destroy(&chan->base);
}
}


static void
nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
{
	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
}

static void
nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
{
	struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
	nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
}

void
nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
{
	struct nvif_notify_uevent_rep {
	} rep;

	nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
}

int
nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
			   struct nvkm_notify *notify)
{
	struct nv50_disp_dmac *dmac = (void *)object;
	union {
		struct nvif_notify_uevent_req none;
	} *args = data;
	int ret;

	if (nvif_unvers(args->none)) {
		notify->size  = sizeof(struct nvif_notify_uevent_rep);
		notify->types = 1;
		notify->index = dmac->base.chid;
		return 0;
	}

	return ret;
}

const struct nvkm_event_func
nv50_disp_chan_uevent = {
	.ctor = nv50_disp_chan_uevent_ctor,
	.init = nv50_disp_chan_uevent_init,
	.fini = nv50_disp_chan_uevent_fini,
};

int
nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type,
		    struct nvkm_event **pevent)
{
	struct nv50_disp_priv *priv = (void *)object->engine;
	switch (type) {
	case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
		*pevent = &priv->uevent;
		return 0;
	default:
		break;
	}
	return -EINVAL;
}

int
int
nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
{
{
@@ -195,7 +261,7 @@ nv50_disp_dmac_init(struct nouveau_object *object)
		return ret;
		return ret;


	/* enable error reporting */
	/* enable error reporting */
	nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid);
	nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);


	/* initialise channel for dma command submission */
	/* initialise channel for dma command submission */
	nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
	nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
@@ -232,7 +298,7 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
			return -EBUSY;
			return -EBUSY;
	}
	}


	/* disable error reporting */
	/* disable error reporting and completion notifications */
	nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
	nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);


	return nv50_disp_chan_fini(&dmac->base, suspend);
	return nv50_disp_chan_fini(&dmac->base, suspend);
@@ -454,7 +520,7 @@ nv50_disp_mast_init(struct nouveau_object *object)
		return ret;
		return ret;


	/* enable error reporting */
	/* enable error reporting */
	nv_mask(priv, 0x610028, 0x00010001, 0x00010001);
	nv_mask(priv, 0x610028, 0x00010000, 0x00010000);


	/* attempt to unstick channel from some unknown state */
	/* attempt to unstick channel from some unknown state */
	if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
	if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
@@ -494,7 +560,7 @@ nv50_disp_mast_fini(struct nouveau_object *object, bool suspend)
			return -EBUSY;
			return -EBUSY;
	}
	}


	/* disable error reporting */
	/* disable error reporting and completion notifications */
	nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
	nv_mask(priv, 0x610028, 0x00010001, 0x00000000);


	return nv50_disp_chan_fini(&mast->base, suspend);
	return nv50_disp_chan_fini(&mast->base, suspend);
@@ -507,6 +573,7 @@ nv50_disp_mast_ofuncs = {
	.base.init = nv50_disp_mast_init,
	.base.init = nv50_disp_mast_init,
	.base.fini = nv50_disp_mast_fini,
	.base.fini = nv50_disp_mast_fini,
	.base.map  = nv50_disp_chan_map,
	.base.map  = nv50_disp_chan_map,
	.base.ntfy = nv50_disp_chan_ntfy,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.wr32 = nv50_disp_chan_wr32,
	.base.wr32 = nv50_disp_chan_wr32,
	.chid = 0,
	.chid = 0,
@@ -607,6 +674,7 @@ nv50_disp_sync_ofuncs = {
	.base.dtor = nv50_disp_dmac_dtor,
	.base.dtor = nv50_disp_dmac_dtor,
	.base.init = nv50_disp_dmac_init,
	.base.init = nv50_disp_dmac_init,
	.base.fini = nv50_disp_dmac_fini,
	.base.fini = nv50_disp_dmac_fini,
	.base.ntfy = nv50_disp_chan_ntfy,
	.base.map  = nv50_disp_chan_map,
	.base.map  = nv50_disp_chan_map,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.wr32 = nv50_disp_chan_wr32,
	.base.wr32 = nv50_disp_chan_wr32,
@@ -696,6 +764,7 @@ nv50_disp_ovly_ofuncs = {
	.base.dtor = nv50_disp_dmac_dtor,
	.base.dtor = nv50_disp_dmac_dtor,
	.base.init = nv50_disp_dmac_init,
	.base.init = nv50_disp_dmac_init,
	.base.fini = nv50_disp_dmac_fini,
	.base.fini = nv50_disp_dmac_fini,
	.base.ntfy = nv50_disp_chan_ntfy,
	.base.map  = nv50_disp_chan_map,
	.base.map  = nv50_disp_chan_map,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.wr32 = nv50_disp_chan_wr32,
	.base.wr32 = nv50_disp_chan_wr32,
@@ -813,6 +882,7 @@ nv50_disp_oimm_ofuncs = {
	.base.dtor = nv50_disp_pioc_dtor,
	.base.dtor = nv50_disp_pioc_dtor,
	.base.init = nv50_disp_pioc_init,
	.base.init = nv50_disp_pioc_init,
	.base.fini = nv50_disp_pioc_fini,
	.base.fini = nv50_disp_pioc_fini,
	.base.ntfy = nv50_disp_chan_ntfy,
	.base.map  = nv50_disp_chan_map,
	.base.map  = nv50_disp_chan_map,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.wr32 = nv50_disp_chan_wr32,
	.base.wr32 = nv50_disp_chan_wr32,
@@ -860,6 +930,7 @@ nv50_disp_curs_ofuncs = {
	.base.dtor = nv50_disp_pioc_dtor,
	.base.dtor = nv50_disp_pioc_dtor,
	.base.init = nv50_disp_pioc_init,
	.base.init = nv50_disp_pioc_init,
	.base.fini = nv50_disp_pioc_fini,
	.base.fini = nv50_disp_pioc_fini,
	.base.ntfy = nv50_disp_chan_ntfy,
	.base.map  = nv50_disp_chan_map,
	.base.map  = nv50_disp_chan_map,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.rd32 = nv50_disp_chan_rd32,
	.base.wr32 = nv50_disp_chan_wr32,
	.base.wr32 = nv50_disp_chan_wr32,
@@ -1846,6 +1917,12 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
		intr0 &= ~(0x00010000 << chid);
		intr0 &= ~(0x00010000 << chid);
	}
	}


	while (intr0 & 0x0000001f) {
		u32 chid = __ffs(intr0 & 0x0000001f);
		nv50_disp_chan_uevent_send(priv, chid);
		intr0 &= ~(0x00000001 << chid);
	}

	if (intr1 & 0x00000004) {
	if (intr1 & 0x00000004) {
		nouveau_disp_vblank(&priv->base, 0);
		nouveau_disp_vblank(&priv->base, 0);
		nv_wr32(priv, 0x610024, 0x00000004);
		nv_wr32(priv, 0x610024, 0x00000004);
@@ -1880,6 +1957,10 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	if (ret)
	if (ret)
		return ret;
		return ret;


	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
	if (ret)
		return ret;

	nv_engine(priv)->sclass = nv50_disp_base_oclass;
	nv_engine(priv)->sclass = nv50_disp_base_oclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_subdev(priv)->intr = nv50_disp_intr;
	nv_subdev(priv)->intr = nv50_disp_intr;
+9 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@ struct nv50_disp_priv {
	struct work_struct supervisor;
	struct work_struct supervisor;
	u32 super;
	u32 super;


	struct nvkm_event uevent;

	struct {
	struct {
		int nr;
		int nr;
	} head;
	} head;
@@ -116,9 +118,16 @@ struct nv50_disp_chan {
	int chid;
	int chid;
};
};


int  nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
int  nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
int  nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
u32  nv50_disp_chan_rd32(struct nouveau_object *, u64);
u32  nv50_disp_chan_rd32(struct nouveau_object *, u64);
void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
extern const struct nvkm_event_func nv50_disp_chan_uevent;
int  nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
				struct nvkm_notify *);
void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);

extern const struct nvkm_event_func nvd0_disp_chan_uevent;


#define nv50_disp_chan_init(a)                                                 \
#define nv50_disp_chan_init(a)                                                 \
	nouveau_namedb_init(&(a)->base)
	nouveau_namedb_init(&(a)->base)
+4 −0
Original line number Original line Diff line number Diff line
@@ -236,6 +236,10 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	if (ret)
	if (ret)
		return ret;
		return ret;


	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
	if (ret)
		return ret;

	nv_engine(priv)->sclass = nv84_disp_base_oclass;
	nv_engine(priv)->sclass = nv84_disp_base_oclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_subdev(priv)->intr = nv50_disp_intr;
	nv_subdev(priv)->intr = nv50_disp_intr;
+4 −0
Original line number Original line Diff line number Diff line
@@ -95,6 +95,10 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
	if (ret)
	if (ret)
		return ret;
		return ret;


	ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
	if (ret)
		return ret;

	nv_engine(priv)->sclass = nv94_disp_base_oclass;
	nv_engine(priv)->sclass = nv94_disp_base_oclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_engine(priv)->cclass = &nv50_disp_cclass;
	nv_subdev(priv)->intr = nv50_disp_intr;
	nv_subdev(priv)->intr = nv50_disp_intr;
Loading