From cb55cd0c66a16fd965a44e2634755b060dc64bd7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Tue, 11 Dec 2018 14:50:02 +1000 Subject: [PATCH] drm/nouveau/kms/nv50-: allow more flexibility with lut formats Will be required for Turing. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv50/atom.h | 3 ++ drivers/gpu/drm/nouveau/dispnv50/base907c.c | 1 + drivers/gpu/drm/nouveau/dispnv50/disp.h | 2 + drivers/gpu/drm/nouveau/dispnv50/head.c | 6 +-- drivers/gpu/drm/nouveau/dispnv50/head.h | 1 + drivers/gpu/drm/nouveau/dispnv50/head507d.c | 19 ++++++++ drivers/gpu/drm/nouveau/dispnv50/head907d.c | 18 ++++++++ drivers/gpu/drm/nouveau/dispnv50/headc37d.c | 1 + drivers/gpu/drm/nouveau/dispnv50/lut.c | 50 +++++++-------------- drivers/gpu/drm/nouveau/dispnv50/lut.h | 5 ++- drivers/gpu/drm/nouveau/dispnv50/wndw.c | 11 +++-- drivers/gpu/drm/nouveau/dispnv50/wndw.h | 1 + drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c | 1 + 13 files changed, 77 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index 908feb1fc60f..0ca5ae103ee9 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -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; diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c b/drivers/gpu/drm/nouveau/dispnv50/base907c.c index a562fc94ce59..049ce6da321c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c +++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.h b/drivers/gpu/drm/nouveau/dispnv50/disp.h index e48c5eb35b49..2216c58620c2 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h @@ -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; diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 4f57e5379796..ac97ebce5b35 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -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; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index 37b3248c6dae..abfc6eac69ea 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -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 *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head507d.c b/drivers/gpu/drm/nouveau/dispnv50/head507d.c index 51bc5996fd37..7561be5ca707 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head507d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head507d.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/dispnv50/head907d.c b/drivers/gpu/drm/nouveau/dispnv50/head907d.c index 633907163eb1..c2d09dd97b1f 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head907d.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c index 989c14083066..d7698563321e 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c @@ -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 diff --git a/drivers/gpu/drm/nouveau/dispnv50/lut.c b/drivers/gpu/drm/nouveau/dispnv50/lut.c index a6b96ae2a22f..994def4fd51a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/lut.c +++ b/drivers/gpu/drm/nouveau/dispnv50/lut.c @@ -29,45 +29,29 @@ #include 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; } diff --git a/drivers/gpu/drm/nouveau/dispnv50/lut.h b/drivers/gpu/drm/nouveau/dispnv50/lut.h index 6d7b8352e4cb..b3b9040cfe9a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/lut.h +++ b/drivers/gpu/drm/nouveau/dispnv50/lut.h @@ -2,6 +2,7 @@ #define __NV50_KMS_LUT_H__ #include 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 diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 2187922e8dc2..96af28e8842a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -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)) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h index b0b6428034b0..cf15e5fdeadd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h @@ -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 *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c index 44afb0f069a5..eb2067576964 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c @@ -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 -- 2.30.2