brintos

brintos / linux-shallow public Read only

0
0
Text · 18.6 KiB · 5936b6b Raw
748 lines · c
1// SPDX-License-Identifier: MIT2#include <linux/debugfs.h>3#include <linux/string.h>4 5#include <drm/drm_crtc.h>6#include <drm/drm_atomic_helper.h>7#include <drm/drm_vblank.h>8#include <drm/drm_vblank_work.h>9 10#include <nvif/class.h>11#include <nvif/cl0002.h>12#include <nvif/timer.h>13 14#include <nvhw/class/cl907d.h>15 16#include "nouveau_drv.h"17#include "core.h"18#include "head.h"19#include "wndw.h"20#include "handles.h"21#include "crc.h"22 23static const char * const nv50_crc_sources[] = {24	[NV50_CRC_SOURCE_NONE] = "none",25	[NV50_CRC_SOURCE_AUTO] = "auto",26	[NV50_CRC_SOURCE_RG] = "rg",27	[NV50_CRC_SOURCE_OUTP_ACTIVE] = "outp-active",28	[NV50_CRC_SOURCE_OUTP_COMPLETE] = "outp-complete",29	[NV50_CRC_SOURCE_OUTP_INACTIVE] = "outp-inactive",30};31 32static int nv50_crc_parse_source(const char *buf, enum nv50_crc_source *s)33{34	int i;35 36	if (!buf) {37		*s = NV50_CRC_SOURCE_NONE;38		return 0;39	}40 41	i = match_string(nv50_crc_sources, ARRAY_SIZE(nv50_crc_sources), buf);42	if (i < 0)43		return i;44 45	*s = i;46	return 0;47}48 49int50nv50_crc_verify_source(struct drm_crtc *crtc, const char *source_name,51		       size_t *values_cnt)52{53	struct nouveau_drm *drm = nouveau_drm(crtc->dev);54	enum nv50_crc_source source;55 56	if (nv50_crc_parse_source(source_name, &source) < 0) {57		NV_DEBUG(drm, "unknown source %s\n", source_name);58		return -EINVAL;59	}60 61	*values_cnt = 1;62	return 0;63}64 65const char *const *nv50_crc_get_sources(struct drm_crtc *crtc, size_t *count)66{67	*count = ARRAY_SIZE(nv50_crc_sources);68	return nv50_crc_sources;69}70 71static void72nv50_crc_program_ctx(struct nv50_head *head,73		     struct nv50_crc_notifier_ctx *ctx)74{75	struct nv50_disp *disp = nv50_disp(head->base.base.dev);76	struct nv50_core *core = disp->core;77	u32 interlock[NV50_DISP_INTERLOCK__SIZE] = { 0 };78 79	core->func->crc->set_ctx(head, ctx);80	core->func->update(core, interlock, false);81}82 83static void nv50_crc_ctx_flip_work(struct kthread_work *base)84{85	struct drm_vblank_work *work = to_drm_vblank_work(base);86	struct nv50_crc *crc = container_of(work, struct nv50_crc, flip_work);87	struct nv50_head *head = container_of(crc, struct nv50_head, crc);88	struct drm_crtc *crtc = &head->base.base;89	struct drm_device *dev = crtc->dev;90	struct nv50_disp *disp = nv50_disp(dev);91	const uint64_t start_vbl = drm_crtc_vblank_count(crtc);92	uint64_t end_vbl;93	u8 new_idx = crc->ctx_idx ^ 1;94 95	/*96	 * We don't want to accidentally wait for longer then the vblank, so97	 * try again for the next vblank if we don't grab the lock98	 */99	if (!mutex_trylock(&disp->mutex)) {100		drm_dbg_kms(dev, "Lock contended, delaying CRC ctx flip for %s\n", crtc->name);101		drm_vblank_work_schedule(work, start_vbl + 1, true);102		return;103	}104 105	drm_dbg_kms(dev, "Flipping notifier ctx for %s (%d -> %d)\n",106		    crtc->name, crc->ctx_idx, new_idx);107 108	nv50_crc_program_ctx(head, NULL);109	nv50_crc_program_ctx(head, &crc->ctx[new_idx]);110	mutex_unlock(&disp->mutex);111 112	end_vbl = drm_crtc_vblank_count(crtc);113	if (unlikely(end_vbl != start_vbl))114		NV_ERROR(nouveau_drm(dev),115			 "Failed to flip CRC context on %s on time (%llu > %llu)\n",116			 crtc->name, end_vbl, start_vbl);117 118	spin_lock_irq(&crc->lock);119	crc->ctx_changed = true;120	spin_unlock_irq(&crc->lock);121}122 123static inline void nv50_crc_reset_ctx(struct nv50_crc_notifier_ctx *ctx)124{125	memset_io(ctx->mem.object.map.ptr, 0, ctx->mem.object.map.size);126}127 128static void129nv50_crc_get_entries(struct nv50_head *head,130		     const struct nv50_crc_func *func,131		     enum nv50_crc_source source)132{133	struct drm_crtc *crtc = &head->base.base;134	struct nv50_crc *crc = &head->crc;135	u32 output_crc;136 137	while (crc->entry_idx < func->num_entries) {138		/*139		 * While Nvidia's documentation says CRCs are written on each140		 * subsequent vblank after being enabled, in practice they141		 * aren't written immediately.142		 */143		output_crc = func->get_entry(head, &crc->ctx[crc->ctx_idx],144					     source, crc->entry_idx);145		if (!output_crc)146			return;147 148		drm_crtc_add_crc_entry(crtc, true, crc->frame, &output_crc);149		crc->frame++;150		crc->entry_idx++;151	}152}153 154void nv50_crc_handle_vblank(struct nv50_head *head)155{156	struct drm_crtc *crtc = &head->base.base;157	struct nv50_crc *crc = &head->crc;158	const struct nv50_crc_func *func =159		nv50_disp(head->base.base.dev)->core->func->crc;160	struct nv50_crc_notifier_ctx *ctx;161	bool need_reschedule = false;162 163	if (!func)164		return;165 166	/*167	 * We don't lose events if we aren't able to report CRCs until the168	 * next vblank, so only report CRCs if the locks we need aren't169	 * contended to prevent missing an actual vblank event170	 */171	if (!spin_trylock(&crc->lock))172		return;173 174	if (!crc->src)175		goto out;176 177	ctx = &crc->ctx[crc->ctx_idx];178	if (crc->ctx_changed && func->ctx_finished(head, ctx)) {179		nv50_crc_get_entries(head, func, crc->src);180 181		crc->ctx_idx ^= 1;182		crc->entry_idx = 0;183		crc->ctx_changed = false;184 185		/*186		 * Unfortunately when notifier contexts are changed during CRC187		 * capture, we will inevitably lose the CRC entry for the188		 * frame where the hardware actually latched onto the first189		 * UPDATE. According to Nvidia's hardware engineers, there's190		 * no workaround for this.191		 *192		 * Now, we could try to be smart here and calculate the number193		 * of missed CRCs based on audit timestamps, but those were194		 * removed starting with volta. Since we always flush our195		 * updates back-to-back without waiting, we'll just be196		 * optimistic and assume we always miss exactly one frame.197		 */198		drm_dbg_kms(head->base.base.dev,199			    "Notifier ctx flip for head-%d finished, lost CRC for frame %llu\n",200			    head->base.index, crc->frame);201		crc->frame++;202 203		nv50_crc_reset_ctx(ctx);204		need_reschedule = true;205	}206 207	nv50_crc_get_entries(head, func, crc->src);208 209	if (need_reschedule)210		drm_vblank_work_schedule(&crc->flip_work,211					 drm_crtc_vblank_count(crtc)212					 + crc->flip_threshold213					 - crc->entry_idx,214					 true);215 216out:217	spin_unlock(&crc->lock);218}219 220static void nv50_crc_wait_ctx_finished(struct nv50_head *head,221				       const struct nv50_crc_func *func,222				       struct nv50_crc_notifier_ctx *ctx)223{224	struct drm_device *dev = head->base.base.dev;225	struct nouveau_drm *drm = nouveau_drm(dev);226	s64 ret;227 228	ret = nvif_msec(&drm->client.device, 50,229			if (func->ctx_finished(head, ctx)) break;);230	if (ret == -ETIMEDOUT)231		NV_ERROR(drm,232			 "CRC notifier ctx for head %d not finished after 50ms\n",233			 head->base.index);234	else if (ret)235		NV_ATOMIC(drm,236			  "CRC notifier ctx for head-%d finished after %lldns\n",237			  head->base.index, ret);238}239 240void nv50_crc_atomic_stop_reporting(struct drm_atomic_state *state)241{242	struct drm_crtc_state *crtc_state;243	struct drm_crtc *crtc;244	int i;245 246	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {247		struct nv50_head *head = nv50_head(crtc);248		struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);249		struct nv50_crc *crc = &head->crc;250 251		if (!asyh->clr.crc)252			continue;253 254		spin_lock_irq(&crc->lock);255		crc->src = NV50_CRC_SOURCE_NONE;256		spin_unlock_irq(&crc->lock);257 258		drm_crtc_vblank_put(crtc);259		drm_vblank_work_cancel_sync(&crc->flip_work);260 261		NV_ATOMIC(nouveau_drm(crtc->dev),262			  "CRC reporting on vblank for head-%d disabled\n",263			  head->base.index);264 265		/* CRC generation is still enabled in hw, we'll just report266		 * any remaining CRC entries ourselves after it gets disabled267		 * in hardware268		 */269	}270}271 272void nv50_crc_atomic_init_notifier_contexts(struct drm_atomic_state *state)273{274	struct drm_crtc_state *new_crtc_state;275	struct drm_crtc *crtc;276	int i;277 278	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {279		struct nv50_head *head = nv50_head(crtc);280		struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);281		struct nv50_crc *crc = &head->crc;282		int i;283 284		if (!asyh->set.crc)285			continue;286 287		crc->entry_idx = 0;288		crc->ctx_changed = false;289		for (i = 0; i < ARRAY_SIZE(crc->ctx); i++)290			nv50_crc_reset_ctx(&crc->ctx[i]);291	}292}293 294void nv50_crc_atomic_release_notifier_contexts(struct drm_atomic_state *state)295{296	const struct nv50_crc_func *func =297		nv50_disp(state->dev)->core->func->crc;298	struct drm_crtc_state *new_crtc_state;299	struct drm_crtc *crtc;300	int i;301 302	for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {303		struct nv50_head *head = nv50_head(crtc);304		struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);305		struct nv50_crc *crc = &head->crc;306		struct nv50_crc_notifier_ctx *ctx = &crc->ctx[crc->ctx_idx];307 308		if (!asyh->clr.crc)309			continue;310 311		if (crc->ctx_changed) {312			nv50_crc_wait_ctx_finished(head, func, ctx);313			ctx = &crc->ctx[crc->ctx_idx ^ 1];314		}315		nv50_crc_wait_ctx_finished(head, func, ctx);316	}317}318 319void nv50_crc_atomic_start_reporting(struct drm_atomic_state *state)320{321	struct drm_crtc_state *crtc_state;322	struct drm_crtc *crtc;323	int i;324 325	for_each_new_crtc_in_state(state, crtc, crtc_state, i) {326		struct nv50_head *head = nv50_head(crtc);327		struct nv50_head_atom *asyh = nv50_head_atom(crtc_state);328		struct nv50_crc *crc = &head->crc;329		u64 vbl_count;330 331		if (!asyh->set.crc)332			continue;333 334		drm_crtc_vblank_get(crtc);335 336		spin_lock_irq(&crc->lock);337		vbl_count = drm_crtc_vblank_count(crtc);338		crc->frame = vbl_count;339		crc->src = asyh->crc.src;340		drm_vblank_work_schedule(&crc->flip_work,341					 vbl_count + crc->flip_threshold,342					 true);343		spin_unlock_irq(&crc->lock);344 345		NV_ATOMIC(nouveau_drm(crtc->dev),346			  "CRC reporting on vblank for head-%d enabled\n",347			  head->base.index);348	}349}350 351int nv50_crc_atomic_check_head(struct nv50_head *head,352			       struct nv50_head_atom *asyh,353			       struct nv50_head_atom *armh)354{355	struct nv50_atom *atom = nv50_atom(asyh->state.state);356	bool changed = armh->crc.src != asyh->crc.src;357 358	if (!armh->crc.src && !asyh->crc.src) {359		asyh->set.crc = false;360		asyh->clr.crc = false;361		return 0;362	}363 364	if (drm_atomic_crtc_needs_modeset(&asyh->state) || changed) {365		asyh->clr.crc = armh->crc.src && armh->state.active;366		asyh->set.crc = asyh->crc.src && asyh->state.active;367		if (changed)368			asyh->set.or |= armh->or.crc_raster !=369					asyh->or.crc_raster;370 371		if (asyh->clr.crc && asyh->set.crc)372			atom->flush_disable = true;373	} else {374		asyh->set.crc = false;375		asyh->clr.crc = false;376	}377 378	return 0;379}380 381void nv50_crc_atomic_check_outp(struct nv50_atom *atom)382{383	struct drm_crtc *crtc;384	struct drm_crtc_state *old_crtc_state, *new_crtc_state;385	int i;386 387	if (atom->flush_disable)388		return;389 390	for_each_oldnew_crtc_in_state(&atom->state, crtc, old_crtc_state,391				      new_crtc_state, i) {392		struct nv50_head_atom *armh = nv50_head_atom(old_crtc_state);393		struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state);394		struct nv50_outp_atom *outp_atom;395		struct nouveau_encoder *outp;396		struct drm_encoder *encoder, *enc;397 398		enc = nv50_head_atom_get_encoder(armh);399		if (!enc)400			continue;401 402		outp = nv50_real_outp(enc);403		if (!outp)404			continue;405 406		encoder = &outp->base.base;407 408		if (!asyh->clr.crc)409			continue;410 411		/*412		 * Re-programming ORs can't be done in the same flush as413		 * disabling CRCs414		 */415		list_for_each_entry(outp_atom, &atom->outp, head) {416			if (outp_atom->encoder == encoder) {417				if (outp_atom->set.mask) {418					atom->flush_disable = true;419					return;420				} else {421					break;422				}423			}424		}425	}426}427 428static enum nv50_crc_source_type429nv50_crc_source_type(struct nouveau_encoder *outp,430		     enum nv50_crc_source source)431{432	struct dcb_output *dcbe = outp->dcb;433 434	switch (source) {435	case NV50_CRC_SOURCE_NONE: return NV50_CRC_SOURCE_TYPE_NONE;436	case NV50_CRC_SOURCE_RG:   return NV50_CRC_SOURCE_TYPE_RG;437	default:		   break;438	}439 440	if (dcbe->location != DCB_LOC_ON_CHIP)441		return NV50_CRC_SOURCE_TYPE_PIOR;442 443	switch (dcbe->type) {444	case DCB_OUTPUT_DP:	return NV50_CRC_SOURCE_TYPE_SF;445	case DCB_OUTPUT_ANALOG:	return NV50_CRC_SOURCE_TYPE_DAC;446	default:		return NV50_CRC_SOURCE_TYPE_SOR;447	}448}449 450void nv50_crc_atomic_set(struct nv50_head *head,451			 struct nv50_head_atom *asyh)452{453	struct drm_crtc *crtc = &head->base.base;454	struct drm_device *dev = crtc->dev;455	struct nv50_crc *crc = &head->crc;456	const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc;457	struct nouveau_encoder *outp;458	struct drm_encoder *encoder;459 460	encoder = nv50_head_atom_get_encoder(asyh);461	if (!encoder)462		return;463 464	outp = nv50_real_outp(encoder);465	if (!outp)466		return;467 468	func->set_src(head, outp->outp.or.id, nv50_crc_source_type(outp, asyh->crc.src),469		      &crc->ctx[crc->ctx_idx]);470}471 472void nv50_crc_atomic_clr(struct nv50_head *head)473{474	const struct nv50_crc_func *func =475		nv50_disp(head->base.base.dev)->core->func->crc;476 477	func->set_src(head, 0, NV50_CRC_SOURCE_TYPE_NONE, NULL);478}479 480static inline int481nv50_crc_raster_type(enum nv50_crc_source source)482{483	switch (source) {484	case NV50_CRC_SOURCE_NONE:485	case NV50_CRC_SOURCE_AUTO:486	case NV50_CRC_SOURCE_RG:487	case NV50_CRC_SOURCE_OUTP_ACTIVE:488		return NV907D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_CRC_MODE_ACTIVE_RASTER;489	case NV50_CRC_SOURCE_OUTP_COMPLETE:490		return NV907D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_CRC_MODE_COMPLETE_RASTER;491	case NV50_CRC_SOURCE_OUTP_INACTIVE:492		return NV907D_HEAD_SET_CONTROL_OUTPUT_RESOURCE_CRC_MODE_NON_ACTIVE_RASTER;493	}494 495	return 0;496}497 498/* We handle mapping the memory for CRC notifiers ourselves, since each499 * notifier needs it's own handle500 */501static inline int502nv50_crc_ctx_init(struct nv50_head *head, struct nvif_mmu *mmu,503		  struct nv50_crc_notifier_ctx *ctx, size_t len, int idx)504{505	struct nv50_core *core = nv50_disp(head->base.base.dev)->core;506	int ret;507 508	ret = nvif_mem_ctor_map(mmu, "kmsCrcNtfy", NVIF_MEM_VRAM, len, &ctx->mem);509	if (ret)510		return ret;511 512	ret = nvif_object_ctor(&core->chan.base.user, "kmsCrcNtfyCtxDma",513			       NV50_DISP_HANDLE_CRC_CTX(head, idx),514			       NV_DMA_IN_MEMORY,515			       &(struct nv_dma_v0) {516					.target = NV_DMA_V0_TARGET_VRAM,517					.access = NV_DMA_V0_ACCESS_RDWR,518					.start = ctx->mem.addr,519					.limit =  ctx->mem.addr520						+ ctx->mem.size - 1,521			       }, sizeof(struct nv_dma_v0),522			       &ctx->ntfy);523	if (ret)524		goto fail_fini;525 526	return 0;527 528fail_fini:529	nvif_mem_dtor(&ctx->mem);530	return ret;531}532 533static inline void534nv50_crc_ctx_fini(struct nv50_crc_notifier_ctx *ctx)535{536	nvif_object_dtor(&ctx->ntfy);537	nvif_mem_dtor(&ctx->mem);538}539 540int nv50_crc_set_source(struct drm_crtc *crtc, const char *source_str)541{542	struct drm_device *dev = crtc->dev;543	struct drm_atomic_state *state;544	struct drm_modeset_acquire_ctx ctx;545	struct nv50_head *head = nv50_head(crtc);546	struct nv50_crc *crc = &head->crc;547	const struct nv50_crc_func *func = nv50_disp(dev)->core->func->crc;548	struct nvif_mmu *mmu = &nouveau_drm(dev)->client.mmu;549	struct nv50_head_atom *asyh;550	struct drm_crtc_state *crtc_state;551	enum nv50_crc_source source;552	int ret = 0, ctx_flags = 0, i;553 554	ret = nv50_crc_parse_source(source_str, &source);555	if (ret)556		return ret;557 558	/*559	 * Since we don't want the user to accidentally interrupt us as we're560	 * disabling CRCs561	 */562	if (source)563		ctx_flags |= DRM_MODESET_ACQUIRE_INTERRUPTIBLE;564	drm_modeset_acquire_init(&ctx, ctx_flags);565 566	state = drm_atomic_state_alloc(dev);567	if (!state) {568		ret = -ENOMEM;569		goto out_acquire_fini;570	}571	state->acquire_ctx = &ctx;572 573	if (source) {574		for (i = 0; i < ARRAY_SIZE(head->crc.ctx); i++) {575			ret = nv50_crc_ctx_init(head, mmu, &crc->ctx[i],576						func->notifier_len, i);577			if (ret)578				goto out_ctx_fini;579		}580	}581 582retry:583	crtc_state = drm_atomic_get_crtc_state(state, &head->base.base);584	if (IS_ERR(crtc_state)) {585		ret = PTR_ERR(crtc_state);586		if (ret == -EDEADLK)587			goto deadlock;588		else if (ret)589			goto out_drop_locks;590	}591	asyh = nv50_head_atom(crtc_state);592	asyh->crc.src = source;593	asyh->or.crc_raster = nv50_crc_raster_type(source);594 595	ret = drm_atomic_commit(state);596	if (ret == -EDEADLK)597		goto deadlock;598	else if (ret)599		goto out_drop_locks;600 601	if (!source) {602		/*603		 * If the user specified a custom flip threshold through604		 * debugfs, reset it605		 */606		crc->flip_threshold = func->flip_threshold;607	}608 609out_drop_locks:610	drm_modeset_drop_locks(&ctx);611out_ctx_fini:612	if (!source || ret) {613		for (i = 0; i < ARRAY_SIZE(crc->ctx); i++)614			nv50_crc_ctx_fini(&crc->ctx[i]);615	}616	drm_atomic_state_put(state);617out_acquire_fini:618	drm_modeset_acquire_fini(&ctx);619	return ret;620 621deadlock:622	drm_atomic_state_clear(state);623	drm_modeset_backoff(&ctx);624	goto retry;625}626 627static int628nv50_crc_debugfs_flip_threshold_get(struct seq_file *m, void *data)629{630	struct nv50_head *head = m->private;631	struct drm_crtc *crtc = &head->base.base;632	struct nv50_crc *crc = &head->crc;633	int ret;634 635	ret = drm_modeset_lock_single_interruptible(&crtc->mutex);636	if (ret)637		return ret;638 639	seq_printf(m, "%d\n", crc->flip_threshold);640 641	drm_modeset_unlock(&crtc->mutex);642	return ret;643}644 645static int646nv50_crc_debugfs_flip_threshold_open(struct inode *inode, struct file *file)647{648	return single_open(file, nv50_crc_debugfs_flip_threshold_get,649			   inode->i_private);650}651 652static ssize_t653nv50_crc_debugfs_flip_threshold_set(struct file *file,654				    const char __user *ubuf, size_t len,655				    loff_t *offp)656{657	struct seq_file *m = file->private_data;658	struct nv50_head *head = m->private;659	struct nv50_head_atom *armh;660	struct drm_crtc *crtc = &head->base.base;661	struct nouveau_drm *drm = nouveau_drm(crtc->dev);662	struct nv50_crc *crc = &head->crc;663	const struct nv50_crc_func *func =664		nv50_disp(crtc->dev)->core->func->crc;665	int value, ret;666 667	ret = kstrtoint_from_user(ubuf, len, 10, &value);668	if (ret)669		return ret;670 671	if (value > func->flip_threshold)672		return -EINVAL;673	else if (value == -1)674		value = func->flip_threshold;675	else if (value < -1)676		return -EINVAL;677 678	ret = drm_modeset_lock_single_interruptible(&crtc->mutex);679	if (ret)680		return ret;681 682	armh = nv50_head_atom(crtc->state);683	if (armh->crc.src) {684		ret = -EBUSY;685		goto out;686	}687 688	NV_DEBUG(drm,689		 "Changing CRC flip threshold for next capture on head-%d to %d\n",690		 head->base.index, value);691	crc->flip_threshold = value;692	ret = len;693 694out:695	drm_modeset_unlock(&crtc->mutex);696	return ret;697}698 699static const struct file_operations nv50_crc_flip_threshold_fops = {700	.owner = THIS_MODULE,701	.open = nv50_crc_debugfs_flip_threshold_open,702	.read = seq_read,703	.write = nv50_crc_debugfs_flip_threshold_set,704	.release = single_release,705};706 707int nv50_head_crc_late_register(struct nv50_head *head)708{709	struct drm_crtc *crtc = &head->base.base;710	const struct nv50_crc_func *func =711		nv50_disp(crtc->dev)->core->func->crc;712	struct dentry *root;713 714	if (!func || !crtc->debugfs_entry)715		return 0;716 717	root = debugfs_create_dir("nv_crc", crtc->debugfs_entry);718	debugfs_create_file("flip_threshold", 0644, root, head,719			    &nv50_crc_flip_threshold_fops);720 721	return 0;722}723 724static inline void725nv50_crc_init_head(struct nv50_disp *disp, const struct nv50_crc_func *func,726		   struct nv50_head *head)727{728	struct nv50_crc *crc = &head->crc;729 730	crc->flip_threshold = func->flip_threshold;731	spin_lock_init(&crc->lock);732	drm_vblank_work_init(&crc->flip_work, &head->base.base,733			     nv50_crc_ctx_flip_work);734}735 736void nv50_crc_init(struct drm_device *dev)737{738	struct nv50_disp *disp = nv50_disp(dev);739	struct drm_crtc *crtc;740	const struct nv50_crc_func *func = disp->core->func->crc;741 742	if (!func)743		return;744 745	drm_for_each_crtc(crtc, dev)746		nv50_crc_init_head(disp, func, nv50_head(crtc));747}748