aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/dispnv50
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/atom.h14
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/base507c.c26
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/base827c.c11
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/base907c.c65
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/base917c.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/corec37d.c2
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c46
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/head.c18
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/ovly507e.c3
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/ovly827e.c3
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/ovly907e.c13
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/ovly917e.c5
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.c111
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndw.h10
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c61
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c72
16 files changed, 383 insertions, 79 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h
index b5fae5ab3fa8..43df86c38f58 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -185,6 +185,11 @@ struct nv50_wndw_atom {
} xlut;
struct {
+ u32 matrix[12];
+ bool valid;
+ } csc;
+
+ struct {
u8 mode:2;
u8 interval:4;
@@ -216,14 +221,23 @@ struct nv50_wndw_atom {
u16 y;
} point;
+ struct {
+ u8 depth;
+ u8 k1;
+ u8 src_color:4;
+ u8 dst_color:4;
+ } blend;
+
union nv50_wndw_atom_mask {
struct {
bool ntfy:1;
bool sema:1;
bool xlut:1;
+ bool csc:1;
bool image:1;
bool scale:1;
bool point:1;
+ bool blend:1;
};
u8 mask;
} set, clr;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/base507c.c b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
index d5e295ca2caa..00a85f1e1a4a 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base507c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
@@ -25,7 +25,9 @@
#include <nvif/event.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
+
#include "nouveau_bo.h"
void
@@ -56,12 +58,21 @@ static void
base507c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
- if ((push = evo_wait(&wndw->wndw, 10))) {
+ if ((push = evo_wait(&wndw->wndw, 13))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, asyw->image.mode << 8 |
asyw->image.interval << 4);
evo_mthd(push, 0x00c0, 1);
evo_data(push, asyw->image.handle[0]);
+ if (asyw->image.format == 0xca) {
+ evo_mthd(push, 0x0110, 2);
+ evo_data(push, 1);
+ evo_data(push, 0x6400);
+ } else {
+ evo_mthd(push, 0x0110, 2);
+ evo_data(push, 0);
+ evo_data(push, 0);
+ }
evo_mthd(push, 0x0800, 5);
evo_data(push, asyw->image.offset[0] >> 8);
evo_data(push, 0x00000000);
@@ -179,9 +190,6 @@ base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
const struct drm_framebuffer *fb = asyw->state.fb;
int ret;
- if (!fb->format->depth)
- return -EINVAL;
-
ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
DRM_PLANE_HELPER_NO_SCALING,
DRM_PLANE_HELPER_NO_SCALING,
@@ -200,6 +208,14 @@ base507c_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
asyh->base.y = asyw->state.src.y1 >> 16;
asyh->base.w = asyw->state.fb->width;
asyh->base.h = asyw->state.fb->height;
+
+ /* Some newer formats, esp FP16 ones, don't have a
+ * "depth". There's nothing that really makes sense there
+ * either, so just set it to the implicit bit count.
+ */
+ if (!asyh->base.depth)
+ asyh->base.depth = asyh->base.cpp * 8;
+
return 0;
}
@@ -215,6 +231,8 @@ base507c_format[] = {
DRM_FORMAT_ABGR2101010,
DRM_FORMAT_XBGR8888,
DRM_FORMAT_ABGR8888,
+ DRM_FORMAT_XBGR16161616F,
+ DRM_FORMAT_ABGR16161616F,
0
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/base827c.c b/drivers/gpu/drm/nouveau/dispnv50/base827c.c
index 73646819a0d6..f4c05949dd62 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base827c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base827c.c
@@ -25,12 +25,21 @@ static void
base827c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
- if ((push = evo_wait(&wndw->wndw, 10))) {
+ if ((push = evo_wait(&wndw->wndw, 13))) {
evo_mthd(push, 0x0084, 1);
evo_data(push, asyw->image.mode << 8 |
asyw->image.interval << 4);
evo_mthd(push, 0x00c0, 1);
evo_data(push, asyw->image.handle[0]);
+ if (asyw->image.format == 0xca) {
+ evo_mthd(push, 0x0110, 2);
+ evo_data(push, 1);
+ evo_data(push, 0x6400);
+ } else {
+ evo_mthd(push, 0x0110, 2);
+ evo_data(push, 0);
+ evo_data(push, 0);
+ }
evo_mthd(push, 0x0800, 5);
evo_data(push, asyw->image.offset[0] >> 8);
evo_data(push, 0x00000000);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
index 049ce6da321c..5f2de77e0f32 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
@@ -83,6 +83,68 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
asyw->xlut.i.load = head907d_olut_load;
}
+static inline u32
+csc_drm_to_base(u64 in)
+{
+ /* base takes a 19-bit 2's complement value in S3.16 format */
+ bool sign = in & BIT_ULL(63);
+ u32 integer = (in >> 32) & 0x7fffffff;
+ u32 fraction = in & 0xffffffff;
+
+ if (integer >= 4) {
+ return (1 << 18) - (sign ? 0 : 1);
+ } else {
+ u32 ret = (integer << 16) | (fraction >> 16);
+ if (sign)
+ ret = -ret;
+ return ret & GENMASK(18, 0);
+ }
+}
+
+void
+base907c_csc(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
+ const struct drm_color_ctm *ctm)
+{
+ int i, j;
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 4; i++) {
+ u32 *val = &asyw->csc.matrix[j * 4 + i];
+ /* DRM does not support constant offset, while
+ * HW CSC does. Skip it. */
+ if (i == 3) {
+ *val = 0;
+ } else {
+ *val = csc_drm_to_base(ctm->matrix[j * 3 + i]);
+ }
+ }
+ }
+}
+
+static void
+base907c_csc_clr(struct nv50_wndw *wndw)
+{
+ u32 *push;
+ if ((push = evo_wait(&wndw->wndw, 2))) {
+ evo_mthd(push, 0x0140, 1);
+ evo_data(push, 0x00000000);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
+static void
+base907c_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+ u32 *push, i;
+ if ((push = evo_wait(&wndw->wndw, 13))) {
+ evo_mthd(push, 0x0140, 12);
+ evo_data(push, asyw->csc.matrix[0] | 0x80000000);
+ for (i = 1; i < 12; i++)
+ evo_data(push, asyw->csc.matrix[i]);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
const struct nv50_wndw_func
base907c = {
.acquire = base507c_acquire,
@@ -94,6 +156,9 @@ base907c = {
.ntfy_clr = base507c_ntfy_clr,
.ntfy_wait_begun = base507c_ntfy_wait_begun,
.ilut = base907c_ilut,
+ .csc = base907c_csc,
+ .csc_set = base907c_csc_set,
+ .csc_clr = base907c_csc_clr,
.olut_core = true,
.xlut_set = base907c_xlut_set,
.xlut_clr = base907c_xlut_clr,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/base917c.c b/drivers/gpu/drm/nouveau/dispnv50/base917c.c
index 54d705bb81a5..a1baed4fe0e9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base917c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base917c.c
@@ -36,6 +36,8 @@ base917c_format[] = {
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_XBGR16161616F,
+ DRM_FORMAT_ABGR16161616F,
0
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c
index 7860774b65bc..40d9b654ab8c 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/corec37d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/corec37d.c
@@ -82,7 +82,7 @@ corec37d_init(struct nv50_core *core)
for (i = 0; i < windows; i++) {
evo_mthd(push, 0x1000 + (i * 0x080), 3);
evo_data(push, i >> 1);
- evo_data(push, 0x00000017);
+ evo_data(push, 0x0000001f);
evo_data(push, 0x00000000);
evo_mthd(push, 0x1010 + (i * 0x080), 1);
evo_data(push, 0x00127fff);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 5c36c75232e6..b46be8a091e9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -30,14 +30,14 @@
#include <linux/dma-mapping.h>
#include <linux/hdmi.h>
-#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_plane_helper.h>
#include <drm/drm_probe_helper.h>
#include <drm/drm_scdc_helper.h>
-#include <drm/drm_edid.h>
+#include <drm/drm_vblank.h>
#include <nvif/class.h>
#include <nvif/cl0002.h>
@@ -1603,7 +1603,8 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
nv_encoder->aux = aux;
}
- if ((data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len)) &&
+ if (nv_connector->type != DCB_CONNECTOR_eDP &&
+ (data = nvbios_dp_table(bios, &ver, &hdr, &cnt, &len)) &&
ver >= 0x40 && (nvbios_rd08(bios, data + 0x08) & 0x04)) {
ret = nv50_mstm_new(nv_encoder, &nv_connector->aux, 16,
nv_connector->base.base.id,
@@ -1830,8 +1831,11 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
NV_ATOMIC(drm, "%s: clr %04x (set %04x)\n", crtc->name,
asyh->clr.mask, asyh->set.mask);
- if (old_crtc_state->active && !new_crtc_state->active)
+
+ if (old_crtc_state->active && !new_crtc_state->active) {
+ pm_runtime_put_noidle(dev->dev);
drm_crtc_vblank_off(crtc);
+ }
if (asyh->clr.mask) {
nv50_head_flush_clr(head, asyh, atom->flush_disable);
@@ -1917,8 +1921,10 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
}
if (new_crtc_state->active) {
- if (!old_crtc_state->active)
+ if (!old_crtc_state->active) {
drm_crtc_vblank_on(crtc);
+ pm_runtime_get_noresume(dev->dev);
+ }
if (new_crtc_state->event)
drm_crtc_vblank_get(crtc);
}
@@ -1983,6 +1989,10 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
drm_atomic_helper_cleanup_planes(dev, state);
drm_atomic_helper_commit_cleanup_done(state);
drm_atomic_state_put(state);
+
+ /* Drop the RPM ref we got from nv50_disp_atomic_commit() */
+ pm_runtime_mark_last_busy(dev->dev);
+ pm_runtime_put_autosuspend(dev->dev);
}
static void
@@ -1997,11 +2007,8 @@ static int
nv50_disp_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state, bool nonblock)
{
- struct nouveau_drm *drm = nouveau_drm(dev);
struct drm_plane_state *new_plane_state;
struct drm_plane *plane;
- struct drm_crtc *crtc;
- bool active = false;
int ret, i;
ret = pm_runtime_get_sync(dev->dev);
@@ -2038,27 +2045,17 @@ nv50_disp_atomic_commit(struct drm_device *dev,
drm_atomic_state_get(state);
+ /*
+ * Grab another RPM ref for the commit tail, which will release the
+ * ref when it's finished
+ */
+ pm_runtime_get_noresume(dev->dev);
+
if (nonblock)
queue_work(system_unbound_wq, &state->commit_work);
else
nv50_disp_atomic_commit_tail(state);
- drm_for_each_crtc(crtc, dev) {
- if (crtc->state->active) {
- if (!drm->have_disp_power_ref) {
- drm->have_disp_power_ref = true;
- return 0;
- }
- active = true;
- break;
- }
- }
-
- if (!active && drm->have_disp_power_ref) {
- pm_runtime_put_autosuspend(dev->dev);
- drm->have_disp_power_ref = false;
- }
-
err_cleanup:
if (ret)
drm_atomic_helper_cleanup_planes(dev, state);
@@ -2320,6 +2317,7 @@ nv50_display_create(struct drm_device *dev)
disp->disp = &nouveau_display(dev)->disp;
dev->mode_config.funcs = &nv50_disp_func;
dev->mode_config.quirk_addfb_prefer_xbgr_30bpp = true;
+ dev->mode_config.normalize_zpos = true;
/* small shared memory area we use for notifiers and semaphores */
ret = nouveau_bo_new(&drm->client, 4096, 0x1000, TTM_PL_FLAG_VRAM,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index 929d93b1677e..71c23bf1fe25 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -480,7 +480,7 @@ nv50_head_create(struct drm_device *dev, int index)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nv50_disp *disp = nv50_disp(dev);
struct nv50_head *head;
- struct nv50_wndw *curs, *wndw;
+ struct nv50_wndw *base, *ovly, *curs;
struct drm_crtc *crtc;
int ret;
@@ -492,13 +492,13 @@ nv50_head_create(struct drm_device *dev, int index)
head->base.index = index;
if (disp->disp->object.oclass < GV100_DISP) {
- ret = nv50_ovly_new(drm, head->base.index, &wndw);
- ret = nv50_base_new(drm, head->base.index, &wndw);
+ ret = nv50_base_new(drm, head->base.index, &base);
+ ret = nv50_ovly_new(drm, head->base.index, &ovly);
} else {
- ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY,
- head->base.index * 2 + 1, &wndw);
ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_PRIMARY,
- head->base.index * 2 + 0, &wndw);
+ head->base.index * 2 + 0, &base);
+ ret = nv50_wndw_new(drm, DRM_PLANE_TYPE_OVERLAY,
+ head->base.index * 2 + 1, &ovly);
}
if (ret == 0)
ret = nv50_curs_new(drm, head->base.index, &curs);
@@ -508,10 +508,14 @@ nv50_head_create(struct drm_device *dev, int index)
}
crtc = &head->base.base;
- drm_crtc_init_with_planes(dev, crtc, &wndw->plane, &curs->plane,
+ drm_crtc_init_with_planes(dev, crtc, &base->plane, &curs->plane,
&nv50_head_func, "head-%d", head->base.index);
drm_crtc_helper_add(crtc, &nv50_head_help);
drm_mode_crtc_set_gamma_size(crtc, 256);
+ if (disp->disp->object.oclass >= GF110_DISP)
+ drm_crtc_enable_color_mgmt(crtc, 256, true, 256);
+ else
+ drm_crtc_enable_color_mgmt(crtc, 0, false, 256);
if (head->func->olut_set) {
ret = nv50_lut_init(disp, &drm->client.mmu, &head->olut);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
index cc417664f823..8ccd96113bad 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
@@ -23,6 +23,7 @@
#include "atom.h"
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
#include <drm/drm_plane_helper.h>
#include <nvif/cl507e.h>
@@ -160,9 +161,7 @@ ovly507e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
- DRM_FORMAT_ARGB1555,
0
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
index aaa9fe5a4fc8..2e68fc736fe1 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
@@ -90,11 +90,8 @@ ovly827e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
- DRM_FORMAT_ARGB1555,
DRM_FORMAT_XBGR2101010,
- DRM_FORMAT_ABGR2101010,
0
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
index a3ce53046015..9efe5e9d5ce4 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
@@ -61,10 +61,21 @@ ovly907e = {
.update = ovly507e_update,
};
+static const u32
+ovly907e_format[] = {
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XRGB1555,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_XBGR16161616F,
+ 0
+};
+
int
ovly907e_new(struct nouveau_drm *drm, int head, s32 oclass,
struct nv50_wndw **pwndw)
{
- return ovly507e_new_(&ovly907e, ovly827e_format, drm, head, oclass,
+ return ovly507e_new_(&ovly907e, ovly907e_format, drm, head, oclass,
0x00000004 << (head * 4), pwndw);
}
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly917e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly917e.c
index 505fa7e78523..e24d6fd23450 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly917e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly917e.c
@@ -26,13 +26,10 @@ ovly917e_format[] = {
DRM_FORMAT_YUYV,
DRM_FORMAT_UYVY,
DRM_FORMAT_XRGB8888,
- DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB1555,
- DRM_FORMAT_ARGB1555,
DRM_FORMAT_XBGR2101010,
- DRM_FORMAT_ABGR2101010,
DRM_FORMAT_XRGB2101010,
- DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_XBGR16161616F,
0
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index 283ff690350e..2db029371c91 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -26,6 +26,8 @@
#include <nvif/cl0002.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_fourcc.h>
+
#include "nouveau_bo.h"
static void
@@ -118,6 +120,7 @@ nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 *interlock, bool flush,
if (clr.sema ) wndw->func-> sema_clr(wndw);
if (clr.ntfy ) wndw->func-> ntfy_clr(wndw);
if (clr.xlut ) wndw->func-> xlut_clr(wndw);
+ if (clr.csc ) wndw->func-> csc_clr(wndw);
if (clr.image) wndw->func->image_clr(wndw);
interlock[wndw->interlock.type] |= wndw->interlock.data;
@@ -145,7 +148,9 @@ nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
wndw->func->xlut_set(wndw, asyw);
}
+ if (asyw->set.csc ) wndw->func->csc_set (wndw, asyw);
if (asyw->set.scale) wndw->func->scale_set(wndw, asyw);
+ if (asyw->set.blend) wndw->func->blend_set(wndw, asyw);
if (asyw->set.point) {
if (asyw->set.point = false, asyw->set.mask)
interlock[wndw->interlock.type] |= wndw->interlock.data;
@@ -202,18 +207,20 @@ static int
nv50_wndw_atomic_check_acquire_rgb(struct nv50_wndw_atom *asyw)
{
switch (asyw->state.fb->format->format) {
- case DRM_FORMAT_C8 : asyw->image.format = 0x1e; break;
- case DRM_FORMAT_XRGB8888 :
- case DRM_FORMAT_ARGB8888 : asyw->image.format = 0xcf; break;
- case DRM_FORMAT_RGB565 : asyw->image.format = 0xe8; break;
- case DRM_FORMAT_XRGB1555 :
- case DRM_FORMAT_ARGB1555 : asyw->image.format = 0xe9; break;
- case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010: asyw->image.format = 0xd1; break;
- case DRM_FORMAT_XBGR8888 :
- case DRM_FORMAT_ABGR8888 : asyw->image.format = 0xd5; break;
- case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010: asyw->image.format = 0xdf; break;
+ case DRM_FORMAT_C8 : asyw->image.format = 0x1e; break;
+ case DRM_FORMAT_XRGB8888 :
+ case DRM_FORMAT_ARGB8888 : asyw->image.format = 0xcf; break;
+ case DRM_FORMAT_RGB565 : asyw->image.format = 0xe8; break;
+ case DRM_FORMAT_XRGB1555 :
+ case DRM_FORMAT_ARGB1555 : asyw->image.format = 0xe9; break;
+ case DRM_FORMAT_XBGR2101010 :
+ case DRM_FORMAT_ABGR2101010 : asyw->image.format = 0xd1; break;
+ case DRM_FORMAT_XBGR8888 :
+ case DRM_FORMAT_ABGR8888 : asyw->image.format = 0xd5; break;
+ case DRM_FORMAT_XRGB2101010 :
+ case DRM_FORMAT_ARGB2101010 : asyw->image.format = 0xdf; break;
+ case DRM_FORMAT_XBGR16161616F:
+ case DRM_FORMAT_ABGR16161616F: asyw->image.format = 0xca; break;
default:
return -EINVAL;
}
@@ -279,6 +286,28 @@ nv50_wndw_atomic_check_acquire(struct nv50_wndw *wndw, bool modeset,
asyw->set.scale = true;
}
+ if (wndw->func->blend_set) {
+ asyw->blend.depth = 255 - asyw->state.normalized_zpos;
+ asyw->blend.k1 = asyw->state.alpha >> 8;
+ switch (asyw->state.pixel_blend_mode) {
+ case DRM_MODE_BLEND_PREMULTI:
+ asyw->blend.src_color = 2; /* K1 */
+ asyw->blend.dst_color = 7; /* NEG_K1_TIMES_SRC */
+ break;
+ case DRM_MODE_BLEND_COVERAGE:
+ asyw->blend.src_color = 5; /* K1_TIMES_SRC */
+ asyw->blend.dst_color = 7; /* NEG_K1_TIMES_SRC */
+ break;
+ case DRM_MODE_BLEND_PIXEL_NONE:
+ default:
+ asyw->blend.src_color = 2; /* K1 */
+ asyw->blend.dst_color = 4; /* NEG_K1 */
+ break;
+ }
+ if (memcmp(&armw->blend, &asyw->blend, sizeof(asyw->blend)))
+ asyw->set.blend = true;
+ }
+
if (wndw->immd) {
asyw->point.x = asyw->state.crtc_x;
asyw->point.y = asyw->state.crtc_y;
@@ -320,7 +349,9 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
asyh->wndw.olut &= ~BIT(wndw->id);
}
- if (!ilut && wndw->func->ilut_identity) {
+ if (!ilut && wndw->func->ilut_identity &&
+ asyw->state.fb->format->format != DRM_FORMAT_XBGR16161616F &&
+ asyw->state.fb->format->format != DRM_FORMAT_ABGR16161616F) {
static struct drm_property_blob dummy = {};
ilut = &dummy;
}
@@ -332,6 +363,8 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
asyw->xlut.handle = wndw->wndw.vram.handle;
asyw->xlut.i.buffer = !asyw->xlut.i.buffer;
asyw->set.xlut = true;
+ } else {
+ asyw->clr.xlut = armw->xlut.handle != 0;
}
/* Handle setting base SET_OUTPUT_LUT_LO_ENABLE_USE_CORE_LUT. */
@@ -339,6 +372,16 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw,
(!armw->visible || (armw->xlut.handle && !asyw->xlut.handle)))
asyw->set.xlut = true;
+ if (wndw->func->csc && asyh->state.ctm) {
+ const struct drm_color_ctm *ctm = asyh->state.ctm->data;
+ wndw->func->csc(wndw, asyw, ctm);
+ asyw->csc.valid = true;
+ asyw->set.csc = true;
+ } else {
+ asyw->csc.valid = false;
+ asyw->clr.csc = armw->csc.valid;
+ }
+
/* Can't do an immediate flip while changing the LUT. */
asyh->state.pageflip_flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
}
@@ -408,6 +451,7 @@ nv50_wndw_atomic_check(struct drm_plane *plane, struct drm_plane_state *state)
asyw->clr.ntfy = armw->ntfy.handle != 0;
asyw->clr.sema = armw->sema.handle != 0;
asyw->clr.xlut = armw->xlut.handle != 0;
+ asyw->clr.csc = armw->csc.valid;
if (wndw->func->image_clr)
asyw->clr.image = armw->image.handle[0] != 0;
}
@@ -457,7 +501,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state)
asyw->image.handle[0] = ctxdma->object.handle;
}
- asyw->state.fence = reservation_object_get_excl_rcu(fb->nvbo->bo.resv);
+ asyw->state.fence = dma_resv_get_excl_rcu(fb->nvbo->bo.base.resv);
asyw->image.offset[0] = fb->nvbo->bo.offset;
if (wndw->func->prepare) {
@@ -499,6 +543,7 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
asyw->ntfy = armw->ntfy;
asyw->ilut = NULL;
asyw->xlut = armw->xlut;
+ asyw->csc = armw->csc;
asyw->image = armw->image;
asyw->point = armw->point;
asyw->clr.mask = 0;
@@ -506,6 +551,13 @@ nv50_wndw_atomic_duplicate_state(struct drm_plane *plane)
return &asyw->state;
}
+static int
+nv50_wndw_zpos_default(struct drm_plane *plane)
+{
+ return (plane->type == DRM_PLANE_TYPE_PRIMARY) ? 0 :
+ (plane->type == DRM_PLANE_TYPE_OVERLAY) ? 1 : 255;
+}
+
static void
nv50_wndw_reset(struct drm_plane *plane)
{
@@ -516,9 +568,10 @@ nv50_wndw_reset(struct drm_plane *plane)
if (plane->state)
plane->funcs->atomic_destroy_state(plane, plane->state);
- plane->state = &asyw->state;
- plane->state->plane = plane;
- plane->state->rotation = DRM_MODE_ROTATE_0;
+
+ __drm_atomic_helper_plane_reset(plane, &asyw->state);
+ plane->state->zpos = nv50_wndw_zpos_default(plane);
+ plane->state->normalized_zpos = nv50_wndw_zpos_default(plane);
}
static void
@@ -613,6 +666,30 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
}
wndw->notify.func = nv50_wndw_notify;
+
+ if (wndw->func->blend_set) {
+ ret = drm_plane_create_zpos_property(&wndw->plane,
+ nv50_wndw_zpos_default(&wndw->plane), 0, 254);
+ if (ret)
+ return ret;
+
+ ret = drm_plane_create_alpha_property(&wndw->plane);
+ if (ret)
+ return ret;
+
+ ret = drm_plane_create_blend_mode_property(&wndw->plane,
+ BIT(DRM_MODE_BLEND_PIXEL_NONE) |
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE));
+ if (ret)
+ return ret;
+ } else {
+ ret = drm_plane_create_zpos_immutable_property(&wndw->plane,
+ nv50_wndw_zpos_default(&wndw->plane));
+ if (ret)
+ return ret;
+ }
+
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
index 03f3d8dc235a..c63bd3bdaf06 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -65,6 +65,10 @@ 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 *);
+ void (*csc)(struct nv50_wndw *, struct nv50_wndw_atom *,
+ const struct drm_color_ctm *);
+ void (*csc_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
+ void (*csc_clr)(struct nv50_wndw *);
bool ilut_identity;
bool olut_core;
void (*xlut_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
@@ -72,6 +76,7 @@ struct nv50_wndw_func {
void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*image_clr)(struct nv50_wndw *);
void (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
+ void (*blend_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
void (*update)(struct nv50_wndw *, u32 *interlock);
};
@@ -81,6 +86,9 @@ extern const struct drm_plane_funcs nv50_wndw;
void base507c_ntfy_reset(struct nouveau_bo *, u32);
int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
+void base907c_csc(struct nv50_wndw *, struct nv50_wndw_atom *,
+ const struct drm_color_ctm *);
+
struct nv50_wimm_func {
void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
@@ -102,8 +110,8 @@ void wndwc37e_sema_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void wndwc37e_sema_clr(struct nv50_wndw *);
void wndwc37e_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void wndwc37e_ntfy_clr(struct nv50_wndw *);
-void wndwc37e_image_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void wndwc37e_image_clr(struct nv50_wndw *);
+void wndwc37e_blend_set(struct nv50_wndw *, struct nv50_wndw_atom *);
void wndwc37e_update(struct nv50_wndw *, u32 *);
int wndwc57e_new(struct nouveau_drm *, enum drm_plane_type, int, s32,
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
index e52a85c83f7a..0f9402162bde 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
@@ -29,6 +29,23 @@
#include <nvif/clc37e.h>
static void
+wndwc37e_csc_clr(struct nv50_wndw *wndw)
+{
+}
+
+static void
+wndwc37e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+ u32 *push, i;
+ if ((push = evo_wait(&wndw->wndw, 13))) {
+ evo_mthd(push, 0x02bc, 12);
+ for (i = 0; i < 12; i++)
+ evo_data(push, asyw->csc.matrix[i]);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
+static void
wndwc37e_ilut_clr(struct nv50_wndw *wndw)
{
u32 *push;
@@ -65,6 +82,26 @@ wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
}
void
+wndwc37e_blend_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+ u32 *push;
+ if ((push = evo_wait(&wndw->wndw, 8))) {
+ evo_mthd(push, 0x02ec, 7);
+ evo_data(push, asyw->blend.depth << 4);
+ evo_data(push, asyw->blend.k1);
+ evo_data(push, asyw->blend.dst_color << 12 |
+ asyw->blend.dst_color << 8 |
+ asyw->blend.src_color << 4 |
+ asyw->blend.src_color);
+ evo_data(push, 0xffff0000);
+ evo_data(push, 0xffff0000);
+ evo_data(push, 0xffff0000);
+ evo_data(push, 0xffff0000);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
+void
wndwc37e_image_clr(struct nv50_wndw *wndw)
{
u32 *push;
@@ -77,12 +114,12 @@ wndwc37e_image_clr(struct nv50_wndw *wndw)
}
}
-void
+static void
wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
{
u32 *push;
- if (!(push = evo_wait(&wndw->wndw, 25)))
+ if (!(push = evo_wait(&wndw->wndw, 17)))
return;
evo_mthd(push, 0x0308, 1);
@@ -90,7 +127,9 @@ wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
evo_mthd(push, 0x0224, 4);
evo_data(push, asyw->image.h << 16 | asyw->image.w);
evo_data(push, asyw->image.layout << 4 | asyw->image.blockh);
- evo_data(push, asyw->image.colorspace << 8 | asyw->image.format);
+ evo_data(push, asyw->csc.valid << 17 |
+ asyw->image.colorspace << 8 |
+ asyw->image.format);
evo_data(push, asyw->image.blocks[0] | (asyw->image.pitch[0] >> 6));
evo_mthd(push, 0x0240, 1);
evo_data(push, asyw->image.handle[0]);
@@ -105,16 +144,6 @@ wndwc37e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
evo_mthd(push, 0x02a4, 1);
evo_data(push, asyw->state.crtc_h << 16 |
asyw->state.crtc_w);
-
- /*XXX: Composition-related stuff. Need to implement properly. */
- evo_mthd(push, 0x02ec, 1);
- evo_data(push, (2 - (wndw->id & 1)) << 4);
- evo_mthd(push, 0x02f4, 5);
- evo_data(push, 0x00000011);
- evo_data(push, 0xffff0000);
- evo_data(push, 0xffff0000);
- evo_data(push, 0xffff0000);
- evo_data(push, 0xffff0000);
evo_kick(push, &wndw->wndw);
}
@@ -216,6 +245,8 @@ wndwc37e_format[] = {
DRM_FORMAT_ABGR8888,
DRM_FORMAT_XRGB2101010,
DRM_FORMAT_ARGB2101010,
+ DRM_FORMAT_XBGR16161616F,
+ DRM_FORMAT_ABGR16161616F,
0
};
@@ -232,8 +263,12 @@ wndwc37e = {
.ilut = wndwc37e_ilut,
.xlut_set = wndwc37e_ilut_set,
.xlut_clr = wndwc37e_ilut_clr,
+ .csc = base907c_csc,
+ .csc_set = wndwc37e_csc_set,
+ .csc_clr = wndwc37e_csc_clr,
.image_set = wndwc37e_image_set,
.image_clr = wndwc37e_image_clr,
+ .blend_set = wndwc37e_blend_set,
.update = wndwc37e_update,
};
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
index ba89f1a5fcfa..a311c79e5295 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
@@ -29,6 +29,72 @@
#include <nvif/clc37e.h>
static void
+wndwc57e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+ u32 *push;
+
+ if (!(push = evo_wait(&wndw->wndw, 17)))
+ return;
+
+ evo_mthd(push, 0x0308, 1);
+ evo_data(push, asyw->image.mode << 4 | asyw->image.interval);
+ evo_mthd(push, 0x0224, 4);
+ evo_data(push, asyw->image.h << 16 | asyw->image.w);
+ evo_data(push, asyw->image.layout << 4 | asyw->image.blockh);
+ evo_data(push, asyw->image.colorspace << 8 |
+ asyw->image.format);
+ evo_data(push, asyw->image.blocks[0] | (asyw->image.pitch[0] >> 6));
+ evo_mthd(push, 0x0240, 1);
+ evo_data(push, asyw->image.handle[0]);
+ evo_mthd(push, 0x0260, 1);
+ evo_data(push, asyw->image.offset[0] >> 8);
+ evo_mthd(push, 0x0290, 1);
+ evo_data(push, (asyw->state.src_y >> 16) << 16 |
+ (asyw->state.src_x >> 16));
+ evo_mthd(push, 0x0298, 1);
+ evo_data(push, (asyw->state.src_h >> 16) << 16 |
+ (asyw->state.src_w >> 16));
+ evo_mthd(push, 0x02a4, 1);
+ evo_data(push, asyw->state.crtc_h << 16 |
+ asyw->state.crtc_w);
+ evo_kick(push, &wndw->wndw);
+}
+
+static void
+wndwc57e_csc_clr(struct nv50_wndw *wndw)
+{
+ u32 *push;
+ if ((push = evo_wait(&wndw->wndw, 13))) {
+ evo_mthd(push, 0x0400, 12);
+ evo_data(push, 0x00010000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00010000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00000000);
+ evo_data(push, 0x00010000);
+ evo_data(push, 0x00000000);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
+static void
+wndwc57e_csc_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+ u32 *push, i;
+ if ((push = evo_wait(&wndw->wndw, 13))) {
+ evo_mthd(push, 0x0400, 12);
+ for (i = 0; i < 12; i++)
+ evo_data(push, asyw->csc.matrix[i]);
+ evo_kick(push, &wndw->wndw);
+ }
+}
+
+static void
wndwc57e_ilut_clr(struct nv50_wndw *wndw)
{
u32 *push;
@@ -119,8 +185,12 @@ wndwc57e = {
.ilut_identity = true,
.xlut_set = wndwc57e_ilut_set,
.xlut_clr = wndwc57e_ilut_clr,
- .image_set = wndwc37e_image_set,
+ .csc = base907c_csc,
+ .csc_set = wndwc57e_csc_set,
+ .csc_clr = wndwc57e_csc_clr,
+ .image_set = wndwc57e_image_set,
.image_clr = wndwc37e_image_clr,
+ .blend_set = wndwc37e_blend_set,
.update = wndwc37e_update,
};