mirror of https://gitee.com/openkylin/linux.git
drm/nouveau/kms/nv50-: allow more flexibility with lut formats
Will be required for Turing. Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
5949dd8ee2
commit
cb55cd0c66
|
@ -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;
|
||||
const u32 addr = lut->mem[buffer].addr;
|
||||
int i;
|
||||
|
||||
/* This can't happen.. But it shuts the compiler up. */
|
||||
if (WARN_ON(size != 256))
|
||||
return 0;
|
||||
|
||||
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;
|
||||
load(in, blob->length / sizeof(*in), mem);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue