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

Signed-off-by: Ilia Mirkin <imir...@alum.mit.edu>
---
 drivers/gpu/drm/nouveau/dispnv50/atom.h     |  6 ++
 drivers/gpu/drm/nouveau/dispnv50/base907c.c | 65 +++++++++++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/wndw.c     | 13 +++++
 drivers/gpu/drm/nouveau/dispnv50/wndw.h     |  4 ++
 4 files changed, 88 insertions(+)

diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h 
b/drivers/gpu/drm/nouveau/dispnv50/atom.h
index b5fae5ab3fa8..894d1fec6f0a 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -184,6 +184,11 @@ struct nv50_wndw_atom {
                } i;
        } xlut;
 
+       struct {
+               u32 matrix[12];
+               bool valid;
+       } ctm;
+
        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 ctm:1;
                        bool image:1;
                        bool scale:1;
                        bool point:1;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c 
b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
index 049ce6da321c..ceadc2e3efe9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
@@ -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
+ctm_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_ctm(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->ctm.matrix[j * 4 + i];
+                       /* CTM does not support constant offset, while
+                        * HW CSC does. Skip it. */
+                       if (i == 3) {
+                               *val = 0;
+                       } else {
+                               *val = ctm_drm_to_base(ctm->matrix[j * 3 + i]);
+                       }
+               }
+       }
+}
+
+static void
+base907c_ctm_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_ctm_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->ctm.matrix[0] | 0x80000000);
+               for (i = 1; i < 12; i++)
+                       evo_data(push, asyw->ctm.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,
+       .ctm = base907c_ctm,
+       .ctm_set = base907c_ctm_set,
+       .ctm_clr = base907c_ctm_clr,
        .olut_core = true,
        .xlut_set = base907c_xlut_set,
        .xlut_clr = base907c_xlut_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c 
b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 3bee1f063dfb..2ae3ca9a5968 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -118,6 +118,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.ctm  ) wndw->func->  ctm_clr(wndw);
        if (clr.image) wndw->func->image_clr(wndw);
 
        interlock[wndw->interlock.type] |= wndw->interlock.data;
@@ -145,6 +146,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
                wndw->func->xlut_set(wndw, asyw);
        }
 
+       if (asyw->set.ctm  ) wndw->func->ctm_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)
@@ -341,6 +343,15 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
            (!armw->visible || (armw->xlut.handle && !asyw->xlut.handle)))
                asyw->set.xlut = true;
 
+       if (wndw->func->ctm && asyh->state.ctm) {
+               const struct drm_color_ctm *ctm = asyh->state.ctm->data;
+               wndw->func->ctm(wndw, asyw, ctm);
+               asyw->ctm.valid = true;
+               asyw->set.ctm = true;
+       } else {
+               asyw->clr.ctm = armw->ctm.valid;
+       }
+
        /* Can't do an immediate flip while changing the LUT. */
        asyh->state.pageflip_flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
 }
@@ -410,6 +421,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.ctm  = armw->ctm.valid;
                if (wndw->func->image_clr)
                        asyw->clr.image = armw->image.handle[0] != 0;
        }
@@ -501,6 +513,7 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
        asyw->ntfy = armw->ntfy;
        asyw->ilut = NULL;
        asyw->xlut = armw->xlut;
+       asyw->ctm  = armw->ctm;
        asyw->image = armw->image;
        asyw->point = armw->point;
        asyw->clr.mask = 0;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h 
b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
index 03f3d8dc235a..b6bdc6617a59 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -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 (*ctm)(struct nv50_wndw *, struct nv50_wndw_atom *,
+                   const struct drm_color_ctm *);
+       void (*ctm_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
+       void (*ctm_clr)(struct nv50_wndw *);
        bool ilut_identity;
        bool olut_core;
        void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
-- 
2.21.0

_______________________________________________
Nouveau mailing list
Nouveau@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/nouveau

Reply via email to