#define __NV50_KMS_CORE_H__
 #include "disp.h"
 #include "atom.h"
+#include <nouveau_encoder.h>
 
 struct nv50_core {
        const struct nv50_core_func *func;
 struct nv50_core_func {
        void (*init)(struct nv50_core *);
        void (*ntfy_init)(struct nouveau_bo *, u32 offset);
+       int (*caps_init)(struct nouveau_drm *, struct nv50_disp *);
        int (*ntfy_wait_done)(struct nouveau_bo *, u32 offset,
                              struct nvif_device *);
        void (*update)(struct nv50_core *, u32 *interlock, bool ntfy);
        const struct nv50_outp_func {
                void (*ctrl)(struct nv50_core *, int or, u32 ctrl,
                             struct nv50_head_atom *);
+               /* XXX: Only used by SORs and PIORs for now */
+               void (*get_caps)(struct nv50_disp *,
+                                struct nouveau_encoder *, int or);
        } *dac, *pior, *sor;
 };
 
                  struct nv50_core **);
 void core507d_init(struct nv50_core *);
 void core507d_ntfy_init(struct nouveau_bo *, u32);
+int core507d_caps_init(struct nouveau_drm *, struct nv50_disp *);
 int core507d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *);
 void core507d_update(struct nv50_core *, u32 *, bool);
 
 int core917d_new(struct nouveau_drm *, s32, struct nv50_core **);
 
 int corec37d_new(struct nouveau_drm *, s32, struct nv50_core **);
+int corec37d_caps_init(struct nouveau_drm *, struct nv50_disp *);
 int corec37d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *);
 void corec37d_update(struct nv50_core *, u32 *, bool);
 void corec37d_wndw_owner(struct nv50_core *);
 
        nouveau_bo_wr32(bo, offset / 4, 0x00000000);
 }
 
+int
+core507d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp)
+{
+       u32 *push = evo_wait(&disp->core->chan, 2);
+
+       if (push) {
+               evo_mthd(push, 0x008c, 1);
+               evo_data(push, 0x0);
+               evo_kick(push, &disp->core->chan);
+       }
+
+       return 0;
+}
+
 void
 core507d_init(struct nv50_core *core)
 {
 core507d = {
        .init = core507d_init,
        .ntfy_init = core507d_ntfy_init,
+       .caps_init = core507d_caps_init,
        .ntfy_wait_done = core507d_ntfy_wait_done,
        .update = core507d_update,
        .head = &head507d,
 
 core827d = {
        .init = core507d_init,
        .ntfy_init = core507d_ntfy_init,
+       .caps_init = core507d_caps_init,
        .ntfy_wait_done = core507d_ntfy_wait_done,
        .update = core507d_update,
        .head = &head827d,
 
 core907d = {
        .init = core507d_init,
        .ntfy_init = core507d_ntfy_init,
+       .caps_init = core507d_caps_init,
        .ntfy_wait_done = core507d_ntfy_wait_done,
        .update = core507d_update,
        .head = &head907d,
 
 core917d = {
        .init = core507d_init,
        .ntfy_init = core507d_ntfy_init,
+       .caps_init = core507d_caps_init,
        .ntfy_wait_done = core507d_ntfy_wait_done,
        .update = core507d_update,
        .head = &head917d,
 
 #include "core.h"
 #include "head.h"
 
+#include <nvif/class.h>
 #include <nouveau_bo.h>
 
 #include <nvif/timer.h>
        nouveau_bo_wr32(bo, offset / 4 + 3, 0x00000000);
 }
 
+int corec37d_caps_init(struct nouveau_drm *drm, struct nv50_disp *disp)
+{
+       int ret;
+
+       ret = nvif_object_init(&disp->disp->object, 0, GV100_DISP_CAPS,
+                              NULL, 0, &disp->caps);
+       if (ret) {
+               NV_ERROR(drm,
+                        "Failed to init notifier caps region: %d\n",
+                        ret);
+               return ret;
+       }
+
+       ret = nvif_object_map(&disp->caps, NULL, 0);
+       if (ret) {
+               NV_ERROR(drm,
+                        "Failed to map notifier caps region: %d\n",
+                        ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static void
 corec37d_init(struct nv50_core *core)
 {
 corec37d = {
        .init = corec37d_init,
        .ntfy_init = corec37d_ntfy_init,
+       .caps_init = corec37d_caps_init,
        .ntfy_wait_done = corec37d_ntfy_wait_done,
        .update = corec37d_update,
        .wndw.owner = corec37d_wndw_owner,
 
 corec57d = {
        .init = corec57d_init,
        .ntfy_init = corec37d_ntfy_init,
+       .caps_init = corec37d_caps_init,
        .ntfy_wait_done = corec37d_ntfy_wait_done,
        .update = corec37d_update,
        .wndw.owner = corec37d_wndw_owner,
 
        struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device);
        struct nouveau_encoder *nv_encoder;
        struct drm_encoder *encoder;
+       struct nv50_disp *disp = nv50_disp(connector->dev);
        int type, ret;
 
        switch (dcbe->type) {
 
        drm_connector_attach_encoder(connector, encoder);
 
+       disp->core->func->sor->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1);
+
        if (dcbe->type == DCB_OUTPUT_DP) {
-               struct nv50_disp *disp = nv50_disp(encoder->dev);
                struct nvkm_i2c_aux *aux =
                        nvkm_i2c_aux_find(i2c, dcbe->i2c_index);
+
                if (aux) {
                        if (disp->disp->object.oclass < GF110_DISP) {
                                /* HW has no support for address-only
 static int
 nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
 {
-       struct nouveau_drm *drm = nouveau_drm(connector->dev);
+       struct drm_device *dev = connector->dev;
+       struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nv50_disp *disp = nv50_disp(dev);
        struct nvkm_i2c *i2c = nvxx_i2c(&drm->client.device);
        struct nvkm_i2c_bus *bus = NULL;
        struct nvkm_i2c_aux *aux = NULL;
        drm_encoder_helper_add(encoder, &nv50_pior_help);
 
        drm_connector_attach_encoder(connector, encoder);
+
+       disp->core->func->pior->get_caps(disp, nv_encoder, ffs(dcbe->or) - 1);
+
        return 0;
 }
 
 
        nv50_audio_component_fini(nouveau_drm(dev));
 
+       nvif_object_unmap(&disp->caps);
+       nvif_object_fini(&disp->caps);
        nv50_core_del(&disp->core);
 
        nouveau_bo_unmap(disp->sync);
                goto out;
 
        disp->core->func->init(disp->core);
+       if (disp->core->func->caps_init) {
+               ret = disp->core->func->caps_init(drm, disp);
+               if (ret)
+                       goto out;
+       }
 
        /* Assign the correct format modifiers */
        if (disp->disp->object.oclass >= TU102_DISP)
 
 struct nv50_disp {
        struct nvif_disp *disp;
        struct nv50_core *core;
+       struct nvif_object caps;
 
 #define NV50_DISP_SYNC(c, o)                                ((c) * 0x040 + (o))
 #define NV50_DISP_CORE_NTFY                       NV50_DISP_SYNC(0      , 0x00)
 
        }
 }
 
+static void
+pior507d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp,
+                 int or)
+{
+       outp->caps.dp_interlace = true;
+}
+
 const struct nv50_outp_func
 pior507d = {
        .ctrl = pior507d_ctrl,
+       .get_caps = pior507d_get_caps,
 };
 
        }
 }
 
+static void
+sor507d_get_caps(struct nv50_disp *core, struct nouveau_encoder *outp, int or)
+{
+       outp->caps.dp_interlace = true;
+}
+
 const struct nv50_outp_func
 sor507d = {
        .ctrl = sor507d_ctrl,
+       .get_caps = sor507d_get_caps,
 };
 
  */
 #include "core.h"
 
+#include <nouveau_bo.h>
 #include <nvif/class.h>
 
 static void
        }
 }
 
+static void
+sor907d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp, int or)
+{
+       const int off = or * 2;
+       u32 tmp = nouveau_bo_rd32(disp->sync, 0x000014 + off);
+
+       outp->caps.dp_interlace = !!(tmp & 0x04000000);
+}
+
 const struct nv50_outp_func
 sor907d = {
        .ctrl = sor907d_ctrl,
+       .get_caps = sor907d_get_caps,
 };
 
        }
 }
 
+static void
+sorc37d_get_caps(struct nv50_disp *disp, struct nouveau_encoder *outp, int or)
+{
+       u32 tmp = nvif_rd32(&disp->caps, 0x000144 + (or * 8));
+
+       outp->caps.dp_interlace = !!(tmp & 0x04000000);
+}
+
 const struct nv50_outp_func
 sorc37d = {
        .ctrl = sorc37d_ctrl,
+       .get_caps = sorc37d_get_caps,
 };
 
        nv_connector->detected_encoder = nv_encoder;
 
        if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
-               connector->interlace_allowed = true;
+               if (nv_encoder->dcb->type == DCB_OUTPUT_DP)
+                       connector->interlace_allowed =
+                               nv_encoder->caps.dp_interlace;
+               else
+                       connector->interlace_allowed = true;
                connector->doublescan_allowed = true;
        } else
        if (nv_encoder->dcb->type == DCB_OUTPUT_LVDS ||
        case DCB_OUTPUT_TV:
                return get_slave_funcs(encoder)->mode_valid(encoder, mode);
        case DCB_OUTPUT_DP:
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE &&
+                   !nv_encoder->caps.dp_interlace)
+                       return MODE_NO_INTERLACE;
+
                max_clock  = nv_encoder->dp.link_nr;
                max_clock *= nv_encoder->dp.link_bw;
                clock = clock * (connector->display_info.bpc * 3) / 10;
 
                } dp;
        };
 
+       struct {
+               bool dp_interlace : 1;
+       } caps;
+
        void (*enc_save)(struct drm_encoder *encoder);
        void (*enc_restore)(struct drm_encoder *encoder);
        void (*update)(struct nouveau_encoder *, u8 head,