drm/nouveau/kms/nv50-: allow more flexibility with lut formats
authorBen Skeggs <bskeggs@redhat.com>
Tue, 11 Dec 2018 04:50:02 +0000 (14:50 +1000)
committerBen Skeggs <bskeggs@redhat.com>
Tue, 11 Dec 2018 05:37:49 +0000 (15:37 +1000)
Will be required for Turing.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
13 files changed:
drivers/gpu/drm/nouveau/dispnv50/atom.h
drivers/gpu/drm/nouveau/dispnv50/base907c.c
drivers/gpu/drm/nouveau/dispnv50/disp.h
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/head907d.c
drivers/gpu/drm/nouveau/dispnv50/headc37d.c
drivers/gpu/drm/nouveau/dispnv50/lut.c
drivers/gpu/drm/nouveau/dispnv50/lut.h
drivers/gpu/drm/nouveau/dispnv50/wndw.c
drivers/gpu/drm/nouveau/dispnv50/wndw.h
drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c

index 908feb1..0ca5ae1 100644 (file)
@@ -57,6 +57,7 @@ struct nv50_head_atom {
                u8 size:2;
                u8 range:2;
                u8 output_mode:2;
+               void (*load)(struct drm_color_lut *, int size, void __iomem *);
        } olut;
 
        struct {
@@ -172,6 +173,8 @@ struct nv50_wndw_atom {
                        u8  size:2;
                        u8  range:2;
                        u8  output_mode:2;
+                       void (*load)(struct drm_color_lut *, int size,
+                                    void __iomem *);
                } i;
        } xlut;
 
index a562fc9..049ce6d 100644 (file)
@@ -80,6 +80,7 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
        asyw->xlut.i.mode = 7;
        asyw->xlut.i.enable = 2;
+       asyw->xlut.i.load = head907d_olut_load;
 }
 
 const struct nv50_wndw_func
index e48c5eb..2216c58 100644 (file)
@@ -45,6 +45,8 @@ struct nv50_disp_interlock {
 
 void corec37d_ntfy_init(struct nouveau_bo *, u32);
 
+void head907d_olut_load(struct drm_color_lut *, int size, void __iomem *);
+
 struct nv50_chan {
        struct nvif_object user;
        struct nvif_device *device;
index 4f57e53..ac97ebc 100644 (file)
@@ -50,9 +50,9 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        if (asyh->set.core   ) head->func->core_set(head, asyh);
        if (asyh->set.olut   ) {
                asyh->olut.offset = nv50_lut_load(&head->olut,
-                                                 asyh->olut.mode <= 1,
                                                  asyh->olut.buffer,
-                                                 asyh->state.gamma_lut);
+                                                 asyh->state.gamma_lut,
+                                                 asyh->olut.load);
                head->func->olut_set(head, asyh);
        }
        if (asyh->set.curs   ) head->func->curs_set(head, asyh);
@@ -210,7 +210,7 @@ nv50_head_atomic_check_lut(struct nv50_head *head,
                }
        }
 
-       if (!olut) {
+       if (!olut && !head->func->olut_identity) {
                asyh->olut.handle = 0;
                return 0;
        }
index 37b3248..abfc6ea 100644 (file)
@@ -21,6 +21,7 @@ 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_identity;
        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 *);
index 51bc599..7561be5 100644 (file)
@@ -254,6 +254,23 @@ head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
+static void
+head507d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       for (; size--; in++, mem += 8) {
+               writew(drm_color_lut_extract(in->  red, 11) << 3, mem + 0);
+               writew(drm_color_lut_extract(in->green, 11) << 3, mem + 2);
+               writew(drm_color_lut_extract(in-> blue, 11) << 3, mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
 void
 head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
@@ -261,6 +278,8 @@ head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
                asyh->olut.mode = 0;
        else
                asyh->olut.mode = 1;
+
+       asyh->olut.load = head507d_olut_load;
 }
 
 void
index 6339071..c2d09dd 100644 (file)
@@ -213,10 +213,28 @@ head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh)
        }
 }
 
+void
+head907d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem)
+{
+       for (; size--; in++, mem += 8) {
+               writew(drm_color_lut_extract(in->  red, 14) + 0x6000, mem + 0);
+               writew(drm_color_lut_extract(in->green, 14) + 0x6000, mem + 2);
+               writew(drm_color_lut_extract(in-> blue, 14) + 0x6000, mem + 4);
+       }
+
+       /* INTERPOLATE modes require a "next" entry to interpolate with,
+        * so we replicate the last entry to deal with this for now.
+        */
+       writew(readw(mem - 8), mem + 0);
+       writew(readw(mem - 6), mem + 2);
+       writew(readw(mem - 4), mem + 4);
+}
+
 void
 head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
 {
        asyh->olut.mode = 7;
+       asyh->olut.load = head907d_olut_load;
 }
 
 void
index 989c140..d769856 100644 (file)
@@ -155,6 +155,7 @@ headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
        asyh->olut.size = 0;
        asyh->olut.range = 0;
        asyh->olut.output_mode = 1;
+       asyh->olut.load = head907d_olut_load;
 }
 
 static void
index a6b96ae..994def4 100644 (file)
 #include <nvif/class.h>
 
 u32
-nv50_lut_load(struct nv50_lut *lut, bool legacy, int buffer,
-             struct drm_property_blob *blob)
+nv50_lut_load(struct nv50_lut *lut, int buffer, struct drm_property_blob *blob,
+             void (*load)(struct drm_color_lut *, int, void __iomem *))
 {
-       struct drm_color_lut *in = (struct drm_color_lut *)blob->data;
+       struct drm_color_lut *in = blob ? blob->data : NULL;
        void __iomem *mem = lut->mem[buffer].object.map.ptr;
-       const int size = blob->length / sizeof(*in);
-       int bits, shift, i;
-       u16 zero, r, g, b;
-       u32 addr = lut->mem[buffer].addr;
-
-       /* This can't happen.. But it shuts the compiler up. */
-       if (WARN_ON(size != 256))
-               return 0;
+       const u32 addr = lut->mem[buffer].addr;
+       int i;
 
-       if (legacy) {
-               bits = 11;
-               shift = 3;
-               zero = 0x0000;
+       if (!in) {
+               in = kvmalloc_array(1024, sizeof(*in), GFP_KERNEL);
+               if (!WARN_ON(!in)) {
+                       for (i = 0; i < 1024; i++) {
+                               in[i].red   =
+                               in[i].green =
+                               in[i].blue  = (i << 16) >> 10;
+                       }
+                       load(in, 1024, mem);
+                       kvfree(in);
+               }
        } else {
-               bits = 14;
-               shift = 0;
-               zero = 0x6000;
-       }
-
-       for (i = 0; i < size; i++) {
-               r = (drm_color_lut_extract(in[i].  red, bits) + zero) << shift;
-               g = (drm_color_lut_extract(in[i].green, bits) + zero) << shift;
-               b = (drm_color_lut_extract(in[i]. blue, bits) + zero) << shift;
-               writew(r, mem + (i * 0x08) + 0);
-               writew(g, mem + (i * 0x08) + 2);
-               writew(b, mem + (i * 0x08) + 4);
+               load(in, blob->length / sizeof(*in), mem);
        }
 
-       /* INTERPOLATE modes require a "next" entry to interpolate with,
-        * so we replicate the last entry to deal with this for now.
-        */
-       writew(r, mem + (i * 0x08) + 0);
-       writew(g, mem + (i * 0x08) + 2);
-       writew(b, mem + (i * 0x08) + 4);
        return addr;
 }
 
index 6d7b835..b3b9040 100644 (file)
@@ -2,6 +2,7 @@
 #define __NV50_KMS_LUT_H__
 #include <nvif/mem.h>
 struct drm_property_blob;
+struct drm_color_lut;
 struct nv50_disp;
 
 struct nv50_lut {
@@ -10,6 +11,6 @@ struct nv50_lut {
 
 int nv50_lut_init(struct nv50_disp *, struct nvif_mmu *, struct nv50_lut *);
 void nv50_lut_fini(struct nv50_lut *);
-u32 nv50_lut_load(struct nv50_lut *, bool legacy, int buffer,
-                 struct drm_property_blob *);
+u32 nv50_lut_load(struct nv50_lut *, int buffer, struct drm_property_blob *,
+                 void (*)(struct drm_color_lut *, int size, void __iomem *));
 #endif
index 2187922..96af28e 100644 (file)
@@ -139,10 +139,8 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
        if (asyw->set.xlut ) {
                if (asyw->ilut) {
                        asyw->xlut.i.offset =
-                               nv50_lut_load(&wndw->ilut,
-                                             asyw->xlut.i.mode <= 1,
-                                             asyw->xlut.i.buffer,
-                                             asyw->ilut);
+                               nv50_lut_load(&wndw->ilut, asyw->xlut.i.buffer,
+                                             asyw->ilut, asyw->xlut.i.load);
                }
                wndw->func->xlut_set(wndw, asyw);
        }
@@ -322,6 +320,11 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
                asyh->wndw.olut &= ~BIT(wndw->id);
        }
 
+       if (!ilut && wndw->func->ilut_identity) {
+               static struct drm_property_blob dummy = {};
+               ilut = &dummy;
+       }
+
        /* Recalculate LUT state. */
        memset(&asyw->xlut, 0x00, sizeof(asyw->xlut));
        if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) {
index b0b6428..cf15e5f 100644 (file)
@@ -65,6 +65,7 @@ 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 *);
+       bool ilut_identity;
        bool olut_core;
        void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
        void (*xlut_clr)(struct nv50_wndw *);
index 44afb0f..eb20675 100644 (file)
@@ -61,6 +61,7 @@ wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
        asyw->xlut.i.size = 0;
        asyw->xlut.i.range = 0;
        asyw->xlut.i.output_mode = 1;
+       asyw->xlut.i.load = head907d_olut_load;
 }
 
 static void