summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/nouveau/dispnv50/disp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50/disp.c')
-rw-r--r--drivers/gpu/drm/nouveau/dispnv50/disp.c339
1 files changed, 223 insertions, 116 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index 800b7757252e..e7874877da85 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -26,6 +26,7 @@
#include "core.h"
#include "head.h"
#include "wndw.h"
+#include "handles.h"
#include <linux/dma-mapping.h>
#include <linux/hdmi.h>
@@ -40,6 +41,8 @@
#include <drm/drm_scdc_helper.h>
#include <drm/drm_vblank.h>
+#include <nvif/push507c.h>
+
#include <nvif/class.h>
#include <nvif/cl0002.h>
#include <nvif/cl5070.h>
@@ -47,6 +50,13 @@
#include <nvif/event.h>
#include <nvif/timer.h>
+#include <nvhw/class/cl507c.h>
+#include <nvhw/class/cl507d.h>
+#include <nvhw/class/cl837d.h>
+#include <nvhw/class/cl887d.h>
+#include <nvhw/class/cl907d.h>
+#include <nvhw/class/cl917d.h>
+
#include "nouveau_drv.h"
#include "nouveau_dma.h"
#include "nouveau_gem.h"
@@ -58,24 +68,6 @@
#include <subdev/bios/dp.h>
/******************************************************************************
- * Atomic state
- *****************************************************************************/
-
-struct nv50_outp_atom {
- struct list_head head;
-
- struct drm_encoder *encoder;
- bool flush_disable;
-
- union nv50_outp_atom_mask {
- struct {
- bool ctrl:1;
- };
- u8 mask;
- } set, clr;
-};
-
-/******************************************************************************
* EVO channel
*****************************************************************************/
@@ -96,8 +88,9 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
while (oclass[0]) {
for (i = 0; i < n; i++) {
if (sclass[i].oclass == oclass[0]) {
- ret = nvif_object_init(disp, 0, oclass[0],
- data, size, &chan->user);
+ ret = nvif_object_ctor(disp, "kmsChan", 0,
+ oclass[0], data, size,
+ &chan->user);
if (ret == 0)
nvif_object_map(&chan->user, NULL, 0);
nvif_object_sclass_put(&sclass);
@@ -114,7 +107,7 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp,
static void
nv50_chan_destroy(struct nv50_chan *chan)
{
- nvif_object_fini(&chan->user);
+ nvif_object_dtor(&chan->user);
}
/******************************************************************************
@@ -124,12 +117,106 @@ nv50_chan_destroy(struct nv50_chan *chan)
void
nv50_dmac_destroy(struct nv50_dmac *dmac)
{
- nvif_object_fini(&dmac->vram);
- nvif_object_fini(&dmac->sync);
+ nvif_object_dtor(&dmac->vram);
+ nvif_object_dtor(&dmac->sync);
nv50_chan_destroy(&dmac->base);
- nvif_mem_fini(&dmac->push);
+ nvif_mem_dtor(&dmac->_push.mem);
+}
+
+static void
+nv50_dmac_kick(struct nvif_push *push)
+{
+ struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push);
+
+ dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr;
+ if (dmac->put != dmac->cur) {
+ /* Push buffer fetches are not coherent with BAR1, we need to ensure
+ * writes have been flushed right through to VRAM before writing PUT.
+ */
+ if (dmac->push->mem.type & NVIF_MEM_VRAM) {
+ struct nvif_device *device = dmac->base.device;
+ nvif_wr32(&device->object, 0x070000, 0x00000001);
+ nvif_msec(device, 2000,
+ if (!(nvif_rd32(&device->object, 0x070000) & 0x00000002))
+ break;
+ );
+ }
+
+ NVIF_WV32(&dmac->base.user, NV507C, PUT, PTR, dmac->cur);
+ dmac->put = dmac->cur;
+ }
+
+ push->bgn = push->cur;
+}
+
+static int
+nv50_dmac_free(struct nv50_dmac *dmac)
+{
+ u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR);
+ if (get > dmac->cur) /* NVIDIA stay 5 away from GET, do the same. */
+ return get - dmac->cur - 5;
+ return dmac->max - dmac->cur;
+}
+
+static int
+nv50_dmac_wind(struct nv50_dmac *dmac)
+{
+ /* Wait for GET to depart from the beginning of the push buffer to
+ * prevent writing PUT == GET, which would be ignored by HW.
+ */
+ u32 get = NVIF_RV32(&dmac->base.user, NV507C, GET, PTR);
+ if (get == 0) {
+ /* Corner-case, HW idle, but non-committed work pending. */
+ if (dmac->put == 0)
+ nv50_dmac_kick(dmac->push);
+
+ if (nvif_msec(dmac->base.device, 2000,
+ if (NVIF_TV32(&dmac->base.user, NV507C, GET, PTR, >, 0))
+ break;
+ ) < 0)
+ return -ETIMEDOUT;
+ }
+
+ PUSH_RSVD(dmac->push, PUSH_JUMP(dmac->push, 0));
+ dmac->cur = 0;
+ return 0;
+}
+
+static int
+nv50_dmac_wait(struct nvif_push *push, u32 size)
+{
+ struct nv50_dmac *dmac = container_of(push, typeof(*dmac), _push);
+ int free;
+
+ if (WARN_ON(size > dmac->max))
+ return -EINVAL;
+
+ dmac->cur = push->cur - (u32 *)dmac->_push.mem.object.map.ptr;
+ if (dmac->cur + size >= dmac->max) {
+ int ret = nv50_dmac_wind(dmac);
+ if (ret)
+ return ret;
+
+ push->cur = dmac->_push.mem.object.map.ptr;
+ push->cur = push->cur + dmac->cur;
+ nv50_dmac_kick(push);
+ }
+
+ if (nvif_msec(dmac->base.device, 2000,
+ if ((free = nv50_dmac_free(dmac)) >= size)
+ break;
+ ) < 0) {
+ WARN_ON(1);
+ return -ETIMEDOUT;
+ }
+
+ push->bgn = dmac->_push.mem.object.map.ptr;
+ push->bgn = push->bgn + dmac->cur;
+ push->cur = push->bgn;
+ push->end = push->cur + free;
+ return 0;
}
int
@@ -156,13 +243,21 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
if (device->info.family == NV_DEVICE_INFO_V0_PASCAL)
type |= NVIF_MEM_VRAM;
- ret = nvif_mem_init_map(&cli->mmu, type, 0x1000, &dmac->push);
+ ret = nvif_mem_ctor_map(&cli->mmu, "kmsChanPush", type, 0x1000,
+ &dmac->_push.mem);
if (ret)
return ret;
- dmac->ptr = dmac->push.object.map.ptr;
+ dmac->ptr = dmac->_push.mem.object.map.ptr;
+ dmac->_push.wait = nv50_dmac_wait;
+ dmac->_push.kick = nv50_dmac_kick;
+ dmac->push = &dmac->_push;
+ dmac->push->bgn = dmac->_push.mem.object.map.ptr;
+ dmac->push->cur = dmac->push->bgn;
+ dmac->push->end = dmac->push->bgn;
+ dmac->max = 0x1000/4 - 1;
- args->pushbuf = nvif_handle(&dmac->push.object);
+ args->pushbuf = nvif_handle(&dmac->_push.mem.object);
ret = nv50_chan_create(device, disp, oclass, head, data, size,
&dmac->base);
@@ -172,7 +267,8 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
if (!syncbuf)
return 0;
- ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY,
+ ret = nvif_object_ctor(&dmac->base.user, "kmsSyncCtxDma", NV50_DISP_HANDLE_SYNCBUF,
+ NV_DMA_IN_MEMORY,
&(struct nv_dma_v0) {
.target = NV_DMA_V0_TARGET_VRAM,
.access = NV_DMA_V0_ACCESS_RDWR,
@@ -183,7 +279,8 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
if (ret)
return ret;
- ret = nvif_object_init(&dmac->base.user, 0xf0000001, NV_DMA_IN_MEMORY,
+ ret = nvif_object_ctor(&dmac->base.user, "kmsVramCtxDma", NV50_DISP_HANDLE_VRAM,
+ NV_DMA_IN_MEMORY,
&(struct nv_dma_v0) {
.target = NV_DMA_V0_TARGET_VRAM,
.access = NV_DMA_V0_ACCESS_RDWR,
@@ -198,64 +295,6 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
}
/******************************************************************************
- * EVO channel helpers
- *****************************************************************************/
-static void
-evo_flush(struct nv50_dmac *dmac)
-{
- /* Push buffer fetches are not coherent with BAR1, we need to ensure
- * writes have been flushed right through to VRAM before writing PUT.
- */
- if (dmac->push.type & NVIF_MEM_VRAM) {
- struct nvif_device *device = dmac->base.device;
- nvif_wr32(&device->object, 0x070000, 0x00000001);
- nvif_msec(device, 2000,
- if (!(nvif_rd32(&device->object, 0x070000) & 0x00000002))
- break;
- );
- }
-}
-
-u32 *
-evo_wait(struct nv50_dmac *evoc, int nr)
-{
- struct nv50_dmac *dmac = evoc;
- struct nvif_device *device = dmac->base.device;
- u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4;
-
- mutex_lock(&dmac->lock);
- if (put + nr >= (PAGE_SIZE / 4) - 8) {
- dmac->ptr[put] = 0x20000000;
- evo_flush(dmac);
-
- nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
- if (nvif_msec(device, 2000,
- if (!nvif_rd32(&dmac->base.user, 0x0004))
- break;
- ) < 0) {
- mutex_unlock(&dmac->lock);
- pr_err("nouveau: evo channel stalled\n");
- return NULL;
- }
-
- put = 0;
- }
-
- return dmac->ptr + put;
-}
-
-void
-evo_kick(u32 *push, struct nv50_dmac *evoc)
-{
- struct nv50_dmac *dmac = evoc;
-
- evo_flush(dmac);
-
- nvif_wr32(&dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
- mutex_unlock(&dmac->lock);
-}
-
-/******************************************************************************
* Output path helpers
*****************************************************************************/
static void
@@ -380,8 +419,9 @@ nv50_dac_disable(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_core *core = nv50_disp(encoder->dev)->core;
+ const u32 ctrl = NVDEF(NV507D, DAC_SET_CONTROL, OWNER, NONE);
if (nv_encoder->crtc)
- core->func->dac->ctrl(core, nv_encoder->or, 0x00000000, NULL);
+ core->func->dac->ctrl(core, nv_encoder->or, ctrl, NULL);
nv_encoder->crtc = NULL;
nv50_outp_release(nv_encoder);
}
@@ -393,10 +433,23 @@ nv50_dac_enable(struct drm_encoder *encoder)
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state);
struct nv50_core *core = nv50_disp(encoder->dev)->core;
+ u32 ctrl = 0;
+
+ switch (nv_crtc->index) {
+ case 0: ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, OWNER, HEAD0); break;
+ case 1: ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, OWNER, HEAD1); break;
+ case 2: ctrl |= NVDEF(NV907D, DAC_SET_CONTROL, OWNER_MASK, HEAD2); break;
+ case 3: ctrl |= NVDEF(NV907D, DAC_SET_CONTROL, OWNER_MASK, HEAD3); break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ ctrl |= NVDEF(NV507D, DAC_SET_CONTROL, PROTOCOL, RGB_CRT);
nv50_outp_acquire(nv_encoder, false);
- core->func->dac->ctrl(core, nv_encoder->or, 1 << nv_crtc->index, asyh);
+ core->func->dac->ctrl(core, nv_encoder->or, ctrl, asyh);
asyh->or.depth = 0;
nv_encoder->crtc = encoder->crtc;
@@ -801,6 +854,19 @@ struct nv50_msto {
bool disabled;
};
+struct nouveau_encoder *nv50_real_outp(struct drm_encoder *encoder)
+{
+ struct nv50_msto *msto;
+
+ if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST)
+ return nouveau_encoder(encoder);
+
+ msto = nv50_msto(encoder);
+ if (!msto->mstc)
+ return NULL;
+ return msto->mstc->mstm->outp;
+}
+
static struct drm_dp_payload *
nv50_msto_payload(struct nv50_msto *msto)
{
@@ -933,10 +999,10 @@ static u8
nv50_dp_bpc_to_depth(unsigned int bpc)
{
switch (bpc) {
- case 6: return 0x2;
- case 8: return 0x5;
- case 10: /* fall-through */
- default: return 0x6;
+ case 6: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_18_444;
+ case 8: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444;
+ case 10:
+ default: return NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444;
}
}
@@ -975,9 +1041,9 @@ nv50_msto_enable(struct drm_encoder *encoder)
nv50_outp_acquire(mstm->outp, false /*XXX: MST audio.*/);
if (mstm->outp->link & 1)
- proto = 0x8;
+ proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
- proto = 0x9;
+ proto = NV917D_SOR_SET_CONTROL_PROTOCOL_DP_B;
mstm->outp->update(mstm->outp, head->base.index, armh, proto,
nv50_dp_bpc_to_depth(armh->or.bpc));
@@ -1506,10 +1572,10 @@ nv50_sor_update(struct nouveau_encoder *nv_encoder, u8 head,
if (!asyh) {
nv_encoder->ctrl &= ~BIT(head);
- if (!(nv_encoder->ctrl & 0x0000000f))
+ if (NVDEF_TEST(nv_encoder->ctrl, NV507D, SOR_SET_CONTROL, OWNER, ==, NONE))
nv_encoder->ctrl = 0;
} else {
- nv_encoder->ctrl |= proto << 8;
+ nv_encoder->ctrl |= NVVAL(NV507D, SOR_SET_CONTROL, PROTOCOL, proto);
nv_encoder->ctrl |= BIT(head);
asyh->or.depth = depth;
}
@@ -1567,8 +1633,8 @@ nv50_sor_enable(struct drm_encoder *encoder)
struct nouveau_connector *nv_connector;
struct nvbios *bios = &drm->vbios;
bool hda = false;
- u8 proto = 0xf;
- u8 depth = 0x0;
+ u8 proto = NV507D_SOR_SET_CONTROL_PROTOCOL_CUSTOM;
+ u8 depth = NV837D_SOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT;
nv_connector = nouveau_encoder_connector_get(nv_encoder);
nv_encoder->crtc = encoder->crtc;
@@ -1582,7 +1648,7 @@ nv50_sor_enable(struct drm_encoder *encoder)
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
if (nv_encoder->link & 1) {
- proto = 0x1;
+ proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_A;
/* Only enable dual-link if:
* - Need to (i.e. rate > 165MHz)
* - DCB says we can
@@ -1592,15 +1658,15 @@ nv50_sor_enable(struct drm_encoder *encoder)
if (mode->clock >= 165000 &&
nv_encoder->dcb->duallink_possible &&
!drm_detect_hdmi_monitor(nv_connector->edid))
- proto |= 0x4;
+ proto = NV507D_SOR_SET_CONTROL_PROTOCOL_DUAL_TMDS;
} else {
- proto = 0x2;
+ proto = NV507D_SOR_SET_CONTROL_PROTOCOL_SINGLE_TMDS_B;
}
nv50_hdmi_enable(&nv_encoder->base.base, mode);
break;
case DCB_OUTPUT_LVDS:
- proto = 0x0;
+ proto = NV507D_SOR_SET_CONTROL_PROTOCOL_LVDS_CUSTOM;
if (bios->fp_no_ddc) {
if (bios->fp.dual_link)
@@ -1634,9 +1700,9 @@ nv50_sor_enable(struct drm_encoder *encoder)
depth = nv50_dp_bpc_to_depth(asyh->or.bpc);
if (nv_encoder->link & 1)
- proto = 0x8;
+ proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_A;
else
- proto = 0x9;
+ proto = NV887D_SOR_SET_CONTROL_PROTOCOL_DP_B;
nv50_audio_enable(encoder, mode);
break;
@@ -1771,8 +1837,9 @@ nv50_pior_disable(struct drm_encoder *encoder)
{
struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
struct nv50_core *core = nv50_disp(encoder->dev)->core;
+ const u32 ctrl = NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, NONE);
if (nv_encoder->crtc)
- core->func->pior->ctrl(core, nv_encoder->or, 0x00000000, NULL);
+ core->func->pior->ctrl(core, nv_encoder->or, ctrl, NULL);
nv_encoder->crtc = NULL;
nv50_outp_release(nv_encoder);
}
@@ -1784,29 +1851,36 @@ nv50_pior_enable(struct drm_encoder *encoder)
struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc);
struct nv50_head_atom *asyh = nv50_head_atom(nv_crtc->base.state);
struct nv50_core *core = nv50_disp(encoder->dev)->core;
- u8 owner = 1 << nv_crtc->index;
- u8 proto;
+ u32 ctrl = 0;
+
+ switch (nv_crtc->index) {
+ case 0: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, HEAD0); break;
+ case 1: ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, OWNER, HEAD1); break;
+ default:
+ WARN_ON(1);
+ break;
+ }
nv50_outp_acquire(nv_encoder, false);
switch (asyh->or.bpc) {
- case 10: asyh->or.depth = 0x6; break;
- case 8: asyh->or.depth = 0x5; break;
- case 6: asyh->or.depth = 0x2; break;
- default: asyh->or.depth = 0x0; break;
+ case 10: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_30_444; break;
+ case 8: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_24_444; break;
+ case 6: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_BPP_18_444; break;
+ default: asyh->or.depth = NV837D_PIOR_SET_CONTROL_PIXEL_DEPTH_DEFAULT; break;
}
switch (nv_encoder->dcb->type) {
case DCB_OUTPUT_TMDS:
case DCB_OUTPUT_DP:
- proto = 0x0;
+ ctrl |= NVDEF(NV507D, PIOR_SET_CONTROL, PROTOCOL, EXT_TMDS_ENC);
break;
default:
BUG();
break;
}
- core->func->pior->ctrl(core, nv_encoder->or, (proto << 8) | owner, asyh);
+ core->func->pior->ctrl(core, nv_encoder->or, ctrl, asyh);
nv_encoder->crtc = encoder->crtc;
}
@@ -1948,8 +2022,10 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
struct nv50_outp_atom *outp, *outt;
u32 interlock[NV50_DISP_INTERLOCK__SIZE] = {};
int i;
+ bool flushed = false;
NV_ATOMIC(drm, "commit %d %d\n", atom->lock_core, atom->flush_disable);
+ nv50_crc_atomic_stop_reporting(state);
drm_atomic_helper_wait_for_fences(dev, state, false);
drm_atomic_helper_wait_for_dependencies(state);
drm_atomic_helper_update_legacy_modeset_state(dev, state);
@@ -2007,6 +2083,8 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
nv50_disp_atomic_commit_wndw(state, interlock);
nv50_disp_atomic_commit_core(state, interlock);
memset(interlock, 0x00, sizeof(interlock));
+
+ flushed = true;
}
}
}
@@ -2017,9 +2095,15 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
nv50_disp_atomic_commit_wndw(state, interlock);
nv50_disp_atomic_commit_core(state, interlock);
memset(interlock, 0x00, sizeof(interlock));
+
+ flushed = true;
}
}
+ if (flushed)
+ nv50_crc_atomic_release_notifier_contexts(state);
+ nv50_crc_atomic_init_notifier_contexts(state);
+
/* Update output path(s). */
list_for_each_entry_safe(outp, outt, &atom->outp, head) {
const struct drm_encoder_helper_funcs *help;
@@ -2133,6 +2217,9 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state)
}
}
+ nv50_crc_atomic_start_reporting(state);
+ if (!flushed)
+ nv50_crc_atomic_release_notifier_contexts(state);
drm_atomic_helper_commit_hw_done(state);
drm_atomic_helper_cleanup_planes(dev, state);
drm_atomic_helper_commit_cleanup_done(state);
@@ -2160,8 +2247,10 @@ nv50_disp_atomic_commit(struct drm_device *dev,
int ret, i;
ret = pm_runtime_get_sync(dev->dev);
- if (ret < 0 && ret != -EACCES)
+ if (ret < 0 && ret != -EACCES) {
+ pm_runtime_put_autosuspend(dev->dev);
return ret;
+ }
ret = drm_atomic_helper_setup_commit(state, nonblock);
if (ret)
@@ -2290,12 +2379,28 @@ static int
nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
{
struct nv50_atom *atom = nv50_atom(state);
+ struct nv50_core *core = nv50_disp(dev)->core;
struct drm_connector_state *old_connector_state, *new_connector_state;
struct drm_connector *connector;
struct drm_crtc_state *new_crtc_state;
struct drm_crtc *crtc;
+ struct nv50_head *head;
+ struct nv50_head_atom *asyh;
int ret, i;
+ if (core->assign_windows && core->func->head->static_wndw_map) {
+ drm_for_each_crtc(crtc, dev) {
+ new_crtc_state = drm_atomic_get_crtc_state(state,
+ crtc);
+ if (IS_ERR(new_crtc_state))
+ return PTR_ERR(new_crtc_state);
+
+ head = nv50_head(crtc);
+ asyh = nv50_head_atom(new_crtc_state);
+ core->func->head->static_wndw_map(head, asyh);
+ }
+ }
+
/* We need to handle colour management on a per-plane basis. */
for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
if (new_crtc_state->color_mgmt_changed) {
@@ -2323,6 +2428,8 @@ nv50_disp_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
if (ret)
return ret;
+ nv50_crc_atomic_check_outp(atom);
+
return 0;
}
@@ -2434,7 +2541,7 @@ nv50_display_destroy(struct drm_device *dev)
nv50_audio_component_fini(nouveau_drm(dev));
nvif_object_unmap(&disp->caps);
- nvif_object_fini(&disp->caps);
+ nvif_object_dtor(&disp->caps);
nv50_core_del(&disp->core);
nouveau_bo_unmap(disp->sync);