1 /*
2  * drivers/gpu/drm/omapdrm/omap_crtc.c
3  *
4  * Copyright (C) 2011 Texas Instruments
5  * Author: Rob Clark <rob@ti.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "omap_drv.h"
21 
22 #include <drm/drm_mode.h>
23 #include "drm_crtc.h"
24 #include "drm_crtc_helper.h"
25 
26 #define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
27 
28 struct omap_crtc {
29 	struct drm_crtc base;
30 	struct drm_plane *plane;
31 
32 	const char *name;
33 	int pipe;
34 	enum omap_channel channel;
35 	struct omap_overlay_manager_info info;
36 
37 	/*
38 	 * Temporary: eventually this will go away, but it is needed
39 	 * for now to keep the output's happy.  (They only need
40 	 * mgr->id.)  Eventually this will be replaced w/ something
41 	 * more common-panel-framework-y
42 	 */
43 	struct omap_overlay_manager *mgr;
44 
45 	struct omap_video_timings timings;
46 	bool enabled;
47 	bool full_update;
48 
49 	struct omap_drm_apply apply;
50 
51 	struct omap_drm_irq apply_irq;
52 	struct omap_drm_irq error_irq;
53 
54 	/* list of in-progress apply's: */
55 	struct list_head pending_applies;
56 
57 	/* list of queued apply's: */
58 	struct list_head queued_applies;
59 
60 	/* for handling queued and in-progress applies: */
61 	struct work_struct apply_work;
62 
63 	/* if there is a pending flip, these will be non-null: */
64 	struct drm_pending_vblank_event *event;
65 	struct drm_framebuffer *old_fb;
66 
67 	/* for handling page flips without caring about what
68 	 * the callback is called from.  Possibly we should just
69 	 * make omap_gem always call the cb from the worker so
70 	 * we don't have to care about this..
71 	 *
72 	 * XXX maybe fold into apply_work??
73 	 */
74 	struct work_struct page_flip_work;
75 };
76 
77 uint32_t pipe2vbl(struct drm_crtc *crtc)
78 {
79 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
80 
81 	return dispc_mgr_get_vsync_irq(omap_crtc->channel);
82 }
83 
84 /*
85  * Manager-ops, callbacks from output when they need to configure
86  * the upstream part of the video pipe.
87  *
88  * Most of these we can ignore until we add support for command-mode
89  * panels.. for video-mode the crtc-helpers already do an adequate
90  * job of sequencing the setup of the video pipe in the proper order
91  */
92 
93 /* ovl-mgr-id -> crtc */
94 static struct omap_crtc *omap_crtcs[8];
95 
96 /* we can probably ignore these until we support command-mode panels: */
97 static int omap_crtc_connect(struct omap_overlay_manager *mgr,
98 		struct omap_dss_device *dst)
99 {
100 	if (mgr->output)
101 		return -EINVAL;
102 
103 	if ((mgr->supported_outputs & dst->id) == 0)
104 		return -EINVAL;
105 
106 	dst->manager = mgr;
107 	mgr->output = dst;
108 
109 	return 0;
110 }
111 
112 static void omap_crtc_disconnect(struct omap_overlay_manager *mgr,
113 		struct omap_dss_device *dst)
114 {
115 	mgr->output->manager = NULL;
116 	mgr->output = NULL;
117 }
118 
119 static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
120 {
121 }
122 
123 static int omap_crtc_enable(struct omap_overlay_manager *mgr)
124 {
125 	return 0;
126 }
127 
128 static void omap_crtc_disable(struct omap_overlay_manager *mgr)
129 {
130 }
131 
132 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
133 		const struct omap_video_timings *timings)
134 {
135 	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
136 	DBG("%s", omap_crtc->name);
137 	omap_crtc->timings = *timings;
138 	omap_crtc->full_update = true;
139 }
140 
141 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
142 		const struct dss_lcd_mgr_config *config)
143 {
144 	struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
145 	DBG("%s", omap_crtc->name);
146 	dispc_mgr_set_lcd_config(omap_crtc->channel, config);
147 }
148 
149 static int omap_crtc_register_framedone_handler(
150 		struct omap_overlay_manager *mgr,
151 		void (*handler)(void *), void *data)
152 {
153 	return 0;
154 }
155 
156 static void omap_crtc_unregister_framedone_handler(
157 		struct omap_overlay_manager *mgr,
158 		void (*handler)(void *), void *data)
159 {
160 }
161 
162 static const struct dss_mgr_ops mgr_ops = {
163 		.connect = omap_crtc_connect,
164 		.disconnect = omap_crtc_disconnect,
165 		.start_update = omap_crtc_start_update,
166 		.enable = omap_crtc_enable,
167 		.disable = omap_crtc_disable,
168 		.set_timings = omap_crtc_set_timings,
169 		.set_lcd_config = omap_crtc_set_lcd_config,
170 		.register_framedone_handler = omap_crtc_register_framedone_handler,
171 		.unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
172 };
173 
174 /*
175  * CRTC funcs:
176  */
177 
178 static void omap_crtc_destroy(struct drm_crtc *crtc)
179 {
180 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
181 
182 	DBG("%s", omap_crtc->name);
183 
184 	WARN_ON(omap_crtc->apply_irq.registered);
185 	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
186 
187 	omap_crtc->plane->funcs->destroy(omap_crtc->plane);
188 	drm_crtc_cleanup(crtc);
189 
190 	kfree(omap_crtc);
191 }
192 
193 static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
194 {
195 	struct omap_drm_private *priv = crtc->dev->dev_private;
196 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
197 	bool enabled = (mode == DRM_MODE_DPMS_ON);
198 	int i;
199 
200 	DBG("%s: %d", omap_crtc->name, mode);
201 
202 	if (enabled != omap_crtc->enabled) {
203 		omap_crtc->enabled = enabled;
204 		omap_crtc->full_update = true;
205 		omap_crtc_apply(crtc, &omap_crtc->apply);
206 
207 		/* also enable our private plane: */
208 		WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
209 
210 		/* and any attached overlay planes: */
211 		for (i = 0; i < priv->num_planes; i++) {
212 			struct drm_plane *plane = priv->planes[i];
213 			if (plane->crtc == crtc)
214 				WARN_ON(omap_plane_dpms(plane, mode));
215 		}
216 	}
217 }
218 
219 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
220 		const struct drm_display_mode *mode,
221 		struct drm_display_mode *adjusted_mode)
222 {
223 	return true;
224 }
225 
226 static int omap_crtc_mode_set(struct drm_crtc *crtc,
227 		struct drm_display_mode *mode,
228 		struct drm_display_mode *adjusted_mode,
229 		int x, int y,
230 		struct drm_framebuffer *old_fb)
231 {
232 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
233 
234 	mode = adjusted_mode;
235 
236 	DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
237 			omap_crtc->name, mode->base.id, mode->name,
238 			mode->vrefresh, mode->clock,
239 			mode->hdisplay, mode->hsync_start,
240 			mode->hsync_end, mode->htotal,
241 			mode->vdisplay, mode->vsync_start,
242 			mode->vsync_end, mode->vtotal,
243 			mode->type, mode->flags);
244 
245 	copy_timings_drm_to_omap(&omap_crtc->timings, mode);
246 	omap_crtc->full_update = true;
247 
248 	return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
249 			0, 0, mode->hdisplay, mode->vdisplay,
250 			x << 16, y << 16,
251 			mode->hdisplay << 16, mode->vdisplay << 16,
252 			NULL, NULL);
253 }
254 
255 static void omap_crtc_prepare(struct drm_crtc *crtc)
256 {
257 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
258 	DBG("%s", omap_crtc->name);
259 	omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
260 }
261 
262 static void omap_crtc_commit(struct drm_crtc *crtc)
263 {
264 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
265 	DBG("%s", omap_crtc->name);
266 	omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
267 }
268 
269 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
270 		struct drm_framebuffer *old_fb)
271 {
272 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
273 	struct drm_plane *plane = omap_crtc->plane;
274 	struct drm_display_mode *mode = &crtc->mode;
275 
276 	return omap_plane_mode_set(plane, crtc, crtc->fb,
277 			0, 0, mode->hdisplay, mode->vdisplay,
278 			x << 16, y << 16,
279 			mode->hdisplay << 16, mode->vdisplay << 16,
280 			NULL, NULL);
281 }
282 
283 static void vblank_cb(void *arg)
284 {
285 	struct drm_crtc *crtc = arg;
286 	struct drm_device *dev = crtc->dev;
287 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
288 	unsigned long flags;
289 
290 	spin_lock_irqsave(&dev->event_lock, flags);
291 
292 	/* wakeup userspace */
293 	if (omap_crtc->event)
294 		drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
295 
296 	omap_crtc->event = NULL;
297 	omap_crtc->old_fb = NULL;
298 
299 	spin_unlock_irqrestore(&dev->event_lock, flags);
300 }
301 
302 static void page_flip_worker(struct work_struct *work)
303 {
304 	struct omap_crtc *omap_crtc =
305 			container_of(work, struct omap_crtc, page_flip_work);
306 	struct drm_crtc *crtc = &omap_crtc->base;
307 	struct drm_display_mode *mode = &crtc->mode;
308 	struct drm_gem_object *bo;
309 
310 	mutex_lock(&crtc->mutex);
311 	omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
312 			0, 0, mode->hdisplay, mode->vdisplay,
313 			crtc->x << 16, crtc->y << 16,
314 			mode->hdisplay << 16, mode->vdisplay << 16,
315 			vblank_cb, crtc);
316 	mutex_unlock(&crtc->mutex);
317 
318 	bo = omap_framebuffer_bo(crtc->fb, 0);
319 	drm_gem_object_unreference_unlocked(bo);
320 }
321 
322 static void page_flip_cb(void *arg)
323 {
324 	struct drm_crtc *crtc = arg;
325 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
326 	struct omap_drm_private *priv = crtc->dev->dev_private;
327 
328 	/* avoid assumptions about what ctxt we are called from: */
329 	queue_work(priv->wq, &omap_crtc->page_flip_work);
330 }
331 
332 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
333 		 struct drm_framebuffer *fb,
334 		 struct drm_pending_vblank_event *event,
335 		 uint32_t page_flip_flags)
336 {
337 	struct drm_device *dev = crtc->dev;
338 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
339 	struct drm_gem_object *bo;
340 
341 	DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
342 			fb->base.id, event);
343 
344 	if (omap_crtc->old_fb) {
345 		dev_err(dev->dev, "already a pending flip\n");
346 		return -EINVAL;
347 	}
348 
349 	omap_crtc->event = event;
350 	crtc->fb = fb;
351 
352 	/*
353 	 * Hold a reference temporarily until the crtc is updated
354 	 * and takes the reference to the bo.  This avoids it
355 	 * getting freed from under us:
356 	 */
357 	bo = omap_framebuffer_bo(fb, 0);
358 	drm_gem_object_reference(bo);
359 
360 	omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
361 
362 	return 0;
363 }
364 
365 static int omap_crtc_set_property(struct drm_crtc *crtc,
366 		struct drm_property *property, uint64_t val)
367 {
368 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
369 	struct omap_drm_private *priv = crtc->dev->dev_private;
370 
371 	if (property == priv->rotation_prop) {
372 		crtc->invert_dimensions =
373 				!!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
374 	}
375 
376 	return omap_plane_set_property(omap_crtc->plane, property, val);
377 }
378 
379 static const struct drm_crtc_funcs omap_crtc_funcs = {
380 	.set_config = drm_crtc_helper_set_config,
381 	.destroy = omap_crtc_destroy,
382 	.page_flip = omap_crtc_page_flip_locked,
383 	.set_property = omap_crtc_set_property,
384 };
385 
386 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
387 	.dpms = omap_crtc_dpms,
388 	.mode_fixup = omap_crtc_mode_fixup,
389 	.mode_set = omap_crtc_mode_set,
390 	.prepare = omap_crtc_prepare,
391 	.commit = omap_crtc_commit,
392 	.mode_set_base = omap_crtc_mode_set_base,
393 };
394 
395 const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
396 {
397 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
398 	return &omap_crtc->timings;
399 }
400 
401 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
402 {
403 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
404 	return omap_crtc->channel;
405 }
406 
407 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
408 {
409 	struct omap_crtc *omap_crtc =
410 			container_of(irq, struct omap_crtc, error_irq);
411 	struct drm_crtc *crtc = &omap_crtc->base;
412 	DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
413 	/* avoid getting in a flood, unregister the irq until next vblank */
414 	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
415 }
416 
417 static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
418 {
419 	struct omap_crtc *omap_crtc =
420 			container_of(irq, struct omap_crtc, apply_irq);
421 	struct drm_crtc *crtc = &omap_crtc->base;
422 
423 	if (!omap_crtc->error_irq.registered)
424 		omap_irq_register(crtc->dev, &omap_crtc->error_irq);
425 
426 	if (!dispc_mgr_go_busy(omap_crtc->channel)) {
427 		struct omap_drm_private *priv =
428 				crtc->dev->dev_private;
429 		DBG("%s: apply done", omap_crtc->name);
430 		omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
431 		queue_work(priv->wq, &omap_crtc->apply_work);
432 	}
433 }
434 
435 static void apply_worker(struct work_struct *work)
436 {
437 	struct omap_crtc *omap_crtc =
438 			container_of(work, struct omap_crtc, apply_work);
439 	struct drm_crtc *crtc = &omap_crtc->base;
440 	struct drm_device *dev = crtc->dev;
441 	struct omap_drm_apply *apply, *n;
442 	bool need_apply;
443 
444 	/*
445 	 * Synchronize everything on mode_config.mutex, to keep
446 	 * the callbacks and list modification all serialized
447 	 * with respect to modesetting ioctls from userspace.
448 	 */
449 	mutex_lock(&crtc->mutex);
450 	dispc_runtime_get();
451 
452 	/*
453 	 * If we are still pending a previous update, wait.. when the
454 	 * pending update completes, we get kicked again.
455 	 */
456 	if (omap_crtc->apply_irq.registered)
457 		goto out;
458 
459 	/* finish up previous apply's: */
460 	list_for_each_entry_safe(apply, n,
461 			&omap_crtc->pending_applies, pending_node) {
462 		apply->post_apply(apply);
463 		list_del(&apply->pending_node);
464 	}
465 
466 	need_apply = !list_empty(&omap_crtc->queued_applies);
467 
468 	/* then handle the next round of of queued apply's: */
469 	list_for_each_entry_safe(apply, n,
470 			&omap_crtc->queued_applies, queued_node) {
471 		apply->pre_apply(apply);
472 		list_del(&apply->queued_node);
473 		apply->queued = false;
474 		list_add_tail(&apply->pending_node,
475 				&omap_crtc->pending_applies);
476 	}
477 
478 	if (need_apply) {
479 		enum omap_channel channel = omap_crtc->channel;
480 
481 		DBG("%s: GO", omap_crtc->name);
482 
483 		if (dispc_mgr_is_enabled(channel)) {
484 			omap_irq_register(dev, &omap_crtc->apply_irq);
485 			dispc_mgr_go(channel);
486 		} else {
487 			struct omap_drm_private *priv = dev->dev_private;
488 			queue_work(priv->wq, &omap_crtc->apply_work);
489 		}
490 	}
491 
492 out:
493 	dispc_runtime_put();
494 	mutex_unlock(&crtc->mutex);
495 }
496 
497 int omap_crtc_apply(struct drm_crtc *crtc,
498 		struct omap_drm_apply *apply)
499 {
500 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
501 
502 	WARN_ON(!mutex_is_locked(&crtc->mutex));
503 
504 	/* no need to queue it again if it is already queued: */
505 	if (apply->queued)
506 		return 0;
507 
508 	apply->queued = true;
509 	list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
510 
511 	/*
512 	 * If there are no currently pending updates, then go ahead and
513 	 * kick the worker immediately, otherwise it will run again when
514 	 * the current update finishes.
515 	 */
516 	if (list_empty(&omap_crtc->pending_applies)) {
517 		struct omap_drm_private *priv = crtc->dev->dev_private;
518 		queue_work(priv->wq, &omap_crtc->apply_work);
519 	}
520 
521 	return 0;
522 }
523 
524 /* called only from apply */
525 static void set_enabled(struct drm_crtc *crtc, bool enable)
526 {
527 	struct drm_device *dev = crtc->dev;
528 	struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
529 	enum omap_channel channel = omap_crtc->channel;
530 	struct omap_irq_wait *wait = NULL;
531 
532 	if (dispc_mgr_is_enabled(channel) == enable)
533 		return;
534 
535 	/* ignore sync-lost irqs during enable/disable */
536 	omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
537 
538 	if (dispc_mgr_get_framedone_irq(channel)) {
539 		if (!enable) {
540 			wait = omap_irq_wait_init(dev,
541 					dispc_mgr_get_framedone_irq(channel), 1);
542 		}
543 	} else {
544 		/*
545 		 * When we disable digit output, we need to wait until fields
546 		 * are done.  Otherwise the DSS is still working, and turning
547 		 * off the clocks prevents DSS from going to OFF mode. And when
548 		 * enabling, we need to wait for the extra sync losts
549 		 */
550 		wait = omap_irq_wait_init(dev,
551 				dispc_mgr_get_vsync_irq(channel), 2);
552 	}
553 
554 	dispc_mgr_enable(channel, enable);
555 
556 	if (wait) {
557 		int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
558 		if (ret) {
559 			dev_err(dev->dev, "%s: timeout waiting for %s\n",
560 					omap_crtc->name, enable ? "enable" : "disable");
561 		}
562 	}
563 
564 	omap_irq_register(crtc->dev, &omap_crtc->error_irq);
565 }
566 
567 static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
568 {
569 	struct omap_crtc *omap_crtc =
570 			container_of(apply, struct omap_crtc, apply);
571 	struct drm_crtc *crtc = &omap_crtc->base;
572 	struct drm_encoder *encoder = NULL;
573 
574 	DBG("%s: enabled=%d, full=%d", omap_crtc->name,
575 			omap_crtc->enabled, omap_crtc->full_update);
576 
577 	if (omap_crtc->full_update) {
578 		struct omap_drm_private *priv = crtc->dev->dev_private;
579 		int i;
580 		for (i = 0; i < priv->num_encoders; i++) {
581 			if (priv->encoders[i]->crtc == crtc) {
582 				encoder = priv->encoders[i];
583 				break;
584 			}
585 		}
586 	}
587 
588 	if (!omap_crtc->enabled) {
589 		set_enabled(&omap_crtc->base, false);
590 		if (encoder)
591 			omap_encoder_set_enabled(encoder, false);
592 	} else {
593 		if (encoder) {
594 			omap_encoder_set_enabled(encoder, false);
595 			omap_encoder_update(encoder, omap_crtc->mgr,
596 					&omap_crtc->timings);
597 			omap_encoder_set_enabled(encoder, true);
598 			omap_crtc->full_update = false;
599 		}
600 
601 		dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
602 		dispc_mgr_set_timings(omap_crtc->channel,
603 				&omap_crtc->timings);
604 		set_enabled(&omap_crtc->base, true);
605 	}
606 
607 	omap_crtc->full_update = false;
608 }
609 
610 static void omap_crtc_post_apply(struct omap_drm_apply *apply)
611 {
612 	/* nothing needed for post-apply */
613 }
614 
615 static const char *channel_names[] = {
616 		[OMAP_DSS_CHANNEL_LCD] = "lcd",
617 		[OMAP_DSS_CHANNEL_DIGIT] = "tv",
618 		[OMAP_DSS_CHANNEL_LCD2] = "lcd2",
619 };
620 
621 void omap_crtc_pre_init(void)
622 {
623 	dss_install_mgr_ops(&mgr_ops);
624 }
625 
626 /* initialize crtc */
627 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
628 		struct drm_plane *plane, enum omap_channel channel, int id)
629 {
630 	struct drm_crtc *crtc = NULL;
631 	struct omap_crtc *omap_crtc;
632 	struct omap_overlay_manager_info *info;
633 
634 	DBG("%s", channel_names[channel]);
635 
636 	omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
637 	if (!omap_crtc)
638 		goto fail;
639 
640 	crtc = &omap_crtc->base;
641 
642 	INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
643 	INIT_WORK(&omap_crtc->apply_work, apply_worker);
644 
645 	INIT_LIST_HEAD(&omap_crtc->pending_applies);
646 	INIT_LIST_HEAD(&omap_crtc->queued_applies);
647 
648 	omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
649 	omap_crtc->apply.post_apply = omap_crtc_post_apply;
650 
651 	omap_crtc->channel = channel;
652 	omap_crtc->plane = plane;
653 	omap_crtc->plane->crtc = crtc;
654 	omap_crtc->name = channel_names[channel];
655 	omap_crtc->pipe = id;
656 
657 	omap_crtc->apply_irq.irqmask = pipe2vbl(crtc);
658 	omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
659 
660 	omap_crtc->error_irq.irqmask =
661 			dispc_mgr_get_sync_lost_irq(channel);
662 	omap_crtc->error_irq.irq = omap_crtc_error_irq;
663 	omap_irq_register(dev, &omap_crtc->error_irq);
664 
665 	/* temporary: */
666 	omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
667 
668 	/* TODO: fix hard-coded setup.. add properties! */
669 	info = &omap_crtc->info;
670 	info->default_color = 0x00000000;
671 	info->trans_key = 0x00000000;
672 	info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
673 	info->trans_enabled = false;
674 
675 	drm_crtc_init(dev, crtc, &omap_crtc_funcs);
676 	drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
677 
678 	omap_plane_install_properties(omap_crtc->plane, &crtc->base);
679 
680 	omap_crtcs[channel] = omap_crtc;
681 
682 	return crtc;
683 
684 fail:
685 	if (crtc)
686 		omap_crtc_destroy(crtc);
687 
688 	return NULL;
689 }
690