aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/omapdrm/omap_crtc.c
diff options
context:
space:
mode:
authorRob Clark <robdclark@gmail.com>2013-02-11 12:43:09 -0500
committerRob Clark <robdclark@gmail.com>2013-02-16 17:38:06 -0500
commit8bb0daffb0b8e45188066255b4203446eae181f1 (patch)
treec1a324b863df57becdfab54c9325231bbb853b56 /drivers/gpu/drm/omapdrm/omap_crtc.c
parenta4462f246c8821f625f45bce52c7ca7e0207dffe (diff)
drm/omap: move out of staging
Now that the omapdss interface has been reworked so that omapdrm can use dispc directly, we have been able to fix the remaining functional kms issues with omapdrm. And in the mean time the PM sequencing and many other of that open issues have been solved. So I think it makes sense to finally move omapdrm out of staging. Signed-off-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu/drm/omapdrm/omap_crtc.c')
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c659
1 files changed, 659 insertions, 0 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
new file mode 100644
index 000000000000..2b97cf90071b
--- /dev/null
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -0,0 +1,659 @@
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
28struct 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/*
78 * Manager-ops, callbacks from output when they need to configure
79 * the upstream part of the video pipe.
80 *
81 * Most of these we can ignore until we add support for command-mode
82 * panels.. for video-mode the crtc-helpers already do an adequate
83 * job of sequencing the setup of the video pipe in the proper order
84 */
85
86/* we can probably ignore these until we support command-mode panels: */
87static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
88{
89}
90
91static int omap_crtc_enable(struct omap_overlay_manager *mgr)
92{
93 return 0;
94}
95
96static void omap_crtc_disable(struct omap_overlay_manager *mgr)
97{
98}
99
100static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
101 const struct omap_video_timings *timings)
102{
103 struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
104 DBG("%s", omap_crtc->name);
105 omap_crtc->timings = *timings;
106 omap_crtc->full_update = true;
107}
108
109static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr,
110 const struct dss_lcd_mgr_config *config)
111{
112 struct omap_crtc *omap_crtc = container_of(mgr, struct omap_crtc, mgr);
113 DBG("%s", omap_crtc->name);
114 dispc_mgr_set_lcd_config(omap_crtc->channel, config);
115}
116
117static int omap_crtc_register_framedone_handler(
118 struct omap_overlay_manager *mgr,
119 void (*handler)(void *), void *data)
120{
121 return 0;
122}
123
124static void omap_crtc_unregister_framedone_handler(
125 struct omap_overlay_manager *mgr,
126 void (*handler)(void *), void *data)
127{
128}
129
130static const struct dss_mgr_ops mgr_ops = {
131 .start_update = omap_crtc_start_update,
132 .enable = omap_crtc_enable,
133 .disable = omap_crtc_disable,
134 .set_timings = omap_crtc_set_timings,
135 .set_lcd_config = omap_crtc_set_lcd_config,
136 .register_framedone_handler = omap_crtc_register_framedone_handler,
137 .unregister_framedone_handler = omap_crtc_unregister_framedone_handler,
138};
139
140/*
141 * CRTC funcs:
142 */
143
144static void omap_crtc_destroy(struct drm_crtc *crtc)
145{
146 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
147
148 DBG("%s", omap_crtc->name);
149
150 WARN_ON(omap_crtc->apply_irq.registered);
151 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
152
153 omap_crtc->plane->funcs->destroy(omap_crtc->plane);
154 drm_crtc_cleanup(crtc);
155
156 kfree(omap_crtc);
157}
158
159static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
160{
161 struct omap_drm_private *priv = crtc->dev->dev_private;
162 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
163 bool enabled = (mode == DRM_MODE_DPMS_ON);
164 int i;
165
166 DBG("%s: %d", omap_crtc->name, mode);
167
168 if (enabled != omap_crtc->enabled) {
169 omap_crtc->enabled = enabled;
170 omap_crtc->full_update = true;
171 omap_crtc_apply(crtc, &omap_crtc->apply);
172
173 /* also enable our private plane: */
174 WARN_ON(omap_plane_dpms(omap_crtc->plane, mode));
175
176 /* and any attached overlay planes: */
177 for (i = 0; i < priv->num_planes; i++) {
178 struct drm_plane *plane = priv->planes[i];
179 if (plane->crtc == crtc)
180 WARN_ON(omap_plane_dpms(plane, mode));
181 }
182 }
183}
184
185static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
186 const struct drm_display_mode *mode,
187 struct drm_display_mode *adjusted_mode)
188{
189 return true;
190}
191
192static int omap_crtc_mode_set(struct drm_crtc *crtc,
193 struct drm_display_mode *mode,
194 struct drm_display_mode *adjusted_mode,
195 int x, int y,
196 struct drm_framebuffer *old_fb)
197{
198 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
199
200 mode = adjusted_mode;
201
202 DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
203 omap_crtc->name, mode->base.id, mode->name,
204 mode->vrefresh, mode->clock,
205 mode->hdisplay, mode->hsync_start,
206 mode->hsync_end, mode->htotal,
207 mode->vdisplay, mode->vsync_start,
208 mode->vsync_end, mode->vtotal,
209 mode->type, mode->flags);
210
211 copy_timings_drm_to_omap(&omap_crtc->timings, mode);
212 omap_crtc->full_update = true;
213
214 return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
215 0, 0, mode->hdisplay, mode->vdisplay,
216 x << 16, y << 16,
217 mode->hdisplay << 16, mode->vdisplay << 16,
218 NULL, NULL);
219}
220
221static void omap_crtc_prepare(struct drm_crtc *crtc)
222{
223 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
224 DBG("%s", omap_crtc->name);
225 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
226}
227
228static void omap_crtc_commit(struct drm_crtc *crtc)
229{
230 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
231 DBG("%s", omap_crtc->name);
232 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
233}
234
235static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
236 struct drm_framebuffer *old_fb)
237{
238 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
239 struct drm_plane *plane = omap_crtc->plane;
240 struct drm_display_mode *mode = &crtc->mode;
241
242 return omap_plane_mode_set(plane, crtc, crtc->fb,
243 0, 0, mode->hdisplay, mode->vdisplay,
244 x << 16, y << 16,
245 mode->hdisplay << 16, mode->vdisplay << 16,
246 NULL, NULL);
247}
248
249static void omap_crtc_load_lut(struct drm_crtc *crtc)
250{
251}
252
253static void vblank_cb(void *arg)
254{
255 struct drm_crtc *crtc = arg;
256 struct drm_device *dev = crtc->dev;
257 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
258 unsigned long flags;
259
260 spin_lock_irqsave(&dev->event_lock, flags);
261
262 /* wakeup userspace */
263 if (omap_crtc->event)
264 drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event);
265
266 omap_crtc->event = NULL;
267 omap_crtc->old_fb = NULL;
268
269 spin_unlock_irqrestore(&dev->event_lock, flags);
270}
271
272static void page_flip_worker(struct work_struct *work)
273{
274 struct omap_crtc *omap_crtc =
275 container_of(work, struct omap_crtc, page_flip_work);
276 struct drm_crtc *crtc = &omap_crtc->base;
277 struct drm_device *dev = crtc->dev;
278 struct drm_display_mode *mode = &crtc->mode;
279 struct drm_gem_object *bo;
280
281 drm_modeset_lock_all(dev);
282 omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
283 0, 0, mode->hdisplay, mode->vdisplay,
284 crtc->x << 16, crtc->y << 16,
285 mode->hdisplay << 16, mode->vdisplay << 16,
286 vblank_cb, crtc);
287 drm_modeset_unlock_all(dev);
288
289 bo = omap_framebuffer_bo(crtc->fb, 0);
290 drm_gem_object_unreference_unlocked(bo);
291}
292
293static void page_flip_cb(void *arg)
294{
295 struct drm_crtc *crtc = arg;
296 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
297 struct omap_drm_private *priv = crtc->dev->dev_private;
298
299 /* avoid assumptions about what ctxt we are called from: */
300 queue_work(priv->wq, &omap_crtc->page_flip_work);
301}
302
303static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
304 struct drm_framebuffer *fb,
305 struct drm_pending_vblank_event *event)
306{
307 struct drm_device *dev = crtc->dev;
308 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
309 struct drm_gem_object *bo;
310
311 DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
312 fb->base.id, event);
313
314 if (omap_crtc->old_fb) {
315 dev_err(dev->dev, "already a pending flip\n");
316 return -EINVAL;
317 }
318
319 omap_crtc->event = event;
320 crtc->fb = fb;
321
322 /*
323 * Hold a reference temporarily until the crtc is updated
324 * and takes the reference to the bo. This avoids it
325 * getting freed from under us:
326 */
327 bo = omap_framebuffer_bo(fb, 0);
328 drm_gem_object_reference(bo);
329
330 omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
331
332 return 0;
333}
334
335static int omap_crtc_set_property(struct drm_crtc *crtc,
336 struct drm_property *property, uint64_t val)
337{
338 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
339 struct omap_drm_private *priv = crtc->dev->dev_private;
340
341 if (property == priv->rotation_prop) {
342 crtc->invert_dimensions =
343 !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
344 }
345
346 return omap_plane_set_property(omap_crtc->plane, property, val);
347}
348
349static const struct drm_crtc_funcs omap_crtc_funcs = {
350 .set_config = drm_crtc_helper_set_config,
351 .destroy = omap_crtc_destroy,
352 .page_flip = omap_crtc_page_flip_locked,
353 .set_property = omap_crtc_set_property,
354};
355
356static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
357 .dpms = omap_crtc_dpms,
358 .mode_fixup = omap_crtc_mode_fixup,
359 .mode_set = omap_crtc_mode_set,
360 .prepare = omap_crtc_prepare,
361 .commit = omap_crtc_commit,
362 .mode_set_base = omap_crtc_mode_set_base,
363 .load_lut = omap_crtc_load_lut,
364};
365
366const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
367{
368 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
369 return &omap_crtc->timings;
370}
371
372enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
373{
374 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
375 return omap_crtc->channel;
376}
377
378static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
379{
380 struct omap_crtc *omap_crtc =
381 container_of(irq, struct omap_crtc, error_irq);
382 struct drm_crtc *crtc = &omap_crtc->base;
383 DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
384 /* avoid getting in a flood, unregister the irq until next vblank */
385 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
386}
387
388static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
389{
390 struct omap_crtc *omap_crtc =
391 container_of(irq, struct omap_crtc, apply_irq);
392 struct drm_crtc *crtc = &omap_crtc->base;
393
394 if (!omap_crtc->error_irq.registered)
395 omap_irq_register(crtc->dev, &omap_crtc->error_irq);
396
397 if (!dispc_mgr_go_busy(omap_crtc->channel)) {
398 struct omap_drm_private *priv =
399 crtc->dev->dev_private;
400 DBG("%s: apply done", omap_crtc->name);
401 omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
402 queue_work(priv->wq, &omap_crtc->apply_work);
403 }
404}
405
406static void apply_worker(struct work_struct *work)
407{
408 struct omap_crtc *omap_crtc =
409 container_of(work, struct omap_crtc, apply_work);
410 struct drm_crtc *crtc = &omap_crtc->base;
411 struct drm_device *dev = crtc->dev;
412 struct omap_drm_apply *apply, *n;
413 bool need_apply;
414
415 /*
416 * Synchronize everything on mode_config.mutex, to keep
417 * the callbacks and list modification all serialized
418 * with respect to modesetting ioctls from userspace.
419 */
420 drm_modeset_lock_all(dev);
421 dispc_runtime_get();
422
423 /*
424 * If we are still pending a previous update, wait.. when the
425 * pending update completes, we get kicked again.
426 */
427 if (omap_crtc->apply_irq.registered)
428 goto out;
429
430 /* finish up previous apply's: */
431 list_for_each_entry_safe(apply, n,
432 &omap_crtc->pending_applies, pending_node) {
433 apply->post_apply(apply);
434 list_del(&apply->pending_node);
435 }
436
437 need_apply = !list_empty(&omap_crtc->queued_applies);
438
439 /* then handle the next round of of queued apply's: */
440 list_for_each_entry_safe(apply, n,
441 &omap_crtc->queued_applies, queued_node) {
442 apply->pre_apply(apply);
443 list_del(&apply->queued_node);
444 apply->queued = false;
445 list_add_tail(&apply->pending_node,
446 &omap_crtc->pending_applies);
447 }
448
449 if (need_apply) {
450 enum omap_channel channel = omap_crtc->channel;
451
452 DBG("%s: GO", omap_crtc->name);
453
454 if (dispc_mgr_is_enabled(channel)) {
455 omap_irq_register(dev, &omap_crtc->apply_irq);
456 dispc_mgr_go(channel);
457 } else {
458 struct omap_drm_private *priv = dev->dev_private;
459 queue_work(priv->wq, &omap_crtc->apply_work);
460 }
461 }
462
463out:
464 dispc_runtime_put();
465 drm_modeset_unlock_all(dev);
466}
467
468int omap_crtc_apply(struct drm_crtc *crtc,
469 struct omap_drm_apply *apply)
470{
471 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
472 struct drm_device *dev = crtc->dev;
473
474 WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
475
476 /* no need to queue it again if it is already queued: */
477 if (apply->queued)
478 return 0;
479
480 apply->queued = true;
481 list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
482
483 /*
484 * If there are no currently pending updates, then go ahead and
485 * kick the worker immediately, otherwise it will run again when
486 * the current update finishes.
487 */
488 if (list_empty(&omap_crtc->pending_applies)) {
489 struct omap_drm_private *priv = crtc->dev->dev_private;
490 queue_work(priv->wq, &omap_crtc->apply_work);
491 }
492
493 return 0;
494}
495
496/* called only from apply */
497static void set_enabled(struct drm_crtc *crtc, bool enable)
498{
499 struct drm_device *dev = crtc->dev;
500 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
501 enum omap_channel channel = omap_crtc->channel;
502 struct omap_irq_wait *wait = NULL;
503
504 if (dispc_mgr_is_enabled(channel) == enable)
505 return;
506
507 /* ignore sync-lost irqs during enable/disable */
508 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
509
510 if (dispc_mgr_get_framedone_irq(channel)) {
511 if (!enable) {
512 wait = omap_irq_wait_init(dev,
513 dispc_mgr_get_framedone_irq(channel), 1);
514 }
515 } else {
516 /*
517 * When we disable digit output, we need to wait until fields
518 * are done. Otherwise the DSS is still working, and turning
519 * off the clocks prevents DSS from going to OFF mode. And when
520 * enabling, we need to wait for the extra sync losts
521 */
522 wait = omap_irq_wait_init(dev,
523 dispc_mgr_get_vsync_irq(channel), 2);
524 }
525
526 dispc_mgr_enable(channel, enable);
527
528 if (wait) {
529 int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
530 if (ret) {
531 dev_err(dev->dev, "%s: timeout waiting for %s\n",
532 omap_crtc->name, enable ? "enable" : "disable");
533 }
534 }
535
536 omap_irq_register(crtc->dev, &omap_crtc->error_irq);
537}
538
539static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
540{
541 struct omap_crtc *omap_crtc =
542 container_of(apply, struct omap_crtc, apply);
543 struct drm_crtc *crtc = &omap_crtc->base;
544 struct drm_encoder *encoder = NULL;
545
546 DBG("%s: enabled=%d, full=%d", omap_crtc->name,
547 omap_crtc->enabled, omap_crtc->full_update);
548
549 if (omap_crtc->full_update) {
550 struct omap_drm_private *priv = crtc->dev->dev_private;
551 int i;
552 for (i = 0; i < priv->num_encoders; i++) {
553 if (priv->encoders[i]->crtc == crtc) {
554 encoder = priv->encoders[i];
555 break;
556 }
557 }
558 }
559
560 if (!omap_crtc->enabled) {
561 set_enabled(&omap_crtc->base, false);
562 if (encoder)
563 omap_encoder_set_enabled(encoder, false);
564 } else {
565 if (encoder) {
566 omap_encoder_set_enabled(encoder, false);
567 omap_encoder_update(encoder, &omap_crtc->mgr,
568 &omap_crtc->timings);
569 omap_encoder_set_enabled(encoder, true);
570 omap_crtc->full_update = false;
571 }
572
573 dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
574 dispc_mgr_set_timings(omap_crtc->channel,
575 &omap_crtc->timings);
576 set_enabled(&omap_crtc->base, true);
577 }
578
579 omap_crtc->full_update = false;
580}
581
582static void omap_crtc_post_apply(struct omap_drm_apply *apply)
583{
584 /* nothing needed for post-apply */
585}
586
587static const char *channel_names[] = {
588 [OMAP_DSS_CHANNEL_LCD] = "lcd",
589 [OMAP_DSS_CHANNEL_DIGIT] = "tv",
590 [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
591};
592
593/* initialize crtc */
594struct drm_crtc *omap_crtc_init(struct drm_device *dev,
595 struct drm_plane *plane, enum omap_channel channel, int id)
596{
597 struct drm_crtc *crtc = NULL;
598 struct omap_crtc *omap_crtc;
599 struct omap_overlay_manager_info *info;
600
601 DBG("%s", channel_names[channel]);
602
603 omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
604
605 if (!omap_crtc) {
606 dev_err(dev->dev, "could not allocate CRTC\n");
607 goto fail;
608 }
609
610 crtc = &omap_crtc->base;
611
612 INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
613 INIT_WORK(&omap_crtc->apply_work, apply_worker);
614
615 INIT_LIST_HEAD(&omap_crtc->pending_applies);
616 INIT_LIST_HEAD(&omap_crtc->queued_applies);
617
618 omap_crtc->apply.pre_apply = omap_crtc_pre_apply;
619 omap_crtc->apply.post_apply = omap_crtc_post_apply;
620
621 omap_crtc->apply_irq.irqmask = pipe2vbl(id);
622 omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
623
624 omap_crtc->error_irq.irqmask =
625 dispc_mgr_get_sync_lost_irq(channel);
626 omap_crtc->error_irq.irq = omap_crtc_error_irq;
627 omap_irq_register(dev, &omap_crtc->error_irq);
628
629 omap_crtc->channel = channel;
630 omap_crtc->plane = plane;
631 omap_crtc->plane->crtc = crtc;
632 omap_crtc->name = channel_names[channel];
633 omap_crtc->pipe = id;
634
635 /* temporary: */
636 omap_crtc->mgr.id = channel;
637
638 dss_install_mgr_ops(&mgr_ops);
639
640 /* TODO: fix hard-coded setup.. add properties! */
641 info = &omap_crtc->info;
642 info->default_color = 0x00000000;
643 info->trans_key = 0x00000000;
644 info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
645 info->trans_enabled = false;
646
647 drm_crtc_init(dev, crtc, &omap_crtc_funcs);
648 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
649
650 omap_plane_install_properties(omap_crtc->plane, &crtc->base);
651
652 return crtc;
653
654fail:
655 if (crtc)
656 omap_crtc_destroy(crtc);
657
658 return NULL;
659}