Lines Matching +full:t +full:- +full:head
1 // SPDX-License-Identifier: MIT
16 #include "head.h"
25 [NV50_CRC_SOURCE_OUTP_ACTIVE] = "outp-active",
26 [NV50_CRC_SOURCE_OUTP_COMPLETE] = "outp-complete",
27 [NV50_CRC_SOURCE_OUTP_INACTIVE] = "outp-inactive",
51 struct nouveau_drm *drm = nouveau_drm(crtc->dev); in nv50_crc_verify_source()
56 return -EINVAL; in nv50_crc_verify_source()
70 nv50_crc_program_ctx(struct nv50_head *head, in nv50_crc_program_ctx() argument
73 struct nv50_disp *disp = nv50_disp(head->base.base.dev); in nv50_crc_program_ctx()
74 struct nv50_core *core = disp->core; in nv50_crc_program_ctx()
77 core->func->crc->set_ctx(head, ctx); in nv50_crc_program_ctx()
78 core->func->update(core, interlock, false); in nv50_crc_program_ctx()
85 struct nv50_head *head = container_of(crc, struct nv50_head, crc); in nv50_crc_ctx_flip_work() local
86 struct drm_crtc *crtc = &head->base.base; in nv50_crc_ctx_flip_work()
87 struct drm_device *dev = crtc->dev; in nv50_crc_ctx_flip_work()
91 u8 new_idx = crc->ctx_idx ^ 1; in nv50_crc_ctx_flip_work()
94 * We don't want to accidentally wait for longer then the vblank, so in nv50_crc_ctx_flip_work()
95 * try again for the next vblank if we don't grab the lock in nv50_crc_ctx_flip_work()
97 if (!mutex_trylock(&disp->mutex)) { in nv50_crc_ctx_flip_work()
98 drm_dbg_kms(dev, "Lock contended, delaying CRC ctx flip for %s\n", crtc->name); in nv50_crc_ctx_flip_work()
103 drm_dbg_kms(dev, "Flipping notifier ctx for %s (%d -> %d)\n", in nv50_crc_ctx_flip_work()
104 crtc->name, crc->ctx_idx, new_idx); in nv50_crc_ctx_flip_work()
106 nv50_crc_program_ctx(head, NULL); in nv50_crc_ctx_flip_work()
107 nv50_crc_program_ctx(head, &crc->ctx[new_idx]); in nv50_crc_ctx_flip_work()
108 mutex_unlock(&disp->mutex); in nv50_crc_ctx_flip_work()
114 crtc->name, end_vbl, start_vbl); in nv50_crc_ctx_flip_work()
116 spin_lock_irq(&crc->lock); in nv50_crc_ctx_flip_work()
117 crc->ctx_changed = true; in nv50_crc_ctx_flip_work()
118 spin_unlock_irq(&crc->lock); in nv50_crc_ctx_flip_work()
123 memset_io(ctx->mem.object.map.ptr, 0, ctx->mem.object.map.size); in nv50_crc_reset_ctx()
127 nv50_crc_get_entries(struct nv50_head *head, in nv50_crc_get_entries() argument
131 struct drm_crtc *crtc = &head->base.base; in nv50_crc_get_entries()
132 struct nv50_crc *crc = &head->crc; in nv50_crc_get_entries()
135 while (crc->entry_idx < func->num_entries) { in nv50_crc_get_entries()
139 * aren't written immediately. in nv50_crc_get_entries()
141 output_crc = func->get_entry(head, &crc->ctx[crc->ctx_idx], in nv50_crc_get_entries()
142 source, crc->entry_idx); in nv50_crc_get_entries()
146 drm_crtc_add_crc_entry(crtc, true, crc->frame, &output_crc); in nv50_crc_get_entries()
147 crc->frame++; in nv50_crc_get_entries()
148 crc->entry_idx++; in nv50_crc_get_entries()
152 void nv50_crc_handle_vblank(struct nv50_head *head) in nv50_crc_handle_vblank() argument
154 struct drm_crtc *crtc = &head->base.base; in nv50_crc_handle_vblank()
155 struct nv50_crc *crc = &head->crc; in nv50_crc_handle_vblank()
157 nv50_disp(head->base.base.dev)->core->func->crc; in nv50_crc_handle_vblank()
165 * We don't lose events if we aren't able to report CRCs until the in nv50_crc_handle_vblank()
166 * next vblank, so only report CRCs if the locks we need aren't in nv50_crc_handle_vblank()
169 if (!spin_trylock(&crc->lock)) in nv50_crc_handle_vblank()
172 if (!crc->src) in nv50_crc_handle_vblank()
175 ctx = &crc->ctx[crc->ctx_idx]; in nv50_crc_handle_vblank()
176 if (crc->ctx_changed && func->ctx_finished(head, ctx)) { in nv50_crc_handle_vblank()
177 nv50_crc_get_entries(head, func, crc->src); in nv50_crc_handle_vblank()
179 crc->ctx_idx ^= 1; in nv50_crc_handle_vblank()
180 crc->entry_idx = 0; in nv50_crc_handle_vblank()
181 crc->ctx_changed = false; in nv50_crc_handle_vblank()
193 * updates back-to-back without waiting, we'll just be in nv50_crc_handle_vblank()
196 drm_dbg_kms(head->base.base.dev, in nv50_crc_handle_vblank()
197 "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n", in nv50_crc_handle_vblank()
198 head->base.index, crc->frame); in nv50_crc_handle_vblank()
199 crc->frame++; in nv50_crc_handle_vblank()
205 nv50_crc_get_entries(head, func, crc->src); in nv50_crc_handle_vblank()
208 drm_vblank_work_schedule(&crc->flip_work, in nv50_crc_handle_vblank()
210 + crc->flip_threshold in nv50_crc_handle_vblank()
211 - crc->entry_idx, in nv50_crc_handle_vblank()
215 spin_unlock(&crc->lock); in nv50_crc_handle_vblank()
218 static void nv50_crc_wait_ctx_finished(struct nv50_head *head, in nv50_crc_wait_ctx_finished() argument
222 struct drm_device *dev = head->base.base.dev; in nv50_crc_wait_ctx_finished()
226 ret = nvif_msec(&drm->client.device, 50, in nv50_crc_wait_ctx_finished()
227 if (func->ctx_finished(head, ctx)) break;); in nv50_crc_wait_ctx_finished()
228 if (ret == -ETIMEDOUT) in nv50_crc_wait_ctx_finished()
230 "CRC notifier ctx for head %d not finished after 50ms\n", in nv50_crc_wait_ctx_finished()
231 head->base.index); in nv50_crc_wait_ctx_finished()
234 "CRC notifier ctx for head-%d finished after %lldns\n", in nv50_crc_wait_ctx_finished()
235 head->base.index, ret); in nv50_crc_wait_ctx_finished()
245 struct nv50_head *head = nv50_head(crtc); in nv50_crc_atomic_stop_reporting() local
247 struct nv50_crc *crc = &head->crc; in nv50_crc_atomic_stop_reporting()
249 if (!asyh->clr.crc) in nv50_crc_atomic_stop_reporting()
252 spin_lock_irq(&crc->lock); in nv50_crc_atomic_stop_reporting()
253 crc->src = NV50_CRC_SOURCE_NONE; in nv50_crc_atomic_stop_reporting()
254 spin_unlock_irq(&crc->lock); in nv50_crc_atomic_stop_reporting()
257 drm_vblank_work_cancel_sync(&crc->flip_work); in nv50_crc_atomic_stop_reporting()
259 NV_ATOMIC(nouveau_drm(crtc->dev), in nv50_crc_atomic_stop_reporting()
260 "CRC reporting on vblank for head-%d disabled\n", in nv50_crc_atomic_stop_reporting()
261 head->base.index); in nv50_crc_atomic_stop_reporting()
277 struct nv50_head *head = nv50_head(crtc); in nv50_crc_atomic_init_notifier_contexts() local
279 struct nv50_crc *crc = &head->crc; in nv50_crc_atomic_init_notifier_contexts()
282 if (!asyh->set.crc) in nv50_crc_atomic_init_notifier_contexts()
285 crc->entry_idx = 0; in nv50_crc_atomic_init_notifier_contexts()
286 crc->ctx_changed = false; in nv50_crc_atomic_init_notifier_contexts()
287 for (i = 0; i < ARRAY_SIZE(crc->ctx); i++) in nv50_crc_atomic_init_notifier_contexts()
288 nv50_crc_reset_ctx(&crc->ctx[i]); in nv50_crc_atomic_init_notifier_contexts()
295 nv50_disp(state->dev)->core->func->crc; in nv50_crc_atomic_release_notifier_contexts()
301 struct nv50_head *head = nv50_head(crtc); in nv50_crc_atomic_release_notifier_contexts() local
303 struct nv50_crc *crc = &head->crc; in nv50_crc_atomic_release_notifier_contexts()
304 struct nv50_crc_notifier_ctx *ctx = &crc->ctx[crc->ctx_idx]; in nv50_crc_atomic_release_notifier_contexts()
306 if (!asyh->clr.crc) in nv50_crc_atomic_release_notifier_contexts()
309 if (crc->ctx_changed) { in nv50_crc_atomic_release_notifier_contexts()
310 nv50_crc_wait_ctx_finished(head, func, ctx); in nv50_crc_atomic_release_notifier_contexts()
311 ctx = &crc->ctx[crc->ctx_idx ^ 1]; in nv50_crc_atomic_release_notifier_contexts()
313 nv50_crc_wait_ctx_finished(head, func, ctx); in nv50_crc_atomic_release_notifier_contexts()
324 struct nv50_head *head = nv50_head(crtc); in nv50_crc_atomic_start_reporting() local
326 struct nv50_crc *crc = &head->crc; in nv50_crc_atomic_start_reporting()
329 if (!asyh->set.crc) in nv50_crc_atomic_start_reporting()
334 spin_lock_irq(&crc->lock); in nv50_crc_atomic_start_reporting()
336 crc->frame = vbl_count; in nv50_crc_atomic_start_reporting()
337 crc->src = asyh->crc.src; in nv50_crc_atomic_start_reporting()
338 drm_vblank_work_schedule(&crc->flip_work, in nv50_crc_atomic_start_reporting()
339 vbl_count + crc->flip_threshold, in nv50_crc_atomic_start_reporting()
341 spin_unlock_irq(&crc->lock); in nv50_crc_atomic_start_reporting()
343 NV_ATOMIC(nouveau_drm(crtc->dev), in nv50_crc_atomic_start_reporting()
344 "CRC reporting on vblank for head-%d enabled\n", in nv50_crc_atomic_start_reporting()
345 head->base.index); in nv50_crc_atomic_start_reporting()
349 int nv50_crc_atomic_check_head(struct nv50_head *head, in nv50_crc_atomic_check_head() argument
353 struct nv50_atom *atom = nv50_atom(asyh->state.state); in nv50_crc_atomic_check_head()
354 bool changed = armh->crc.src != asyh->crc.src; in nv50_crc_atomic_check_head()
356 if (!armh->crc.src && !asyh->crc.src) { in nv50_crc_atomic_check_head()
357 asyh->set.crc = false; in nv50_crc_atomic_check_head()
358 asyh->clr.crc = false; in nv50_crc_atomic_check_head()
362 if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed) { in nv50_crc_atomic_check_head()
363 asyh->clr.crc = armh->crc.src && armh->state.active; in nv50_crc_atomic_check_head()
364 asyh->set.crc = asyh->crc.src && asyh->state.active; in nv50_crc_atomic_check_head()
366 asyh->set.or |= armh->or.crc_raster != in nv50_crc_atomic_check_head()
367 asyh->or.crc_raster; in nv50_crc_atomic_check_head()
369 if (asyh->clr.crc && asyh->set.crc) in nv50_crc_atomic_check_head()
370 atom->flush_disable = true; in nv50_crc_atomic_check_head()
372 asyh->set.crc = false; in nv50_crc_atomic_check_head()
373 asyh->clr.crc = false; in nv50_crc_atomic_check_head()
385 if (atom->flush_disable) in nv50_crc_atomic_check_outp()
388 for_each_oldnew_crtc_in_state(&atom->state, crtc, old_crtc_state, in nv50_crc_atomic_check_outp()
404 encoder = &outp->base.base; in nv50_crc_atomic_check_outp()
406 if (!asyh->clr.crc) in nv50_crc_atomic_check_outp()
410 * Re-programming ORs can't be done in the same flush as in nv50_crc_atomic_check_outp()
413 list_for_each_entry(outp_atom, &atom->outp, head) { in nv50_crc_atomic_check_outp()
414 if (outp_atom->encoder == encoder) { in nv50_crc_atomic_check_outp()
415 if (outp_atom->set.mask) { in nv50_crc_atomic_check_outp()
416 atom->flush_disable = true; in nv50_crc_atomic_check_outp()
430 struct dcb_output *dcbe = outp->dcb; in nv50_crc_source_type()
438 if (dcbe->location != DCB_LOC_ON_CHIP) in nv50_crc_source_type()
441 switch (dcbe->type) { in nv50_crc_source_type()
448 void nv50_crc_atomic_set(struct nv50_head *head, in nv50_crc_atomic_set() argument
451 struct drm_crtc *crtc = &head->base.base; in nv50_crc_atomic_set()
452 struct drm_device *dev = crtc->dev; in nv50_crc_atomic_set()
453 struct nv50_crc *crc = &head->crc; in nv50_crc_atomic_set()
454 const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc; in nv50_crc_atomic_set()
466 func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src), in nv50_crc_atomic_set()
467 &crc->ctx[crc->ctx_idx]); in nv50_crc_atomic_set()
470 void nv50_crc_atomic_clr(struct nv50_head *head) in nv50_crc_atomic_clr() argument
473 nv50_disp(head->base.base.dev)->core->func->crc; in nv50_crc_atomic_clr()
475 func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL); in nv50_crc_atomic_clr()
500 nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu *mmu, in nv50_crc_ctx_init() argument
503 struct nv50_core *core = nv50_disp(head->base.base.dev)->core; in nv50_crc_ctx_init()
506 ret = nvif_mem_ctor_map(mmu, "kmsCrcNtfy", NVIF_MEM_VRAM, len, &ctx->mem); in nv50_crc_ctx_init()
510 ret = nvif_object_ctor(&core->chan.base.user, "kmsCrcNtfyCtxDma", in nv50_crc_ctx_init()
511 NV50_DISP_HANDLE_CRC_CTX(head, idx), in nv50_crc_ctx_init()
516 .start = ctx->mem.addr, in nv50_crc_ctx_init()
517 .limit = ctx->mem.addr in nv50_crc_ctx_init()
518 + ctx->mem.size - 1, in nv50_crc_ctx_init()
520 &ctx->ntfy); in nv50_crc_ctx_init()
527 nvif_mem_dtor(&ctx->mem); in nv50_crc_ctx_init()
534 nvif_object_dtor(&ctx->ntfy); in nv50_crc_ctx_fini()
535 nvif_mem_dtor(&ctx->mem); in nv50_crc_ctx_fini()
540 struct drm_device *dev = crtc->dev; in nv50_crc_set_source()
543 struct nv50_head *head = nv50_head(crtc); in nv50_crc_set_source() local
544 struct nv50_crc *crc = &head->crc; in nv50_crc_set_source()
545 const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc; in nv50_crc_set_source()
546 struct nvif_mmu *mmu = &nouveau_drm(dev)->client.mmu; in nv50_crc_set_source()
557 * Since we don't want the user to accidentally interrupt us as we're in nv50_crc_set_source()
566 ret = -ENOMEM; in nv50_crc_set_source()
569 state->acquire_ctx = &ctx; in nv50_crc_set_source()
572 for (i = 0; i < ARRAY_SIZE(head->crc.ctx); i++) { in nv50_crc_set_source()
573 ret = nv50_crc_ctx_init(head, mmu, &crc->ctx[i], in nv50_crc_set_source()
574 func->notifier_len, i); in nv50_crc_set_source()
581 crtc_state = drm_atomic_get_crtc_state(state, &head->base.base); in nv50_crc_set_source()
584 if (ret == -EDEADLK) in nv50_crc_set_source()
590 asyh->crc.src = source; in nv50_crc_set_source()
591 asyh->or.crc_raster = nv50_crc_raster_type(source); in nv50_crc_set_source()
594 if (ret == -EDEADLK) in nv50_crc_set_source()
604 crc->flip_threshold = func->flip_threshold; in nv50_crc_set_source()
611 for (i = 0; i < ARRAY_SIZE(crc->ctx); i++) in nv50_crc_set_source()
612 nv50_crc_ctx_fini(&crc->ctx[i]); in nv50_crc_set_source()
628 struct nv50_head *head = m->private; in nv50_crc_debugfs_flip_threshold_get() local
629 struct drm_crtc *crtc = &head->base.base; in nv50_crc_debugfs_flip_threshold_get()
630 struct nv50_crc *crc = &head->crc; in nv50_crc_debugfs_flip_threshold_get()
633 ret = drm_modeset_lock_single_interruptible(&crtc->mutex); in nv50_crc_debugfs_flip_threshold_get()
637 seq_printf(m, "%d\n", crc->flip_threshold); in nv50_crc_debugfs_flip_threshold_get()
639 drm_modeset_unlock(&crtc->mutex); in nv50_crc_debugfs_flip_threshold_get()
647 inode->i_private); in nv50_crc_debugfs_flip_threshold_open()
655 struct seq_file *m = file->private_data; in nv50_crc_debugfs_flip_threshold_set()
656 struct nv50_head *head = m->private; in nv50_crc_debugfs_flip_threshold_set() local
658 struct drm_crtc *crtc = &head->base.base; in nv50_crc_debugfs_flip_threshold_set()
659 struct nouveau_drm *drm = nouveau_drm(crtc->dev); in nv50_crc_debugfs_flip_threshold_set()
660 struct nv50_crc *crc = &head->crc; in nv50_crc_debugfs_flip_threshold_set()
662 nv50_disp(crtc->dev)->core->func->crc; in nv50_crc_debugfs_flip_threshold_set()
669 if (value > func->flip_threshold) in nv50_crc_debugfs_flip_threshold_set()
670 return -EINVAL; in nv50_crc_debugfs_flip_threshold_set()
671 else if (value == -1) in nv50_crc_debugfs_flip_threshold_set()
672 value = func->flip_threshold; in nv50_crc_debugfs_flip_threshold_set()
673 else if (value < -1) in nv50_crc_debugfs_flip_threshold_set()
674 return -EINVAL; in nv50_crc_debugfs_flip_threshold_set()
676 ret = drm_modeset_lock_single_interruptible(&crtc->mutex); in nv50_crc_debugfs_flip_threshold_set()
680 armh = nv50_head_atom(crtc->state); in nv50_crc_debugfs_flip_threshold_set()
681 if (armh->crc.src) { in nv50_crc_debugfs_flip_threshold_set()
682 ret = -EBUSY; in nv50_crc_debugfs_flip_threshold_set()
687 "Changing CRC flip threshold for next capture on head-%d to %d\n", in nv50_crc_debugfs_flip_threshold_set()
688 head->base.index, value); in nv50_crc_debugfs_flip_threshold_set()
689 crc->flip_threshold = value; in nv50_crc_debugfs_flip_threshold_set()
693 drm_modeset_unlock(&crtc->mutex); in nv50_crc_debugfs_flip_threshold_set()
705 int nv50_head_crc_late_register(struct nv50_head *head) in nv50_head_crc_late_register() argument
707 struct drm_crtc *crtc = &head->base.base; in nv50_head_crc_late_register()
709 nv50_disp(crtc->dev)->core->func->crc; in nv50_head_crc_late_register()
712 if (!func || !crtc->debugfs_entry) in nv50_head_crc_late_register()
715 root = debugfs_create_dir("nv_crc", crtc->debugfs_entry); in nv50_head_crc_late_register()
716 debugfs_create_file("flip_threshold", 0644, root, head, in nv50_head_crc_late_register()
724 struct nv50_head *head) in nv50_crc_init_head() argument
726 struct nv50_crc *crc = &head->crc; in nv50_crc_init_head()
728 crc->flip_threshold = func->flip_threshold; in nv50_crc_init_head()
729 spin_lock_init(&crc->lock); in nv50_crc_init_head()
730 drm_vblank_work_init(&crc->flip_work, &head->base.base, in nv50_crc_init_head()
738 const struct nv50_crc_func *func = disp->core->func->crc; in nv50_crc_init()