summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/dispnv50/head.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50/head.c')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/head.c89
1 files changed, 53 insertions, 36 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c
index ec361d17e900..3dd742b4f823 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/head.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
@@ -32,7 +32,7 @@
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
#include <drm/drm_vblank.h>
#include "nouveau_connector.h"
@@ -50,11 +50,9 @@ nv50_head_flush_clr(struct nv50_head *head,
}
void
-nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
+nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh)
{
- if (asyh->set.view ) head->func->view (head, asyh);
- if (asyh->set.mode ) head->func->mode (head, asyh);
- if (asyh->set.core ) head->func->core_set(head, asyh);
+ if (asyh->set.curs ) head->func->curs_set(head, asyh);
if (asyh->set.olut ) {
asyh->olut.offset = nv50_lut_load(&head->olut,
asyh->olut.buffer,
@@ -62,7 +60,14 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
asyh->olut.load);
head->func->olut_set(head, asyh);
}
- if (asyh->set.curs ) head->func->curs_set(head, asyh);
+}
+
+void
+nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
+{
+ if (asyh->set.view ) head->func->view (head, asyh);
+ if (asyh->set.mode ) head->func->mode (head, asyh);
+ if (asyh->set.core ) head->func->core_set(head, asyh);
if (asyh->set.base ) head->func->base (head, asyh);
if (asyh->set.ovly ) head->func->ovly (head, asyh);
if (asyh->set.dither ) head->func->dither (head, asyh);
@@ -122,14 +127,8 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
struct drm_display_mode *omode = &asyh->state.adjusted_mode;
struct drm_display_mode *umode = &asyh->state.mode;
int mode = asyc->scaler.mode;
- struct edid *edid;
int umode_vdisplay, omode_hdisplay, omode_vdisplay;
- if (connector->edid_blob_ptr)
- edid = (struct edid *)connector->edid_blob_ptr->data;
- else
- edid = NULL;
-
if (!asyc->scaler.full) {
if (mode == DRM_MODE_SCALE_NONE)
omode = umode;
@@ -157,7 +156,7 @@ nv50_head_atomic_check_view(struct nv50_head_atom *armh,
*/
if ((asyc->scaler.underscan.mode == UNDERSCAN_ON ||
(asyc->scaler.underscan.mode == UNDERSCAN_AUTO &&
- drm_detect_hdmi_monitor(edid)))) {
+ connector->display_info.is_hdmi))) {
u32 bX = asyc->scaler.underscan.hborder;
u32 bY = asyc->scaler.underscan.vborder;
u32 r = (asyh->view.oH << 19) / asyh->view.oW;
@@ -221,10 +220,24 @@ static int
nv50_head_atomic_check_lut(struct nv50_head *head,
struct nv50_head_atom *asyh)
{
- struct nv50_disp *disp = nv50_disp(head->base.base.dev);
- struct drm_property_blob *olut = asyh->state.gamma_lut;
+ struct drm_device *dev = head->base.base.dev;
+ struct drm_crtc *crtc = &head->base.base;
+ struct nv50_disp *disp = nv50_disp(dev);
+ struct nouveau_drm *drm = nouveau_drm(dev);
+ struct drm_property_blob *olut = asyh->state.gamma_lut,
+ *ilut = asyh->state.degamma_lut;
int size;
+ /* Ensure that the ilut is valid */
+ if (ilut) {
+ size = drm_color_lut_size(ilut);
+ if (!head->func->ilut_check(size)) {
+ NV_ATOMIC(drm, "Invalid size %d for degamma on [CRTC:%d:%s]\n",
+ size, crtc->base.id, crtc->name);
+ return -EINVAL;
+ }
+ }
+
/* Determine whether core output LUT should be enabled. */
if (olut) {
/* Check if any window(s) have stolen the core output LUT
@@ -251,7 +264,8 @@ nv50_head_atomic_check_lut(struct nv50_head *head,
}
if (!head->func->olut(head, asyh, size)) {
- DRM_DEBUG_KMS("Invalid olut\n");
+ NV_ATOMIC(drm, "Invalid size %d for gamma on [CRTC:%d:%s]\n",
+ size, crtc->base.id, crtc->name);
return -EINVAL;
}
asyh->olut.handle = disp->core->chan.vram.handle;
@@ -325,8 +339,17 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
struct drm_connector_state *conns;
struct drm_connector *conn;
int i, ret;
+ bool check_lut = asyh->state.color_mgmt_changed ||
+ memcmp(&armh->wndw, &asyh->wndw, sizeof(asyh->wndw));
NV_ATOMIC(drm, "%s atomic_check %d\n", crtc->name, asyh->state.active);
+
+ if (check_lut) {
+ ret = nv50_head_atomic_check_lut(head, asyh);
+ if (ret)
+ return ret;
+ }
+
if (asyh->state.active) {
for_each_new_connector_in_state(asyh->state.state, conn, conns, i) {
if (conns->crtc == crtc) {
@@ -352,14 +375,8 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_atomic_state *state)
if (asyh->state.mode_changed || asyh->state.connectors_changed)
nv50_head_atomic_check_mode(head, asyh);
- if (asyh->state.color_mgmt_changed ||
- memcmp(&armh->wndw, &asyh->wndw, sizeof(asyh->wndw))) {
- int ret = nv50_head_atomic_check_lut(head, asyh);
- if (ret)
- return ret;
-
+ if (check_lut)
asyh->olut.visible = asyh->olut.handle != 0;
- }
if (asyc) {
if (asyc->set.scaler)
@@ -494,7 +511,8 @@ nv50_head_destroy(struct drm_crtc *crtc)
{
struct nv50_head *head = nv50_head(crtc);
- nvif_notify_dtor(&head->base.vblank);
+ nvif_event_dtor(&head->base.vblank);
+ nvif_head_dtor(&head->base.head);
nv50_lut_fini(&head->olut);
drm_crtc_cleanup(crtc);
kfree(head);
@@ -531,15 +549,15 @@ nvd9_head_func = {
.late_register = nv50_head_late_register,
};
-static int nv50_head_vblank_handler(struct nvif_notify *notify)
+static int
+nv50_head_vblank_handler(struct nvif_event *event, void *repv, u32 repc)
{
- struct nouveau_crtc *nv_crtc =
- container_of(notify, struct nouveau_crtc, vblank);
+ struct nouveau_crtc *nv_crtc = container_of(event, struct nouveau_crtc, vblank);
if (drm_crtc_handle_vblank(&nv_crtc->base))
nv50_crc_handle_vblank(nv50_head(&nv_crtc->base));
- return NVIF_NOTIFY_KEEP;
+ return NVIF_EVENT_KEEP;
}
struct nv50_head *
@@ -559,6 +577,7 @@ nv50_head_create(struct drm_device *dev, int index)
return ERR_PTR(-ENOMEM);
head->func = disp->core->func->head;
+ head->disp = disp;
head->base.index = index;
if (disp->disp->object.oclass < GF110_DISP)
@@ -601,14 +620,12 @@ nv50_head_create(struct drm_device *dev, int index)
}
}
- ret = nvif_notify_ctor(&disp->disp->object, "kmsVbl", nv50_head_vblank_handler,
- false, NV04_DISP_NTFY_VBLANK,
- &(struct nvif_notify_head_req_v0) {
- .head = nv_crtc->index,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &nv_crtc->vblank);
+ ret = nvif_head_ctor(disp->disp, head->base.base.name, head->base.index, &head->base.head);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = nvif_head_vblank_event_ctor(&head->base.head, "kmsVbl", nv50_head_vblank_handler,
+ false, &nv_crtc->vblank);
if (ret)
return ERR_PTR(ret);