Commit cb55cd0c authored by Ben Skeggs's avatar Ben Skeggs

drm/nouveau/kms/nv50-: allow more flexibility with lut formats

Will be required for Turing.
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent 5949dd8e
...@@ -57,6 +57,7 @@ struct nv50_head_atom { ...@@ -57,6 +57,7 @@ struct nv50_head_atom {
u8 size:2; u8 size:2;
u8 range:2; u8 range:2;
u8 output_mode:2; u8 output_mode:2;
void (*load)(struct drm_color_lut *, int size, void __iomem *);
} olut; } olut;
struct { struct {
...@@ -172,6 +173,8 @@ struct nv50_wndw_atom { ...@@ -172,6 +173,8 @@ struct nv50_wndw_atom {
u8 size:2; u8 size:2;
u8 range:2; u8 range:2;
u8 output_mode:2; u8 output_mode:2;
void (*load)(struct drm_color_lut *, int size,
void __iomem *);
} i; } i;
} xlut; } xlut;
......
...@@ -80,6 +80,7 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) ...@@ -80,6 +80,7 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{ {
asyw->xlut.i.mode = 7; asyw->xlut.i.mode = 7;
asyw->xlut.i.enable = 2; asyw->xlut.i.enable = 2;
asyw->xlut.i.load = head907d_olut_load;
} }
const struct nv50_wndw_func const struct nv50_wndw_func
......
...@@ -45,6 +45,8 @@ struct nv50_disp_interlock { ...@@ -45,6 +45,8 @@ struct nv50_disp_interlock {
void corec37d_ntfy_init(struct nouveau_bo *, u32); void corec37d_ntfy_init(struct nouveau_bo *, u32);
void head907d_olut_load(struct drm_color_lut *, int size, void __iomem *);
struct nv50_chan { struct nv50_chan {
struct nvif_object user; struct nvif_object user;
struct nvif_device *device; struct nvif_device *device;
......
...@@ -50,9 +50,9 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) ...@@ -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.core ) head->func->core_set(head, asyh);
if (asyh->set.olut ) { if (asyh->set.olut ) {
asyh->olut.offset = nv50_lut_load(&head->olut, asyh->olut.offset = nv50_lut_load(&head->olut,
asyh->olut.mode <= 1,
asyh->olut.buffer, asyh->olut.buffer,
asyh->state.gamma_lut); asyh->state.gamma_lut,
asyh->olut.load);
head->func->olut_set(head, asyh); head->func->olut_set(head, asyh);
} }
if (asyh->set.curs ) head->func->curs_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, ...@@ -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; asyh->olut.handle = 0;
return 0; return 0;
} }
......
...@@ -21,6 +21,7 @@ struct nv50_head_func { ...@@ -21,6 +21,7 @@ struct nv50_head_func {
void (*view)(struct nv50_head *, struct nv50_head_atom *); void (*view)(struct nv50_head *, struct nv50_head_atom *);
void (*mode)(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 *);
bool olut_identity;
void (*olut_set)(struct nv50_head *, struct nv50_head_atom *); void (*olut_set)(struct nv50_head *, struct nv50_head_atom *);
void (*olut_clr)(struct nv50_head *); void (*olut_clr)(struct nv50_head *);
void (*core_calc)(struct nv50_head *, struct nv50_head_atom *); void (*core_calc)(struct nv50_head *, struct nv50_head_atom *);
......
...@@ -254,6 +254,23 @@ head507d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) ...@@ -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 void
head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh) 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) ...@@ -261,6 +278,8 @@ head507d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
asyh->olut.mode = 0; asyh->olut.mode = 0;
else else
asyh->olut.mode = 1; asyh->olut.mode = 1;
asyh->olut.load = head507d_olut_load;
} }
void void
......
...@@ -213,10 +213,28 @@ head907d_olut_set(struct nv50_head *head, struct nv50_head_atom *asyh) ...@@ -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 void
head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh) head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
{ {
asyh->olut.mode = 7; asyh->olut.mode = 7;
asyh->olut.load = head907d_olut_load;
} }
void void
......
...@@ -155,6 +155,7 @@ headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh) ...@@ -155,6 +155,7 @@ headc37d_olut(struct nv50_head *head, struct nv50_head_atom *asyh)
asyh->olut.size = 0; asyh->olut.size = 0;
asyh->olut.range = 0; asyh->olut.range = 0;
asyh->olut.output_mode = 1; asyh->olut.output_mode = 1;
asyh->olut.load = head907d_olut_load;
} }
static void static void
......
...@@ -29,45 +29,29 @@ ...@@ -29,45 +29,29 @@
#include <nvif/class.h> #include <nvif/class.h>
u32 u32
nv50_lut_load(struct nv50_lut *lut, bool legacy, int buffer, nv50_lut_load(struct nv50_lut *lut, int buffer, struct drm_property_blob *blob,
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; void __iomem *mem = lut->mem[buffer].object.map.ptr;
const int size = blob->length / sizeof(*in); const u32 addr = lut->mem[buffer].addr;
int bits, shift, i; int 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;
if (legacy) { if (!in) {
bits = 11; in = kvmalloc_array(1024, sizeof(*in), GFP_KERNEL);
shift = 3; if (!WARN_ON(!in)) {
zero = 0x0000; 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 { } else {
bits = 14; load(in, blob->length / sizeof(*in), mem);
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);
} }
/* 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; return addr;
} }
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define __NV50_KMS_LUT_H__ #define __NV50_KMS_LUT_H__
#include <nvif/mem.h> #include <nvif/mem.h>
struct drm_property_blob; struct drm_property_blob;
struct drm_color_lut;
struct nv50_disp; struct nv50_disp;
struct nv50_lut { struct nv50_lut {
...@@ -10,6 +11,6 @@ struct nv50_lut { ...@@ -10,6 +11,6 @@ struct nv50_lut {
int nv50_lut_init(struct nv50_disp *, struct nvif_mmu *, struct nv50_lut *); int nv50_lut_init(struct nv50_disp *, struct nvif_mmu *, struct nv50_lut *);
void nv50_lut_fini(struct nv50_lut *); void nv50_lut_fini(struct nv50_lut *);
u32 nv50_lut_load(struct nv50_lut *, bool legacy, int buffer, u32 nv50_lut_load(struct nv50_lut *, int buffer, struct drm_property_blob *,
struct drm_property_blob *); void (*)(struct drm_color_lut *, int size, void __iomem *));
#endif #endif
...@@ -139,10 +139,8 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock, ...@@ -139,10 +139,8 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
if (asyw->set.xlut ) { if (asyw->set.xlut ) {
if (asyw->ilut) { if (asyw->ilut) {
asyw->xlut.i.offset = asyw->xlut.i.offset =
nv50_lut_load(&wndw->ilut, nv50_lut_load(&wndw->ilut, asyw->xlut.i.buffer,
asyw->xlut.i.mode <= 1, asyw->ilut, asyw->xlut.i.load);
asyw->xlut.i.buffer,
asyw->ilut);
} }
wndw->func->xlut_set(wndw, asyw); wndw->func->xlut_set(wndw, asyw);
} }
...@@ -322,6 +320,11 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw, ...@@ -322,6 +320,11 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
asyh->wndw.olut &= ~BIT(wndw->id); asyh->wndw.olut &= ~BIT(wndw->id);
} }
if (!ilut && wndw->func->ilut_identity) {
static struct drm_property_blob dummy = {};
ilut = &dummy;
}
/* Recalculate LUT state. */ /* Recalculate LUT state. */
memset(&asyw->xlut, 0x00, sizeof(asyw->xlut)); memset(&asyw->xlut, 0x00, sizeof(asyw->xlut));
if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) { if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) {
......
...@@ -65,6 +65,7 @@ struct nv50_wndw_func { ...@@ -65,6 +65,7 @@ struct nv50_wndw_func {
int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset, int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset,
struct nvif_device *); struct nvif_device *);
void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *); void (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *);
bool ilut_identity;
bool olut_core; bool olut_core;
void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *); void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*xlut_clr)(struct nv50_wndw *); void (*xlut_clr)(struct nv50_wndw *);
......
...@@ -61,6 +61,7 @@ wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) ...@@ -61,6 +61,7 @@ wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
asyw->xlut.i.size = 0; asyw->xlut.i.size = 0;
asyw->xlut.i.range = 0; asyw->xlut.i.range = 0;
asyw->xlut.i.output_mode = 1; asyw->xlut.i.output_mode = 1;
asyw->xlut.i.load = head907d_olut_load;
} }
static void static void
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment