drm/nouveau/kms/gf119-: allow both 256- and 1024-sized LUTs to be used
authorIlia Mirkin <imirkin@alum.mit.edu>
Fri, 6 Sep 2019 04:13:59 +0000 (00:13 -0400)
committerBen Skeggs <bskeggs@redhat.com>
Wed, 15 Jan 2020 00:49:58 +0000 (10:49 +1000)
The hardware supports either size. Also add checks to ensure that only
these two sizes may be used for supplying a LUT.

Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
14 files changed:
drivers/gpu/drm/nouveau/dispnv50/base907c.c
drivers/gpu/drm/nouveau/dispnv50/head.c
drivers/gpu/drm/nouveau/dispnv50/head.h
drivers/gpu/drm/nouveau/dispnv50/head507d.c
drivers/gpu/drm/nouveau/dispnv50/head827d.c
drivers/gpu/drm/nouveau/dispnv50/head907d.c
drivers/gpu/drm/nouveau/dispnv50/head917d.c
drivers/gpu/drm/nouveau/dispnv50/headc37d.c
drivers/gpu/drm/nouveau/dispnv50/headc57d.c
drivers/gpu/drm/nouveau/dispnv50/lut.c
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/dispnv50/wndw.h
drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c

index 5f2de77e0f32e1bcce6a48a41c1546f4ba9b09a8..224a34c340fe72f49ae7900594a9a30b36b1fcc5 100644 (file)
@@ -75,12 +75,16 @@ 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)
+static bool
+base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
 {
-       asyw->xlut.i.mode = 7;
+       if (size != 256 && size != 1024)
+               return false;
+
+       asyw->xlut.i.mode = size == 1024 ? 4 : 7;
        asyw->xlut.i.enable = 2;
        asyw->xlut.i.load = head907d_olut_load;
+       return true;
 }
 
 static inline u32
@@ -160,6 +164,7 @@ base907c = {
        .csc_set = base907c_csc_set,
        .csc_clr = base907c_csc_clr,
        .olut_core = true,
+       .ilut_size = 1024,
        .xlut_set = base907c_xlut_set,
        .xlut_clr = base907c_xlut_clr,
        .image_set = base907c_image_set,
index c9692df2b76cca51604c0fb008643ff26a972be0..f64c87dfc1d0ab3a4563ec86f83d6bc31564b25d 100644 (file)
@@ -213,6 +213,7 @@ nv50_head_atomic_check_lut(struct nv50_head *head,
 {
        struct nv50_disp *disp = nv50_disp(head->base.base.dev);
        struct drm_property_blob *olut = asyh->state.gamma_lut;
+       int size;
 
        /* Determine whether core output LUT should be enabled. */
        if (olut) {
@@ -229,14 +230,23 @@ nv50_head_atomic_check_lut(struct nv50_head *head,
                }
        }
 
-       if (!olut && !head->func->olut_identity) {
-               asyh->olut.handle = 0;
-               return 0;
+       if (!olut) {
+               if (!head->func->olut_identity) {
+                       asyh->olut.handle = 0;
+                       return 0;
+               }
+               size = 0;
+       } else {
+               size = drm_color_lut_size(olut);
        }
 
+       if (!head->func->olut(head, asyh, size)) {
+               DRM_DEBUG_KMS("Invalid olut\n");
+               return -EINVAL;
+       }
        asyh->olut.handle = disp->core->chan.vram.handle;
        asyh->olut.buffer = !asyh->olut.buffer;
-       head->func->olut(head, asyh);
+
        return 0;
 }
 
@@ -510,11 +520,11 @@ nv50_head_create(struct drm_device *dev, int index)
        drm_crtc_init_with_planes(dev, crtc, &base->plane, &curs->plane,
                                  &nv50_head_func, "head-%d", head->base.index);
        drm_crtc_helper_add(crtc, &nv50_head_help);
+       /* Keep the legacy gamma size at 256 to avoid compatibility issues */
        drm_mode_crtc_set_gamma_size(crtc, 256);
-       if (disp->disp->object.oclass >= GF110_DISP)
-               drm_crtc_enable_color_mgmt(crtc, 256, true, 256);
-       else
-               drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
+       drm_crtc_enable_color_mgmt(crtc, base->func->ilut_size,
+                                  disp->disp->object.oclass >= GF110_DISP,
+                                  head->func->olut_size);
 
        if (head->func->olut_set) {
                ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut);
index d1c002f534d4edaffb48bff227a0b1b81d90d986..5c2cda2f32a8b79ba26644bc31a98aac2328b355 100644 (file)
@@ -20,8 +20,9 @@ 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 *);
+       bool (*olut)(struct nv50_head *, struct nv50_head_atom *, int);
        bool olut_identity;
+       int  olut_size;
        void (*olut_set)(struct nv50_head *, struct nv50_head_atom *);
        void (*olut_clr)(struct nv50_head *);
        void (*core_calc)(struct nv50_head *, struct nv50_head_atom *);
@@ -43,7 +44,7 @@ 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 *);
+bool head507d_olut(struct nv50_head *, struct nv50_head_atom *, 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,7 +61,7 @@ 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 *);
+bool 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 *);
 void head907d_core_set(struct nv50_head *, struct nv50_head_atom *);
index 7561be5ca707c5d2447ecb027349e60a004fc6fd..66ccf36b56a2be9179299c9da41e7e0b9d9eb946 100644 (file)
@@ -271,15 +271,19 @@ head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
        writew(readw(mem - 4), mem + 4);
 }
 
-void
-head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+bool
+head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
+       if (size != 256)
+               return false;
+
        if (asyh->base.cpp == 1)
                asyh->olut.mode = 0;
        else
                asyh->olut.mode = 1;
 
        asyh->olut.load = head507d_olut_load;
+       return true;
 }
 
 void
@@ -328,6 +332,7 @@ head507d = {
        .view = head507d_view,
        .mode = head507d_mode,
        .olut = head507d_olut,
+       .olut_size = 256,
        .olut_set = head507d_olut_set,
        .olut_clr = head507d_olut_clr,
        .core_calc = head507d_core_calc,
index af5e7bd5978bf4ff848e11cc8852de8e16240a30..11877119eea49c316071370efac7cee859b66450 100644 (file)
@@ -108,6 +108,7 @@ head827d = {
        .view = head507d_view,
        .mode = head507d_mode,
        .olut = head507d_olut,
+       .olut_size = 256,
        .olut_set = head827d_olut_set,
        .olut_clr = head827d_olut_clr,
        .core_calc = head507d_core_calc,
index c2d09dd97b1ff1a01c91a6593f7b8f4d18d12ea8..3002ec23d7a6fb91b0547c5f23f086ee8e7f5f9f 100644 (file)
@@ -230,11 +230,15 @@ head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
        writew(readw(mem - 4), mem + 4);
 }
 
-void
-head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+bool
+head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
-       asyh->olut.mode = 7;
+       if (size != 256 && size != 1024)
+               return false;
+
+       asyh->olut.mode = size == 1024 ? 4 : 7;
        asyh->olut.load = head907d_olut_load;
+       return true;
 }
 
 void
@@ -285,6 +289,7 @@ head907d = {
        .view = head907d_view,
        .mode = head907d_mode,
        .olut = head907d_olut,
+       .olut_size = 1024,
        .olut_set = head907d_olut_set,
        .olut_clr = head907d_olut_clr,
        .core_calc = head507d_core_calc,
index 303df8459ca83c522807188543a1fae77560da91..76958cedd51fd59185c3583e9dded9a35bb6452d 100644 (file)
@@ -83,6 +83,7 @@ head917d = {
        .view = head907d_view,
        .mode = head907d_mode,
        .olut = head907d_olut,
+       .olut_size = 1024,
        .olut_set = head907d_olut_set,
        .olut_clr = head907d_olut_clr,
        .core_calc = head507d_core_calc,
index ef6a99d95a9cd009cfe9ad637dc0646e9ddbadad..00011ce109a629da6a1f5f47453e1ecc3f298aac 100644 (file)
@@ -148,14 +148,18 @@ 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)
+static bool
+headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
+       if (size != 256 && size != 1024)
+               return false;
+
        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;
+       return true;
 }
 
 static void
@@ -201,6 +205,7 @@ headc37d = {
        .view = headc37d_view,
        .mode = headc37d_mode,
        .olut = headc37d_olut,
+       .olut_size = 1024,
        .olut_set = headc37d_olut_set,
        .olut_clr = headc37d_olut_clr,
        .curs_layout = head917d_curs_layout,
index 32a7f9e85fb0e529b3451d5930786024c659f8a6..938d910a1b1e4acd1a65900415367141d056d0fd 100644 (file)
@@ -151,17 +151,20 @@ headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
        writew(readw(mem - 4), mem + 4);
 }
 
-void
-headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
+bool
+headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size)
 {
+       if (size != 0 && size != 256 && size != 1024)
+               return false;
+
        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;
+       return true;
 }
 
 static void
@@ -194,6 +197,7 @@ headc57d = {
        .mode = headc57d_mode,
        .olut = headc57d_olut,
        .olut_identity = true,
+       .olut_size = 1024,
        .olut_set = headc57d_olut_set,
        .olut_clr = headc57d_olut_clr,
        .curs_layout = head917d_curs_layout,
index 994def4fd51a8da9deb2f99374ecfe3a88bc08fc..4e95ca5604ab7d1b4b2a783f798001dc8ea4c36d 100644 (file)
@@ -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;
index 5193b6257061a4614570cafb830e0b8775a35290..890315291b01eff70a13ca6a3232517f970f4e65 100644 (file)
@@ -318,7 +318,7 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
        return wndw->func->acquire(wndw, asyw, asyh);
 }
 
-static void
+static int
 nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
                           struct nv50_wndw_atom *armw,
                           struct nv50_wndw_atom *asyw,
@@ -340,7 +340,7 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
                 */
                if (!(ilut = asyh->state.gamma_lut)) {
                        asyw->visible = false;
-                       return;
+                       return 0;
                }
 
                if (wndw->func->ilut)
@@ -359,7 +359,10 @@ 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);
+               if (!wndw->func->ilut(wndw, asyw, drm_color_lut_size(ilut))) {
+                       DRM_DEBUG_KMS("Invalid ilut\n");
+                       return -EINVAL;
+               }
                asyw->xlut.handle = wndw->wndw.vram.handle;
                asyw->xlut.i.buffer = !asyw->xlut.i.buffer;
                asyw->set.xlut = true;
@@ -384,6 +387,7 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
 
        /* Can't do an immediate flip while changing the LUT. */
        asyh->state.async_flip = false;
+       return 0;
 }
 
 static int
@@ -424,8 +428,11 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
            (!armw->visible ||
             asyh->state.color_mgmt_changed ||
             asyw->state.fb->format->format !=
-            armw->state.fb->format->format))
-               nv50_wndw_atomic_check_lut(wndw, armw, asyw, asyh);
+            armw->state.fb->format->format)) {
+               ret = nv50_wndw_atomic_check_lut(wndw, armw, asyw, asyh);
+               if (ret)
+                       return ret;
+       }
 
        /* Calculate new window state. */
        if (asyw->visible) {
index c63bd3bdaf0690ea8de8acc5ba1a51bf69b384b1..caf3974759181acc8fc652f19a68ec0675dc2dc5 100644 (file)
@@ -64,12 +64,13 @@ 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 *);
+       bool (*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 *);
        void (*csc_clr)(struct nv50_wndw *);
        bool ilut_identity;
+       int  ilut_size;
        bool olut_core;
        void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
        void (*xlut_clr)(struct nv50_wndw *);
index 0f9402162bde92eab82c0b86e0b554606dddd2e3..b92dc3461bbd0577f92c83f15d0cca5847577ffa 100644 (file)
@@ -71,14 +71,18 @@ 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)
+static bool
+wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size)
 {
+       if (size != 256 && size != 1024)
+               return false;
+
        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;
+       return true;
 }
 
 void
@@ -261,6 +265,7 @@ wndwc37e = {
        .ntfy_reset = corec37d_ntfy_init,
        .ntfy_wait_begun = base507c_ntfy_wait_begun,
        .ilut = wndwc37e_ilut,
+       .ilut_size = 1024,
        .xlut_set = wndwc37e_ilut_set,
        .xlut_clr = wndwc37e_ilut_clr,
        .csc = base907c_csc,
index a311c79e52953fc243f09c0924c3dee833381b22..35c9c52fab263ec7e8c1b99114fbe2203da0c86a 100644 (file)
@@ -156,19 +156,21 @@ wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem)
        writew(readw(mem - 4), mem + 4);
 }
 
-static void
-wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+static bool
+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 = size ? size : 1024, size != 256 && size != 1024)
+               return false;
+
        if (size == 256) {
                asyw->xlut.i.mode = 1; /* DIRECT8. */
        } else {
                asyw->xlut.i.mode = 2; /* DIRECT10. */
-               size = 1024;
        }
        asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */;
        asyw->xlut.i.output_mode = 0; /* INTERPOLATE_DISABLE. */
        asyw->xlut.i.load = wndwc57e_ilut_load;
+       return true;
 }
 
 static const struct nv50_wndw_func
@@ -183,6 +185,7 @@ wndwc57e = {
        .ntfy_wait_begun = base507c_ntfy_wait_begun,
        .ilut = wndwc57e_ilut,
        .ilut_identity = true,
+       .ilut_size = 1024,
        .xlut_set = wndwc57e_ilut_set,
        .xlut_clr = wndwc57e_ilut_clr,
        .csc = base907c_csc,