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

drm/nouveau/kms/gf119-: add ctm property support



This adds support on GF119:GV100 (exclusive) for CTM (aka CSC).

Signed-off-by: default avatarIlia Mirkin <imirkin@alum.mit.edu>
parent 7c844e9d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -184,6 +184,11 @@ struct nv50_wndw_atom {
		} i;
	} xlut;

	struct {
		u32 matrix[12];
		bool valid;
	} csc;

	struct {
		u8  mode:2;
		u8  interval:4;
@@ -221,6 +226,7 @@ struct nv50_wndw_atom {
			bool ntfy:1;
			bool sema:1;
			bool xlut:1;
			bool csc:1;
			bool image:1;
			bool scale:1;
			bool point:1;
+65 −0
Original line number Diff line number Diff line
@@ -83,6 +83,68 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
	asyw->xlut.i.load = head907d_olut_load;
}

static inline u32
csc_drm_to_base(u64 in)
{
	/* base takes a 19-bit 2's complement value in S3.16 format */
	bool sign = in & BIT_ULL(63);
	u32 integer = (in >> 32) & 0x7fffffff;
	u32 fraction = in & 0xffffffff;

	if (integer >= 4) {
		return (1 << 18) - (sign ? 0 : 1);
	} else {
		u32 ret = (integer << 16) | (fraction >> 16);
		if (sign)
			ret = -ret;
		return ret & GENMASK(18, 0);
	}
}

static void
base907c_csc(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
	     const struct drm_color_ctm *ctm)
{
	int i, j;

	for (j = 0; j < 3; j++) {
		for (i = 0; i < 4; i++) {
			u32 *val = &asyw->csc.matrix[j * 4 + i];
			/* DRM does not support constant offset, while
			 * HW CSC does. Skip it. */
			if (i == 3) {
				*val = 0;
			} else {
				*val = csc_drm_to_base(ctm->matrix[j * 3 + i]);
			}
		}
	}
}

static void
base907c_csc_clr(struct nv50_wndw *wndw)
{
	u32 *push;
	if ((push = evo_wait(&wndw->wndw, 2))) {
		evo_mthd(push, 0x0140, 1);
		evo_data(push, 0x00000000);
		evo_kick(push, &wndw->wndw);
	}
}

static void
base907c_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
	u32 *push, i;
	if ((push = evo_wait(&wndw->wndw, 13))) {
		evo_mthd(push, 0x0140, 12);
		evo_data(push, asyw->csc.matrix[0] | 0x80000000);
		for (i = 1; i < 12; i++)
			evo_data(push, asyw->csc.matrix[i]);
		evo_kick(push, &wndw->wndw);
	}
}

const struct nv50_wndw_func
base907c = {
	.acquire = base507c_acquire,
@@ -94,6 +156,9 @@ base907c = {
	.ntfy_clr = base507c_ntfy_clr,
	.ntfy_wait_begun = base507c_ntfy_wait_begun,
	.ilut = base907c_ilut,
	.csc = base907c_csc,
	.csc_set = base907c_csc_set,
	.csc_clr = base907c_csc_clr,
	.olut_core = true,
	.xlut_set = base907c_xlut_set,
	.xlut_clr = base907c_xlut_clr,
+14 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 *interlock, bool flush,
	if (clr.sema ) wndw->func-> sema_clr(wndw);
	if (clr.ntfy ) wndw->func-> ntfy_clr(wndw);
	if (clr.xlut ) wndw->func-> xlut_clr(wndw);
	if (clr.csc  ) wndw->func->  csc_clr(wndw);
	if (clr.image) wndw->func->image_clr(wndw);

	interlock[wndw->interlock.type] |= wndw->interlock.data;
@@ -147,6 +148,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
		wndw->func->xlut_set(wndw, asyw);
	}

	if (asyw->set.csc  ) wndw->func->csc_set  (wndw, asyw);
	if (asyw->set.scale) wndw->func->scale_set(wndw, asyw);
	if (asyw->set.point) {
		if (asyw->set.point = false, asyw->set.mask)
@@ -347,6 +349,16 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
	    (!armw->visible || (armw->xlut.handle && !asyw->xlut.handle)))
		asyw->set.xlut = true;

	if (wndw->func->csc && asyh->state.ctm) {
		const struct drm_color_ctm *ctm = asyh->state.ctm->data;
		wndw->func->csc(wndw, asyw, ctm);
		asyw->csc.valid = true;
		asyw->set.csc = true;
	} else {
		asyw->csc.valid = false;
		asyw->clr.csc = armw->csc.valid;
	}

	/* Can't do an immediate flip while changing the LUT. */
	asyh->state.pageflip_flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
}
@@ -416,6 +428,7 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
		asyw->clr.ntfy = armw->ntfy.handle != 0;
		asyw->clr.sema = armw->sema.handle != 0;
		asyw->clr.xlut = armw->xlut.handle != 0;
		asyw->clr.csc  = armw->csc.valid;
		if (wndw->func->image_clr)
			asyw->clr.image = armw->image.handle[0] != 0;
	}
@@ -507,6 +520,7 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
	asyw->ntfy = armw->ntfy;
	asyw->ilut = NULL;
	asyw->xlut = armw->xlut;
	asyw->csc  = armw->csc;
	asyw->image = armw->image;
	asyw->point = armw->point;
	asyw->clr.mask = 0;
+4 −0
Original line number Diff line number Diff line
@@ -65,6 +65,10 @@ struct nv50_wndw_func {
	int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset,
			       struct nvif_device *);
	void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *);
	void (*csc)(struct nv50_wndw *, struct nv50_wndw_atom *,
		    const struct drm_color_ctm *);
	void (*csc_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
	void (*csc_clr)(struct nv50_wndw *);
	bool ilut_identity;
	bool olut_core;
	void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);