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 {
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;
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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 *);
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -29,45 +29,29 @@
#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;
} else {
bits = 14;
shift = 0;
zero = 0x6000;
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;
}
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, 1024, mem);
kvfree(in);
}
} else {
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;
}
......
......@@ -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
......@@ -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)) {
......
......@@ -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 *);
......
......@@ -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
......
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