drm/nouveau/kms/gf119-: allow both 256- and 1024-sized LUTs to be used

Submitted by Ilia Mirkin on June 20, 2019, 12:11 a.m.

Details

Message ID 20190620001123.10962-1-imirkin@alum.mit.edu
State New
Headers show
Series "drm/nouveau/kms/gf119-: allow both 256- and 1024-sized LUTs to be used" ( rev: 1 ) in Nouveau

Not browsing as part of any series.

Commit Message

Ilia Mirkin June 20, 2019, 12:11 a.m.
The hardware supports either size. Also add checks to ensure that only
these two sizes may be used for supplying a LUT.

Finally, experimental evidence suggests you can't mix sizes for degamma
and gamma. Disallow this as well.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
---

Note that all the gv100+ changes are purely speculative.

Tested on a GK208 with 8- and 10-bpc formats (but still 8bpc output).

This is on top of the patches which I've sent in the past. You'll end up
with some conflicts, I suspect, but I can't rebase easily on your changes
since they're not in a linux tree.

 drivers/gpu/drm/nouveau/dispnv50/base907c.c |  4 ++--
 drivers/gpu/drm/nouveau/dispnv50/corec57d.c |  2 +-
 drivers/gpu/drm/nouveau/dispnv50/head.c     | 26 +++++++++++++++++----
 drivers/gpu/drm/nouveau/dispnv50/head.h     | 10 +++++---
 drivers/gpu/drm/nouveau/dispnv50/head507d.c | 10 +++++++-
 drivers/gpu/drm/nouveau/dispnv50/head827d.c |  2 ++
 drivers/gpu/drm/nouveau/dispnv50/head907d.c | 12 ++++++++--
 drivers/gpu/drm/nouveau/dispnv50/head917d.c |  2 ++
 drivers/gpu/drm/nouveau/dispnv50/headc37d.c |  6 +++--
 drivers/gpu/drm/nouveau/dispnv50/headc57d.c |  9 +++----
 drivers/gpu/drm/nouveau/dispnv50/lut.c      |  2 +-
 drivers/gpu/drm/nouveau/dispnv50/wndw.c     |  2 +-
 drivers/gpu/drm/nouveau/dispnv50/wndw.h     |  2 +-
 drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c |  4 ++--
 drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c |  3 +--
 15 files changed, 70 insertions(+), 26 deletions(-)

Patch hide | download patch | download mbox

diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
index fd0c1d84730b..76db448205d2 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
@@ -76,9 +76,9 @@  base907c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 }
 
 static void
-base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
 {
-	asyw->xlut.i.mode = 7;
+	asyw->xlut.i.mode = size == 1024 ? 4 : 7;
 	asyw->xlut.i.enable = 2;
 	asyw->xlut.i.load = head907d_olut_load;
 }
diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c
index b606d68cda10..700df4762b6d 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c
@@ -36,7 +36,7 @@  corec57d_init(struct nv50_core *core)
 			evo_data(push, 0x0000000f);
 			evo_data(push, 0x00000000);
 			evo_mthd(push, 0x1010 + (i * 0x080), 1);
-			evo_data(push, 0x00117fff);
+			evo_data(push, 0x00127fff);
 		}
 		evo_mthd(push, 0x0200, 1);
 		evo_data(push, 0x00000001);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index 8cac8b724b70..407c91bd09b9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -193,7 +193,23 @@  nv50_head_atomic_check_lut(struct nv50_head *head,
 			   struct nv50_head_atom *asyh)
 {
 	struct nv50_disp *disp = nv50_disp(head->base.base.dev);
+	struct drm_property_blob *ilut = asyh->state.degamma_lut;
 	struct drm_property_blob *olut = asyh->state.gamma_lut;
+	int ilut_size = ilut ? drm_color_lut_size(ilut) : 0;
+	int olut_size = olut ? drm_color_lut_size(olut) : 0;
+
+	if (!head->func->lut_chk(ilut_size)) {
+		DRM_DEBUG_KMS("Invalid DEGAMMA_LUT size: %d\n", ilut_size);
+		return -EINVAL;
+	}
+	if (!head->func->lut_chk(olut_size)) {
+		DRM_DEBUG_KMS("Invalid GAMMA_LUT size: %d\n", olut_size);
+		return -EINVAL;
+	}
+	if (ilut && olut && ilut_size != olut_size) {
+		DRM_DEBUG_KMS("DEGAMMA_LUT size (%d) must match GAMMA_LUT size (%d)\n",
+			      ilut_size, olut_size);
+	}
 
 	/* Determine whether core output LUT should be enabled. */
 	if (olut) {
@@ -217,7 +233,7 @@  nv50_head_atomic_check_lut(struct nv50_head *head,
 
 	asyh->olut.handle = disp->core->chan.vram.handle;
 	asyh->olut.buffer = !asyh->olut.buffer;
-	head->func->olut(head, asyh);
+	head->func->olut(head, asyh, olut_size);
 	return 0;
 }
 
@@ -491,12 +507,14 @@  nv50_head_create(struct drm_device *dev, int index)
 	drm_crtc_init_with_planes(dev, crtc, &wndw->plane, &curs->plane,
 				  &nv50_head_func, "head-%d", head->base.index);
 	drm_crtc_helper_add(crtc, &nv50_head_help);
-	drm_mode_crtc_set_gamma_size(crtc, 256);
+	drm_mode_crtc_set_gamma_size(crtc, head->func->lut_size);
 	if (disp->disp->object.oclass >= GF110_DISP &&
 	    disp->disp->object.oclass < GV100_DISP)
-		drm_crtc_enable_color_mgmt(crtc, 256, true, 256);
+		drm_crtc_enable_color_mgmt(crtc, head->func->lut_size, true,
+					   head->func->lut_size);
 	else
-		drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
+		drm_crtc_enable_color_mgmt(crtc, 0, false,
+					   head->func->lut_size);
 
 	if (head->func->olut_set) {
 		ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h
index d1c002f534d4..cefe589136f6 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.h
@@ -20,10 +20,12 @@  void nv50_head_flush_clr(struct nv50_head *, struct nv50_head_atom *, bool y);
 struct nv50_head_func {
 	void (*view)(struct nv50_head *, struct nv50_head_atom *);
 	void (*mode)(struct nv50_head *, struct nv50_head_atom *);
-	void (*olut)(struct nv50_head *, struct nv50_head_atom *);
+	void (*olut)(struct nv50_head *, struct nv50_head_atom *, int);
 	bool olut_identity;
 	void (*olut_set)(struct nv50_head *, struct nv50_head_atom *);
 	void (*olut_clr)(struct nv50_head *);
+	int  lut_size;
+	bool (*lut_chk)(int size);
 	void (*core_calc)(struct nv50_head *, struct nv50_head_atom *);
 	void (*core_set)(struct nv50_head *, struct nv50_head_atom *);
 	void (*core_clr)(struct nv50_head *);
@@ -43,7 +45,8 @@  struct nv50_head_func {
 extern const struct nv50_head_func head507d;
 void head507d_view(struct nv50_head *, struct nv50_head_atom *);
 void head507d_mode(struct nv50_head *, struct nv50_head_atom *);
-void head507d_olut(struct nv50_head *, struct nv50_head_atom *);
+void head507d_olut(struct nv50_head *, struct nv50_head_atom *, int);
+bool head507d_lut_chk(int);
 void head507d_core_calc(struct nv50_head *, struct nv50_head_atom *);
 void head507d_core_clr(struct nv50_head *);
 int head507d_curs_layout(struct nv50_head *, struct nv50_wndw_atom *,
@@ -60,9 +63,10 @@  extern const struct nv50_head_func head827d;
 extern const struct nv50_head_func head907d;
 void head907d_view(struct nv50_head *, struct nv50_head_atom *);
 void head907d_mode(struct nv50_head *, struct nv50_head_atom *);
-void head907d_olut(struct nv50_head *, struct nv50_head_atom *);
+void head907d_olut(struct nv50_head *, struct nv50_head_atom *, int);
 void head907d_olut_set(struct nv50_head *, struct nv50_head_atom *);
 void head907d_olut_clr(struct nv50_head *);
+bool head907d_lut_chk(int);
 void head907d_core_set(struct nv50_head *, struct nv50_head_atom *);
 void head907d_core_clr(struct nv50_head *);
 void head907d_curs_set(struct nv50_head *, struct nv50_head_atom *);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head507d.c b/drivers/gpu/drm/nouveau/dispnv50/head507d.c
index 7561be5ca707..59f06cebfce6 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head507d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head507d.c
@@ -272,7 +272,7 @@  head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 }
 
 void
-head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
 	if (asyh->base.cpp == 1)
 		asyh->olut.mode = 0;
@@ -282,6 +282,12 @@  head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 	asyh->olut.load = head507d_olut_load;
 }
 
+bool
+head507d_lut_chk(int size)
+{
+	return size == 0 || size == 256;
+}
+
 void
 head507d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
@@ -330,6 +336,8 @@  head507d = {
 	.olut = head507d_olut,
 	.olut_set = head507d_olut_set,
 	.olut_clr = head507d_olut_clr,
+	.lut_size = 256,
+	.lut_chk  = head507d_lut_chk,
 	.core_calc = head507d_core_calc,
 	.core_set = head507d_core_set,
 	.core_clr = head507d_core_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head827d.c b/drivers/gpu/drm/nouveau/dispnv50/head827d.c
index af5e7bd5978b..d69e8671b743 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head827d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head827d.c
@@ -110,6 +110,8 @@  head827d = {
 	.olut = head507d_olut,
 	.olut_set = head827d_olut_set,
 	.olut_clr = head827d_olut_clr,
+	.lut_size = 256,
+	.lut_chk  = head507d_lut_chk,
 	.core_calc = head507d_core_calc,
 	.core_set = head827d_core_set,
 	.core_clr = head507d_core_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head907d.c b/drivers/gpu/drm/nouveau/dispnv50/head907d.c
index c2d09dd97b1f..c523d3c3feb5 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head907d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head907d.c
@@ -231,12 +231,18 @@  head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 }
 
 void
-head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
-	asyh->olut.mode = 7;
+	asyh->olut.mode = size == 1024 ? 4 : 7;
 	asyh->olut.load = head907d_olut_load;
 }
 
+bool
+head907d_lut_chk(int size)
+{
+	return size == 0 || size == 256 || size == 1024;
+}
+
 void
 head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
@@ -287,6 +293,8 @@  head907d = {
 	.olut = head907d_olut,
 	.olut_set = head907d_olut_set,
 	.olut_clr = head907d_olut_clr,
+	.lut_size = 1024,
+	.lut_chk = head907d_lut_chk,
 	.core_calc = head507d_core_calc,
 	.core_set = head907d_core_set,
 	.core_clr = head907d_core_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head917d.c b/drivers/gpu/drm/nouveau/dispnv50/head917d.c
index 303df8459ca8..7e79fab52104 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head917d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head917d.c
@@ -85,6 +85,8 @@  head917d = {
 	.olut = head907d_olut,
 	.olut_set = head907d_olut_set,
 	.olut_clr = head907d_olut_clr,
+	.lut_size = 1024,
+	.lut_chk = head907d_lut_chk,
 	.core_calc = head507d_core_calc,
 	.core_set = head907d_core_set,
 	.core_clr = head907d_core_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
index ef6a99d95a9c..96ef740c6a96 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c
@@ -149,10 +149,10 @@  headc37d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
 }
 
 static void
-headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
 	asyh->olut.mode = 2;
-	asyh->olut.size = 0;
+	asyh->olut.size = size == 1024 ? 2 : 0;
 	asyh->olut.range = 0;
 	asyh->olut.output_mode = 1;
 	asyh->olut.load = head907d_olut_load;
@@ -203,6 +203,8 @@  headc37d = {
 	.olut = headc37d_olut,
 	.olut_set = headc37d_olut_set,
 	.olut_clr = headc37d_olut_clr,
+	.lut_size = 1024,
+	.lut_chk = head907d_lut_chk,
 	.curs_layout = head917d_curs_layout,
 	.curs_format = headc37d_curs_format,
 	.curs_set = headc37d_curs_set,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
index 32a7f9e85fb0..0d91ba8000cc 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c
@@ -152,13 +152,12 @@  headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 }
 
 void
-headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
 	asyh->olut.mode = 2; /* DIRECT10 */
 	asyh->olut.size = 4 /* VSS header. */ + 1024 + 1 /* Entries. */;
 	asyh->olut.output_mode = 1; /* INTERPOLATE_ENABLE. */
-	if (asyh->state.gamma_lut &&
-	    asyh->state.gamma_lut->length / sizeof(struct drm_color_lut) == 256)
+	if (size == 256)
 		asyh->olut.load = headc57d_olut_load_8;
 	else
 		asyh->olut.load = headc57d_olut_load;
@@ -183,7 +182,7 @@  headc57d_mode(struct nv50_head *head, struct nv50_head_atom *asyh)
 		evo_data(push, m->clock * 1000);
 		/*XXX: HEAD_USAGE_BOUNDS, doesn't belong here. */
 		evo_mthd(push, 0x2030 + (head->base.index * 0x400), 1);
-		evo_data(push, 0x00001014);
+		evo_data(push, 0x00001024);
 		evo_kick(push, core);
 	}
 }
@@ -196,6 +195,8 @@  headc57d = {
 	.olut_identity = true,
 	.olut_set = headc57d_olut_set,
 	.olut_clr = headc57d_olut_clr,
+	.lut_size = 1024,
+	.lut_chk = head907d_lut_chk,
 	.curs_layout = head917d_curs_layout,
 	.curs_format = headc37d_curs_format,
 	.curs_set = headc37d_curs_set,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/lut.c b/drivers/gpu/drm/nouveau/dispnv50/lut.c
index 994def4fd51a..4e95ca5604ab 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/lut.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/lut.c
@@ -49,7 +49,7 @@  nv50_lut_load(struct nv50_lut *lut, int buffer, struct drm_property_blob *blob,
 			kvfree(in);
 		}
 	} else {
-		load(in, blob->length / sizeof(*in), mem);
+		load(in, drm_color_lut_size(blob), mem);
 	}
 
 	return addr;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index cb94bc9f820f..1ecce1750a77 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -332,7 +332,7 @@  nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
 	/* Recalculate LUT state. */
 	memset(&asyw->xlut, 0x00, sizeof(asyw->xlut));
 	if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) {
-		wndw->func->ilut(wndw, asyw);
+		wndw->func->ilut(wndw, asyw, drm_color_lut_size(ilut));
 		asyw->xlut.handle = wndw->wndw.vram.handle;
 		asyw->xlut.i.buffer = !asyw->xlut.i.buffer;
 		asyw->set.xlut = true;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
index 1e781d80c990..0a4cf6903b67 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -64,7 +64,7 @@  struct nv50_wndw_func {
 	void (*ntfy_clr)(struct nv50_wndw *);
 	int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset,
 			       struct nvif_device *);
-	void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *);
+	void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *, int);
 	void (*csc)(struct nv50_wndw *, struct nv50_wndw_atom *,
 		    const struct drm_color_ctm *);
 	void (*csc_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
index 826d1d760d3a..776cda7e5377 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
@@ -55,10 +55,10 @@  wndwc37e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 }
 
 static void
-wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
 {
 	asyw->xlut.i.mode = 2;
-	asyw->xlut.i.size = 0;
+	asyw->xlut.i.size = size == 1024 ? 2 : 0;
 	asyw->xlut.i.range = 0;
 	asyw->xlut.i.output_mode = 1;
 	asyw->xlut.i.load = head907d_olut_load;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
index ba89f1a5fcfa..45348dbe9e59 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
@@ -91,9 +91,8 @@  wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem)
 }
 
 static void
-wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
 {
-	u16 size = asyw->ilut->length / sizeof(struct drm_color_lut);
 	if (size == 256) {
 		asyw->xlut.i.mode = 1; /* DIRECT8. */
 	} else {