diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/dispnv50')
21 files changed, 214 insertions, 126 deletions
diff --git a/drivers/gpu/drm/nouveau/dispnv50/Kbuild b/drivers/gpu/drm/nouveau/dispnv50/Kbuild index 4488e1c061b3..28be2912ff74 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/Kbuild +++ b/drivers/gpu/drm/nouveau/dispnv50/Kbuild @@ -13,6 +13,7 @@ nouveau-y += dispnv50/corec57d.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crc.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crc907d.o nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crcc37d.o +nouveau-$(CONFIG_DEBUG_FS) += dispnv50/crcc57d.o nouveau-y += dispnv50/dac507d.o nouveau-y += dispnv50/dac907d.o diff --git a/drivers/gpu/drm/nouveau/dispnv50/base907c.c b/drivers/gpu/drm/nouveau/dispnv50/base907c.c index 5396e3707cc4..e6b0417c325b 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c +++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c @@ -103,12 +103,9 @@ base907c_xlut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) return 0; } -static bool +static void base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) { - if (size != 256 && size != 1024) - return false; - if (size == 1024) asyw->xlut.i.mode = NV907C_SET_BASE_LUT_LO_MODE_INTERPOLATE_1025_UNITY_RANGE; else @@ -116,7 +113,6 @@ base907c_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) asyw->xlut.i.enable = NV907C_SET_BASE_LUT_LO_ENABLE_ENABLE; asyw->xlut.i.load = head907d_olut_load; - return true; } static inline u32 diff --git a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c index 75876546eac1..53b1e2a569c1 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/corec57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/corec57d.c @@ -69,7 +69,7 @@ corec57d = { .head = &headc57d, .sor = &sorc37d, #if IS_ENABLED(CONFIG_DEBUG_FS) - .crc = &crcc37d, + .crc = &crcc57d, #endif }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index 66f32d965c72..29428e770f14 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -84,7 +84,10 @@ static void nv50_crc_ctx_flip_work(struct kthread_work *base) struct nv50_crc *crc = container_of(work, struct nv50_crc, flip_work); struct nv50_head *head = container_of(crc, struct nv50_head, crc); struct drm_crtc *crtc = &head->base.base; - struct nv50_disp *disp = nv50_disp(crtc->dev); + struct drm_device *dev = crtc->dev; + struct nv50_disp *disp = nv50_disp(dev); + const uint64_t start_vbl = drm_crtc_vblank_count(crtc); + uint64_t end_vbl; u8 new_idx = crc->ctx_idx ^ 1; /* @@ -92,23 +95,24 @@ static void nv50_crc_ctx_flip_work(struct kthread_work *base) * try again for the next vblank if we don't grab the lock */ if (!mutex_trylock(&disp->mutex)) { - DRM_DEV_DEBUG_KMS(crtc->dev->dev, - "Lock contended, delaying CRC ctx flip for head-%d\n", - head->base.index); - drm_vblank_work_schedule(work, - drm_crtc_vblank_count(crtc) + 1, - true); + drm_dbg_kms(dev, "Lock contended, delaying CRC ctx flip for %s\n", crtc->name); + drm_vblank_work_schedule(work, start_vbl + 1, true); return; } - DRM_DEV_DEBUG_KMS(crtc->dev->dev, - "Flipping notifier ctx for head %d (%d -> %d)\n", - drm_crtc_index(crtc), crc->ctx_idx, new_idx); + drm_dbg_kms(dev, "Flipping notifier ctx for %s (%d -> %d)\n", + crtc->name, crc->ctx_idx, new_idx); nv50_crc_program_ctx(head, NULL); nv50_crc_program_ctx(head, &crc->ctx[new_idx]); mutex_unlock(&disp->mutex); + end_vbl = drm_crtc_vblank_count(crtc); + if (unlikely(end_vbl != start_vbl)) + NV_ERROR(nouveau_drm(dev), + "Failed to flip CRC context on %s on time (%llu > %llu)\n", + crtc->name, end_vbl, start_vbl); + spin_lock_irq(&crc->lock); crc->ctx_changed = true; spin_unlock_irq(&crc->lock); @@ -189,9 +193,9 @@ void nv50_crc_handle_vblank(struct nv50_head *head) * updates back-to-back without waiting, we'll just be * optimistic and assume we always miss exactly one frame. */ - DRM_DEV_DEBUG_KMS(head->base.base.dev->dev, - "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n", - head->base.index, crc->frame); + drm_dbg_kms(head->base.base.dev, + "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n", + head->base.index, crc->frame); crc->frame++; nv50_crc_reset_ctx(ctx); @@ -347,8 +351,6 @@ int nv50_crc_atomic_check_head(struct nv50_head *head, struct nv50_head_atom *armh) { struct nv50_atom *atom = nv50_atom(asyh->state.state); - struct drm_device *dev = head->base.base.dev; - struct nv50_disp *disp = nv50_disp(dev); bool changed = armh->crc.src != asyh->crc.src; if (!armh->crc.src && !asyh->crc.src) { @@ -357,30 +359,7 @@ int nv50_crc_atomic_check_head(struct nv50_head *head, return 0; } - /* While we don't care about entry tags, Volta+ hw always needs the - * controlling wndw channel programmed to a wndw that's owned by our - * head - */ - if (asyh->crc.src && disp->disp->object.oclass >= GV100_DISP && - !(BIT(asyh->crc.wndw) & asyh->wndw.owned)) { - if (!asyh->wndw.owned) { - /* TODO: once we support flexible channel ownership, - * we should write some code here to handle attempting - * to "steal" a plane: e.g. take a plane that is - * currently not-visible and owned by another head, - * and reassign it to this head. If we fail to do so, - * we shuld reject the mode outright as CRC capture - * then becomes impossible. - */ - NV_ATOMIC(nouveau_drm(dev), - "No available wndws for CRC readback\n"); - return -EINVAL; - } - asyh->crc.wndw = ffs(asyh->wndw.owned) - 1; - } - - if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed || - armh->crc.wndw != asyh->crc.wndw) { + if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed) { asyh->clr.crc = armh->crc.src && armh->state.active; asyh->set.crc = asyh->crc.src && asyh->state.active; if (changed) @@ -467,9 +446,8 @@ void nv50_crc_atomic_set(struct nv50_head *head, struct nouveau_encoder *outp = nv50_real_outp(nv50_head_atom_get_encoder(asyh)); - func->set_src(head, outp->or, - nv50_crc_source_type(outp, asyh->crc.src), - &crc->ctx[crc->ctx_idx], asyh->crc.wndw); + func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src), + &crc->ctx[crc->ctx_idx]); } void nv50_crc_atomic_clr(struct nv50_head *head) @@ -477,7 +455,7 @@ void nv50_crc_atomic_clr(struct nv50_head *head) const struct nv50_crc_func *func = nv50_disp(head->base.base.dev)->core->func->crc; - func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL, 0); + func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL); } static inline int diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.h b/drivers/gpu/drm/nouveau/dispnv50/crc.h index 4fce871b04c8..4823f1fde2dd 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.h +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.h @@ -45,13 +45,11 @@ struct nv50_crc_notifier_ctx { struct nv50_crc_atom { enum nv50_crc_source src; - /* Only used for gv100+ */ - u8 wndw : 4; }; struct nv50_crc_func { - int (*set_src)(struct nv50_head *, int or, enum nv50_crc_source_type, - struct nv50_crc_notifier_ctx *, u32 wndw); + int (*set_src)(struct nv50_head *, int or, enum nv50_crc_source_type type, + struct nv50_crc_notifier_ctx *ctx); int (*set_ctx)(struct nv50_head *, struct nv50_crc_notifier_ctx *); u32 (*get_entry)(struct nv50_head *, struct nv50_crc_notifier_ctx *, enum nv50_crc_source, int idx); @@ -95,6 +93,7 @@ void nv50_crc_atomic_clr(struct nv50_head *); extern const struct nv50_crc_func crc907d; extern const struct nv50_crc_func crcc37d; +extern const struct nv50_crc_func crcc57d; #else /* IS_ENABLED(CONFIG_DEBUG_FS) */ struct nv50_crc {}; diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc907d.c b/drivers/gpu/drm/nouveau/dispnv50/crc907d.c index 0fb0fdb9f119..f9ad641555b7 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc907d.c @@ -23,9 +23,8 @@ struct crc907d_notifier { } __packed; static int -crc907d_set_src(struct nv50_head *head, int or, - enum nv50_crc_source_type source, - struct nv50_crc_notifier_ctx *ctx, u32 wndw) +crc907d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, + struct nv50_crc_notifier_ctx *ctx) { struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; const int i = head->base.index; @@ -33,7 +32,8 @@ crc907d_set_src(struct nv50_head *head, int or, NVDEF(NV907D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | NVDEF(NV907D, HEAD_SET_CRC_CONTROL, TIMESTAMP_MODE, FALSE) | NVDEF(NV907D, HEAD_SET_CRC_CONTROL, SECONDARY_OUTPUT, NONE) | - NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE); + NVDEF(NV907D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE) | + NVDEF(NV907D, HEAD_SET_CRC_CONTROL, WIDE_PIPE_CRC, ENABLE); int ret; switch (source) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c b/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c index 814e5bd97446..f10f6c484408 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crcc37d.c @@ -2,6 +2,7 @@ #include <drm/drm_crtc.h> #include "crc.h" +#include "crcc37d.h" #include "core.h" #include "disp.h" #include "head.h" @@ -10,38 +11,13 @@ #include <nvhw/class/clc37d.h> -#define CRCC37D_MAX_ENTRIES 2047 - -struct crcc37d_notifier { - u32 status; - - /* reserved */ - u32 :32; - u32 :32; - u32 :32; - u32 :32; - u32 :32; - u32 :32; - u32 :32; - - struct crcc37d_entry { - u32 status[2]; - u32 :32; /* reserved */ - u32 compositor_crc; - u32 rg_crc; - u32 output_crc[2]; - u32 :32; /* reserved */ - } entries[CRCC37D_MAX_ENTRIES]; -} __packed; - static int -crcc37d_set_src(struct nv50_head *head, int or, - enum nv50_crc_source_type source, - struct nv50_crc_notifier_ctx *ctx, u32 wndw) +crcc37d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, + struct nv50_crc_notifier_ctx *ctx) { struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; const int i = head->base.index; - u32 crc_args = NVVAL(NVC37D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, wndw) | + u32 crc_args = NVVAL(NVC37D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, i * 4) | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) | NVDEF(NVC37D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE); @@ -75,8 +51,7 @@ crcc37d_set_src(struct nv50_head *head, int or, return 0; } -static int -crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) +int crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) { struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; const int i = head->base.index; @@ -89,9 +64,8 @@ crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) return 0; } -static u32 crcc37d_get_entry(struct nv50_head *head, - struct nv50_crc_notifier_ctx *ctx, - enum nv50_crc_source source, int idx) +u32 crcc37d_get_entry(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx, + enum nv50_crc_source source, int idx) { struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr; struct crcc37d_entry __iomem *entry = ¬ifier->entries[idx]; @@ -105,8 +79,7 @@ static u32 crcc37d_get_entry(struct nv50_head *head, return ioread32_native(crc_addr); } -static bool crcc37d_ctx_finished(struct nv50_head *head, - struct nv50_crc_notifier_ctx *ctx) +bool crcc37d_ctx_finished(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx) { struct nouveau_drm *drm = nouveau_drm(head->base.base.dev); struct crcc37d_notifier __iomem *notifier = ctx->mem.object.map.ptr; @@ -148,7 +121,7 @@ const struct nv50_crc_func crcc37d = { .set_ctx = crcc37d_set_ctx, .get_entry = crcc37d_get_entry, .ctx_finished = crcc37d_ctx_finished, - .flip_threshold = CRCC37D_MAX_ENTRIES - 30, + .flip_threshold = CRCC37D_FLIP_THRESHOLD, .num_entries = CRCC37D_MAX_ENTRIES, .notifier_len = sizeof(struct crcc37d_notifier), }; diff --git a/drivers/gpu/drm/nouveau/dispnv50/crcc37d.h b/drivers/gpu/drm/nouveau/dispnv50/crcc37d.h new file mode 100644 index 000000000000..5775137b832d --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/crcc37d.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: MIT */ + +#ifndef __CRCC37D_H__ +#define __CRCC37D_H__ + +#include <linux/types.h> + +#include "crc.h" + +#define CRCC37D_MAX_ENTRIES 2047 +#define CRCC37D_FLIP_THRESHOLD (CRCC37D_MAX_ENTRIES - 30) + +struct crcc37d_notifier { + u32 status; + + /* reserved */ + u32:32; + u32:32; + u32:32; + u32:32; + u32:32; + u32:32; + u32:32; + + struct crcc37d_entry { + u32 status[2]; + u32:32; /* reserved */ + u32 compositor_crc; + u32 rg_crc; + u32 output_crc[2]; + u32:32; /* reserved */ + } entries[CRCC37D_MAX_ENTRIES]; +} __packed; + +int crcc37d_set_ctx(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx); +u32 crcc37d_get_entry(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx, + enum nv50_crc_source source, int idx); +bool crcc37d_ctx_finished(struct nv50_head *head, struct nv50_crc_notifier_ctx *ctx); + +#endif /* !__CRCC37D_H__ */ diff --git a/drivers/gpu/drm/nouveau/dispnv50/crcc57d.c b/drivers/gpu/drm/nouveau/dispnv50/crcc57d.c new file mode 100644 index 000000000000..cc0130e3d496 --- /dev/null +++ b/drivers/gpu/drm/nouveau/dispnv50/crcc57d.c @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT + +#include "crc.h" +#include "crcc37d.h" +#include "core.h" +#include "disp.h" +#include "head.h" + +#include <nvif/pushc37b.h> + +#include <nvhw/class/clc57d.h> + +static int crcc57d_set_src(struct nv50_head *head, int or, enum nv50_crc_source_type source, + struct nv50_crc_notifier_ctx *ctx) +{ + struct nvif_push *push = nv50_disp(head->base.base.dev)->core->chan.push; + const int i = head->base.index; + u32 crc_args = NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, CONTROLLING_CHANNEL, CORE) | + NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, EXPECT_BUFFER_COLLAPSE, FALSE) | + NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, SECONDARY_CRC, NONE) | + NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, CRC_DURING_SNOOZE, DISABLE); + int ret; + + switch (source) { + case NV50_CRC_SOURCE_TYPE_SOR: + crc_args |= NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SOR(or)); + break; + case NV50_CRC_SOURCE_TYPE_SF: + crc_args |= NVDEF(NVC57D, HEAD_SET_CRC_CONTROL, PRIMARY_CRC, SF); + break; + default: + break; + } + + ret = PUSH_WAIT(push, 4); + if (ret) + return ret; + + if (source) { + PUSH_MTHD(push, NVC57D, HEAD_SET_CONTEXT_DMA_CRC(i), ctx->ntfy.handle); + PUSH_MTHD(push, NVC57D, HEAD_SET_CRC_CONTROL(i), crc_args); + } else { + PUSH_MTHD(push, NVC57D, HEAD_SET_CRC_CONTROL(i), 0); + PUSH_MTHD(push, NVC57D, HEAD_SET_CONTEXT_DMA_CRC(i), 0); + } + + return 0; +} + +const struct nv50_crc_func crcc57d = { + .set_src = crcc57d_set_src, + .set_ctx = crcc37d_set_ctx, + .get_entry = crcc37d_get_entry, + .ctx_finished = crcc37d_ctx_finished, + .flip_threshold = CRCC37D_FLIP_THRESHOLD, + .num_entries = CRCC37D_MAX_ENTRIES, + .notifier_len = sizeof(struct crcc37d_notifier), +}; diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c index 54fbd6fe751d..00e19fd959ea 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c +++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c @@ -98,6 +98,7 @@ static int curs507a_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, struct nv50_head_atom *asyh) { + struct nouveau_drm *drm = nouveau_drm(wndw->plane.dev); struct nv50_head *head = nv50_head(asyw->state.crtc); int ret; @@ -109,8 +110,20 @@ curs507a_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, if (ret || !asyh->curs.visible) return ret; - if (asyw->image.w != asyw->image.h) + if (asyw->state.crtc_w != asyw->state.crtc_h) { + NV_ATOMIC(drm, "Plane width/height must be equal for cursors\n"); return -EINVAL; + } + + if (asyw->image.w != asyw->state.crtc_w) { + NV_ATOMIC(drm, "Plane width must be equal to fb width for cursors (height can be larger though)\n"); + return -EINVAL; + } + + if (asyw->state.src_x || asyw->state.src_y) { + NV_ATOMIC(drm, "Cursor planes do not support framebuffer offsets\n"); + return -EINVAL; + } ret = head->func->curs_layout(head, asyw, asyh); if (ret) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index 8e28403ea9b1..ae1f41205520 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -852,6 +852,9 @@ nv50_hdmi_enable(struct drm_encoder *encoder, struct nouveau_crtc *nv_crtc, ret = drm_hdmi_avi_infoframe_from_display_mode(&avi_frame.avi, &nv_connector->base, mode); if (!ret) { + drm_hdmi_avi_infoframe_quant_range(&avi_frame.avi, + &nv_connector->base, mode, + HDMI_QUANTIZATION_RANGE_FULL); /* We have an AVI InfoFrame, populate it to the display */ args.pwr.avi_infoframe_length = hdmi_infoframe_pack(&avi_frame, args.infoframes, 17); @@ -1387,12 +1390,11 @@ nv50_mstm_cleanup(struct nv50_mstm *mstm) { struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); struct drm_encoder *encoder; - int ret; NV_ATOMIC(drm, "%s: mstm cleanup\n", mstm->outp->base.base.name); - ret = drm_dp_check_act_status(&mstm->mgr); + drm_dp_check_act_status(&mstm->mgr); - ret = drm_dp_update_payload_part2(&mstm->mgr); + drm_dp_update_payload_part2(&mstm->mgr); drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { @@ -1411,10 +1413,9 @@ nv50_mstm_prepare(struct nv50_mstm *mstm) { struct nouveau_drm *drm = nouveau_drm(mstm->outp->base.base.dev); struct drm_encoder *encoder; - int ret; NV_ATOMIC(drm, "%s: mstm prepare\n", mstm->outp->base.base.name); - ret = drm_dp_update_payload_part1(&mstm->mgr, 1); + drm_dp_update_payload_part1(&mstm->mgr, 1); drm_for_each_encoder(encoder, mstm->outp->base.base.dev) { if (encoder->encoder_type == DRM_MODE_ENCODER_DPMST) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index 72099d1e4816..c3c57be54e1c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -226,10 +226,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 @@ -256,7 +270,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; @@ -330,8 +345,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) { @@ -357,14 +381,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) diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index 0bac6be9ba34..41c8788dfb31 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -29,6 +29,7 @@ struct nv50_head_func { int (*view)(struct nv50_head *, struct nv50_head_atom *); int (*mode)(struct nv50_head *, struct nv50_head_atom *); bool (*olut)(struct nv50_head *, struct nv50_head_atom *, int); + bool (*ilut_check)(int size); bool olut_identity; int olut_size; int (*olut_set)(struct nv50_head *, struct nv50_head_atom *); @@ -71,6 +72,7 @@ extern const struct nv50_head_func head907d; int head907d_view(struct nv50_head *, struct nv50_head_atom *); int head907d_mode(struct nv50_head *, struct nv50_head_atom *); bool head907d_olut(struct nv50_head *, struct nv50_head_atom *, int); +bool head907d_ilut_check(int size); int head907d_olut_set(struct nv50_head *, struct nv50_head_atom *); int head907d_olut_clr(struct nv50_head *); int head907d_core_set(struct nv50_head *, struct nv50_head_atom *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head907d.c b/drivers/gpu/drm/nouveau/dispnv50/head907d.c index 85648d790743..18fe4c1e2d6a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head907d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head907d.c @@ -314,6 +314,11 @@ head907d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) return true; } +bool head907d_ilut_check(int size) +{ + return size == 256 || size == 1024; +} + int head907d_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { @@ -409,6 +414,7 @@ head907d = { .view = head907d_view, .mode = head907d_mode, .olut = head907d_olut, + .ilut_check = head907d_ilut_check, .olut_size = 1024, .olut_set = head907d_olut_set, .olut_clr = head907d_olut_clr, diff --git a/drivers/gpu/drm/nouveau/dispnv50/head917d.c b/drivers/gpu/drm/nouveau/dispnv50/head917d.c index ea9f8667305e..4ce47b55f72c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head917d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head917d.c @@ -119,6 +119,7 @@ head917d = { .view = head907d_view, .mode = head907d_mode, .olut = head907d_olut, + .ilut_check = head907d_ilut_check, .olut_size = 1024, .olut_set = head907d_olut_set, .olut_clr = head907d_olut_clr, diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c index 63adfeba50e5..a4a3b78ea42c 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc37d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc37d.c @@ -285,6 +285,7 @@ headc37d = { .view = headc37d_view, .mode = headc37d_mode, .olut = headc37d_olut, + .ilut_check = head907d_ilut_check, .olut_size = 1024, .olut_set = headc37d_olut_set, .olut_clr = headc37d_olut_clr, diff --git a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c index fd51527b56b8..543f08ceaad6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/headc57d.c +++ b/drivers/gpu/drm/nouveau/dispnv50/headc57d.c @@ -169,7 +169,7 @@ headc57d_olut_load(struct drm_color_lut *in, int size, void __iomem *mem) writew(readw(mem - 4), mem + 4); } -bool +static bool headc57d_olut(struct nv50_head *head, struct nv50_head_atom *asyh, int size) { if (size != 0 && size != 256 && size != 1024) @@ -236,6 +236,7 @@ headc57d = { .view = headc37d_view, .mode = headc57d_mode, .olut = headc57d_olut, + .ilut_check = head907d_ilut_check, .olut_identity = true, .olut_size = 1024, .olut_set = headc57d_olut_set, diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index 8d048bacd6f0..133c8736426a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -403,10 +403,7 @@ nv50_wndw_atomic_check_lut(struct nv50_wndw *wndw, /* Recalculate LUT state. */ memset(&asyw->xlut, 0x00, sizeof(asyw->xlut)); if ((asyw->ilut = wndw->func->ilut ? ilut : NULL)) { - if (!wndw->func->ilut(wndw, asyw, drm_color_lut_size(ilut))) { - DRM_DEBUG_KMS("Invalid ilut\n"); - return -EINVAL; - } + wndw->func->ilut(wndw, asyw, drm_color_lut_size(ilut)); asyw->xlut.handle = wndw->wndw.vram.handle; asyw->xlut.i.buffer = !asyw->xlut.i.buffer; asyw->set.xlut = true; @@ -539,6 +536,8 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) struct nouveau_bo *nvbo; struct nv50_head_atom *asyh; struct nv50_wndw_ctxdma *ctxdma; + struct dma_resv_iter cursor; + struct dma_fence *fence; int ret; NV_ATOMIC(drm, "%s prepare: %p\n", plane->name, fb); @@ -561,7 +560,13 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) asyw->image.handle[0] = ctxdma->object.handle; } - asyw->state.fence = dma_resv_get_excl_unlocked(nvbo->bo.base.resv); + dma_resv_iter_begin(&cursor, nvbo->bo.base.resv, false); + dma_resv_for_each_fence_unlocked(&cursor, fence) { + /* TODO: We only use the first writer here */ + asyw->state.fence = dma_fence_get(fence); + break; + } + dma_resv_iter_end(&cursor); asyw->image.offset[0] = nvbo->offset; if (wndw->func->prepare) { diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h index f4e0c5080034..9c9f2c2a71a5 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h @@ -64,7 +64,7 @@ struct nv50_wndw_func { int (*ntfy_clr)(struct nv50_wndw *); int (*ntfy_wait_begun)(struct nouveau_bo *, u32 offset, struct nvif_device *); - bool (*ilut)(struct nv50_wndw *, struct nv50_wndw_atom *, int); + void (*ilut)(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyh, int size); void (*csc)(struct nv50_wndw *, struct nv50_wndw_atom *, const struct drm_color_ctm *); int (*csc_set)(struct nv50_wndw *, struct nv50_wndw_atom *); @@ -129,7 +129,7 @@ int wndwc37e_update(struct nv50_wndw *, u32 *); int wndwc57e_new(struct nouveau_drm *, enum drm_plane_type, int, s32, struct nv50_wndw **); -bool wndwc57e_ilut(struct nv50_wndw *, struct nv50_wndw_atom *, int); +void wndwc57e_ilut(struct nv50_wndw *, struct nv50_wndw_atom *, int); int wndwc57e_ilut_set(struct nv50_wndw *, struct nv50_wndw_atom *); int wndwc57e_ilut_clr(struct nv50_wndw *); int wndwc57e_csc_set(struct nv50_wndw *, struct nv50_wndw_atom *); diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c index 57df997c5ff3..183d2c0e65b6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c @@ -82,18 +82,14 @@ wndwc37e_ilut_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw) return 0; } -static bool +static void wndwc37e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) { - if (size != 256 && size != 1024) - return false; - asyw->xlut.i.size = size == 1024 ? NVC37E_SET_CONTROL_INPUT_LUT_SIZE_SIZE_1025 : NVC37E_SET_CONTROL_INPUT_LUT_SIZE_SIZE_257; asyw->xlut.i.range = NVC37E_SET_CONTROL_INPUT_LUT_RANGE_UNITY; asyw->xlut.i.output_mode = NVC37E_SET_CONTROL_INPUT_LUT_OUTPUT_MODE_INTERPOLATE; asyw->xlut.i.load = head907d_olut_load; - return true; } int diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c index abdd3bb658b3..37f6da8b3f2a 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c @@ -179,11 +179,11 @@ wndwc57e_ilut_load(struct drm_color_lut *in, int size, void __iomem *mem) writew(readw(mem - 4), mem + 4); } -bool +void wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) { - if (size = size ? size : 1024, size != 256 && size != 1024) - return false; + if (!size) + size = 1024; if (size == 256) asyw->xlut.i.mode = NVC57E_SET_ILUT_CONTROL_MODE_DIRECT8; @@ -193,7 +193,6 @@ wndwc57e_ilut(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw, int size) asyw->xlut.i.size = 4 /* VSS header. */ + size + 1 /* Entries. */; asyw->xlut.i.output_mode = NVC57E_SET_ILUT_CONTROL_INTERPOLATE_DISABLE; asyw->xlut.i.load = wndwc57e_ilut_load; - return true; } /**************************************************************** |