2 * drivers/gpu/drm/omapdrm/omap_crtc.c
4 * Copyright (C) 2011 Texas Instruments
5 * Author: Rob Clark <rob@ti.com>
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.
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
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/>.
20 #include <linux/completion.h>
22 #include <drm/drm_atomic.h>
23 #include <drm/drm_atomic_helper.h>
24 #include <drm/drm_crtc.h>
25 #include <drm/drm_crtc_helper.h>
26 #include <drm/drm_mode.h>
27 #include <drm/drm_plane_helper.h>
31 #define to_omap_crtc(x) container_of(x, struct omap_crtc, base)
33 enum omap_page_flip_state {
36 OMAP_PAGE_FLIP_QUEUED,
37 OMAP_PAGE_FLIP_CANCELLED,
45 enum omap_channel channel;
46 struct omap_overlay_manager_info info;
47 struct drm_encoder *current_encoder;
50 * Temporary: eventually this will go away, but it is needed
51 * for now to keep the output's happy. (They only need
52 * mgr->id.) Eventually this will be replaced w/ something
53 * more common-panel-framework-y
55 struct omap_overlay_manager *mgr;
57 struct omap_video_timings timings;
60 struct omap_drm_irq vblank_irq;
61 struct omap_drm_irq error_irq;
63 /* list of framebuffers to unpin */
64 struct list_head pending_unpins;
67 * flip_state flag indicates the current page flap state: IDLE if no
68 * page queue has been submitted, WAIT when waiting for GEM async
69 * completion, QUEUED when the page flip has been queued to the hardware
70 * or CANCELLED when the CRTC is turned off before the flip gets queued
71 * to the hardware. The flip event, if any, is stored in flip_event, and
72 * the framebuffer queued for page flip is stored in flip_fb. The
73 * flip_wait wait queue is used to wait for page flip completion.
75 * The flip_work work queue handles page flip requests without caring
76 * about what context the GEM async callback is called from. Possibly we
77 * should just make omap_gem always call the cb from the worker so we
78 * don't have to care about this.
80 enum omap_page_flip_state flip_state;
81 struct drm_pending_vblank_event *flip_event;
82 struct drm_framebuffer *flip_fb;
83 wait_queue_head_t flip_wait;
84 struct work_struct flip_work;
86 struct completion completion;
88 bool ignore_digit_sync_lost;
91 struct omap_framebuffer_unpin {
92 struct list_head list;
93 struct drm_framebuffer *fb;
96 /* -----------------------------------------------------------------------------
100 uint32_t pipe2vbl(struct drm_crtc *crtc)
102 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
104 return dispc_mgr_get_vsync_irq(omap_crtc->channel);
107 const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
109 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
110 return &omap_crtc->timings;
113 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
115 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
116 return omap_crtc->channel;
119 /* -----------------------------------------------------------------------------
120 * DSS Manager Functions
124 * Manager-ops, callbacks from output when they need to configure
125 * the upstream part of the video pipe.
127 * Most of these we can ignore until we add support for command-mode
128 * panels.. for video-mode the crtc-helpers already do an adequate
129 * job of sequencing the setup of the video pipe in the proper order
132 /* ovl-mgr-id -> crtc */
133 static struct omap_crtc *omap_crtcs[8];
135 /* we can probably ignore these until we support command-mode panels: */
136 static int omap_crtc_dss_connect(struct omap_overlay_manager *mgr,
137 struct omap_dss_device *dst)
142 if ((mgr->supported_outputs & dst->id) == 0)
151 static void omap_crtc_dss_disconnect(struct omap_overlay_manager *mgr,
152 struct omap_dss_device *dst)
154 mgr->output->manager = NULL;
158 static void omap_crtc_dss_start_update(struct omap_overlay_manager *mgr)
162 /* Called only from omap_crtc_setup and suspend/resume handlers. */
163 static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
165 struct drm_device *dev = crtc->dev;
166 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
167 enum omap_channel channel = omap_crtc->channel;
168 struct omap_irq_wait *wait;
169 u32 framedone_irq, vsync_irq;
172 if (dispc_mgr_is_enabled(channel) == enable)
175 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
177 * Digit output produces some sync lost interrupts during the
178 * first frame when enabling, so we need to ignore those.
180 omap_crtc->ignore_digit_sync_lost = true;
183 framedone_irq = dispc_mgr_get_framedone_irq(channel);
184 vsync_irq = dispc_mgr_get_vsync_irq(channel);
187 wait = omap_irq_wait_init(dev, vsync_irq, 1);
190 * When we disable the digit output, we need to wait for
191 * FRAMEDONE to know that DISPC has finished with the output.
193 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in
194 * that case we need to use vsync interrupt, and wait for both
195 * even and odd frames.
199 wait = omap_irq_wait_init(dev, framedone_irq, 1);
201 wait = omap_irq_wait_init(dev, vsync_irq, 2);
204 dispc_mgr_enable(channel, enable);
206 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
208 dev_err(dev->dev, "%s: timeout waiting for %s\n",
209 omap_crtc->name, enable ? "enable" : "disable");
212 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
213 omap_crtc->ignore_digit_sync_lost = false;
214 /* make sure the irq handler sees the value above */
220 static int omap_crtc_dss_enable(struct omap_overlay_manager *mgr)
222 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
224 dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
225 dispc_mgr_set_timings(omap_crtc->channel,
226 &omap_crtc->timings);
227 omap_crtc_set_enabled(&omap_crtc->base, true);
232 static void omap_crtc_dss_disable(struct omap_overlay_manager *mgr)
234 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
236 omap_crtc_set_enabled(&omap_crtc->base, false);
239 static void omap_crtc_dss_set_timings(struct omap_overlay_manager *mgr,
240 const struct omap_video_timings *timings)
242 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
243 DBG("%s", omap_crtc->name);
244 omap_crtc->timings = *timings;
247 static void omap_crtc_dss_set_lcd_config(struct omap_overlay_manager *mgr,
248 const struct dss_lcd_mgr_config *config)
250 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id];
251 DBG("%s", omap_crtc->name);
252 dispc_mgr_set_lcd_config(omap_crtc->channel, config);
255 static int omap_crtc_dss_register_framedone(
256 struct omap_overlay_manager *mgr,
257 void (*handler)(void *), void *data)
262 static void omap_crtc_dss_unregister_framedone(
263 struct omap_overlay_manager *mgr,
264 void (*handler)(void *), void *data)
268 static const struct dss_mgr_ops mgr_ops = {
269 .connect = omap_crtc_dss_connect,
270 .disconnect = omap_crtc_dss_disconnect,
271 .start_update = omap_crtc_dss_start_update,
272 .enable = omap_crtc_dss_enable,
273 .disable = omap_crtc_dss_disable,
274 .set_timings = omap_crtc_dss_set_timings,
275 .set_lcd_config = omap_crtc_dss_set_lcd_config,
276 .register_framedone_handler = omap_crtc_dss_register_framedone,
277 .unregister_framedone_handler = omap_crtc_dss_unregister_framedone,
280 /* -----------------------------------------------------------------------------
281 * Setup, Flush and Page Flip
284 void omap_crtc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
286 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
287 struct drm_device *dev = crtc->dev;
290 spin_lock_irqsave(&dev->event_lock, flags);
292 /* Only complete events queued for our file handle. */
293 if (omap_crtc->flip_event &&
294 file == omap_crtc->flip_event->base.file_priv) {
295 drm_send_vblank_event(dev, omap_crtc->pipe,
296 omap_crtc->flip_event);
297 omap_crtc->flip_event = NULL;
300 spin_unlock_irqrestore(&dev->event_lock, flags);
303 /* Must be called with dev->event_lock locked. */
304 static void omap_crtc_complete_page_flip(struct drm_crtc *crtc,
305 enum omap_page_flip_state state)
307 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
308 struct drm_device *dev = crtc->dev;
310 if (omap_crtc->flip_event) {
311 drm_send_vblank_event(dev, omap_crtc->pipe,
312 omap_crtc->flip_event);
313 omap_crtc->flip_event = NULL;
316 omap_crtc->flip_state = state;
318 if (state == OMAP_PAGE_FLIP_IDLE)
319 wake_up(&omap_crtc->flip_wait);
322 static bool omap_crtc_page_flip_pending(struct drm_crtc *crtc)
324 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
325 struct drm_device *dev = crtc->dev;
329 spin_lock_irqsave(&dev->event_lock, flags);
330 pending = omap_crtc->flip_state != OMAP_PAGE_FLIP_IDLE;
331 spin_unlock_irqrestore(&dev->event_lock, flags);
336 static void omap_crtc_wait_page_flip(struct drm_crtc *crtc)
338 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
339 struct drm_device *dev = crtc->dev;
340 bool cancelled = false;
344 * If we're still waiting for the GEM async operation to complete just
345 * cancel the page flip, as we're holding the CRTC mutex preventing the
346 * page flip work handler from queueing the page flip.
348 * We can't release the reference to the frame buffer here as the async
349 * operation doesn't keep its own reference to the buffer. We'll just
350 * let the page flip work queue handle that.
352 spin_lock_irqsave(&dev->event_lock, flags);
353 if (omap_crtc->flip_state == OMAP_PAGE_FLIP_WAIT) {
354 omap_crtc_complete_page_flip(crtc, OMAP_PAGE_FLIP_CANCELLED);
357 spin_unlock_irqrestore(&dev->event_lock, flags);
362 if (wait_event_timeout(omap_crtc->flip_wait,
363 !omap_crtc_page_flip_pending(crtc),
364 msecs_to_jiffies(50)))
367 dev_warn(crtc->dev->dev, "page flip timeout!\n");
369 spin_lock_irqsave(&dev->event_lock, flags);
370 omap_crtc_complete_page_flip(crtc, OMAP_PAGE_FLIP_IDLE);
371 spin_unlock_irqrestore(&dev->event_lock, flags);
374 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
376 struct omap_crtc *omap_crtc =
377 container_of(irq, struct omap_crtc, error_irq);
379 if (omap_crtc->ignore_digit_sync_lost) {
380 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
385 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
388 static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
390 struct omap_crtc *omap_crtc =
391 container_of(irq, struct omap_crtc, vblank_irq);
392 struct drm_device *dev = omap_crtc->base.dev;
395 if (dispc_mgr_go_busy(omap_crtc->channel))
398 DBG("%s: apply done", omap_crtc->name);
399 __omap_irq_unregister(dev, &omap_crtc->vblank_irq);
401 /* wakeup userspace */
402 spin_lock_irqsave(&dev->event_lock, flags);
403 omap_crtc_complete_page_flip(&omap_crtc->base, OMAP_PAGE_FLIP_IDLE);
404 spin_unlock_irqrestore(&dev->event_lock, flags);
406 complete(&omap_crtc->completion);
409 int omap_crtc_flush(struct drm_crtc *crtc)
411 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
412 struct omap_framebuffer_unpin *fb, *next;
414 DBG("%s: GO", omap_crtc->name);
416 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
417 WARN_ON(omap_crtc->vblank_irq.registered);
421 if (dispc_mgr_is_enabled(omap_crtc->channel)) {
422 dispc_mgr_go(omap_crtc->channel);
423 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
425 WARN_ON(!wait_for_completion_timeout(&omap_crtc->completion,
426 msecs_to_jiffies(100)));
427 reinit_completion(&omap_crtc->completion);
432 /* Unpin and unreference pending framebuffers. */
433 list_for_each_entry_safe(fb, next, &omap_crtc->pending_unpins, list) {
434 omap_framebuffer_unpin(fb->fb);
435 drm_framebuffer_unreference(fb->fb);
443 int omap_crtc_queue_unpin(struct drm_crtc *crtc, struct drm_framebuffer *fb)
445 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
446 struct omap_framebuffer_unpin *unpin;
448 unpin = kzalloc(sizeof(*unpin), GFP_KERNEL);
453 list_add_tail(&unpin->list, &omap_crtc->pending_unpins);
458 static void omap_crtc_setup(struct drm_crtc *crtc)
460 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
461 struct omap_drm_private *priv = crtc->dev->dev_private;
462 struct drm_encoder *encoder = NULL;
465 DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled);
469 for (i = 0; i < priv->num_encoders; i++) {
470 if (priv->encoders[i]->crtc == crtc) {
471 encoder = priv->encoders[i];
476 if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder)
477 omap_encoder_set_enabled(omap_crtc->current_encoder, false);
479 omap_crtc->current_encoder = encoder;
481 if (!omap_crtc->enabled) {
483 omap_encoder_set_enabled(encoder, false);
486 omap_encoder_set_enabled(encoder, false);
487 omap_encoder_update(encoder, omap_crtc->mgr,
488 &omap_crtc->timings);
489 omap_encoder_set_enabled(encoder, true);
496 /* -----------------------------------------------------------------------------
500 static void omap_crtc_destroy(struct drm_crtc *crtc)
502 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
504 DBG("%s", omap_crtc->name);
506 WARN_ON(omap_crtc->vblank_irq.registered);
507 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
509 drm_crtc_cleanup(crtc);
514 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc,
515 const struct drm_display_mode *mode,
516 struct drm_display_mode *adjusted_mode)
521 static void omap_crtc_enable(struct drm_crtc *crtc)
523 struct omap_drm_private *priv = crtc->dev->dev_private;
524 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
527 DBG("%s", omap_crtc->name);
529 if (omap_crtc->enabled)
532 /* Enable all planes associated with the CRTC. */
533 for (i = 0; i < priv->num_planes; i++) {
534 struct drm_plane *plane = priv->planes[i];
536 if (plane->crtc == crtc)
537 WARN_ON(omap_plane_set_enable(plane, true));
540 omap_crtc->enabled = true;
542 omap_crtc_setup(crtc);
543 omap_crtc_flush(crtc);
546 drm_crtc_vblank_on(crtc);
550 static void omap_crtc_disable(struct drm_crtc *crtc)
552 struct omap_drm_private *priv = crtc->dev->dev_private;
553 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
556 DBG("%s", omap_crtc->name);
558 if (!omap_crtc->enabled)
561 omap_crtc_wait_page_flip(crtc);
563 drm_crtc_vblank_off(crtc);
566 /* Disable all planes associated with the CRTC. */
567 for (i = 0; i < priv->num_planes; i++) {
568 struct drm_plane *plane = priv->planes[i];
570 if (plane->crtc == crtc)
571 WARN_ON(omap_plane_set_enable(plane, false));
574 omap_crtc->enabled = false;
576 omap_crtc_setup(crtc);
577 omap_crtc_flush(crtc);
580 static int omap_crtc_mode_set(struct drm_crtc *crtc,
581 struct drm_display_mode *mode,
582 struct drm_display_mode *adjusted_mode,
584 struct drm_framebuffer *old_fb)
586 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
588 mode = adjusted_mode;
590 DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
591 omap_crtc->name, mode->base.id, mode->name,
592 mode->vrefresh, mode->clock,
593 mode->hdisplay, mode->hsync_start,
594 mode->hsync_end, mode->htotal,
595 mode->vdisplay, mode->vsync_start,
596 mode->vsync_end, mode->vtotal,
597 mode->type, mode->flags);
599 copy_timings_drm_to_omap(&omap_crtc->timings, mode);
602 * The primary plane CRTC can be reset if the plane is disabled directly
603 * through the universal plane API. Set it again here.
605 crtc->primary->crtc = crtc;
607 return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb,
608 0, 0, mode->hdisplay, mode->vdisplay,
609 x, y, mode->hdisplay, mode->vdisplay);
612 static void omap_crtc_dpms(struct drm_crtc *crtc, int mode)
614 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
615 bool enable = (mode == DRM_MODE_DPMS_ON);
617 DBG("%s: %d", omap_crtc->name, mode);
620 omap_crtc_enable(crtc);
622 omap_crtc_disable(crtc);
625 static void omap_crtc_prepare(struct drm_crtc *crtc)
627 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
628 DBG("%s", omap_crtc->name);
629 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
632 static void omap_crtc_commit(struct drm_crtc *crtc)
634 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
635 DBG("%s", omap_crtc->name);
636 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
639 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
640 struct drm_framebuffer *old_fb)
642 struct drm_plane *plane = crtc->primary;
643 struct drm_display_mode *mode = &crtc->mode;
646 ret = omap_plane_mode_set(plane, crtc, crtc->primary->fb,
647 0, 0, mode->hdisplay, mode->vdisplay,
648 x, y, mode->hdisplay, mode->vdisplay);
652 return omap_crtc_flush(crtc);
655 static void page_flip_worker(struct work_struct *work)
657 struct omap_crtc *omap_crtc =
658 container_of(work, struct omap_crtc, flip_work);
659 struct drm_crtc *crtc = &omap_crtc->base;
660 struct drm_display_mode *mode = &crtc->mode;
661 struct drm_device *dev = crtc->dev;
662 struct drm_framebuffer *fb;
663 struct drm_gem_object *bo;
667 drm_modeset_lock(&crtc->mutex, NULL);
669 spin_lock_irqsave(&dev->event_lock, flags);
672 * The page flip could have been cancelled while waiting for the GEM
673 * async operation to complete. Don't queue the flip in that case.
675 if (omap_crtc->flip_state == OMAP_PAGE_FLIP_WAIT) {
676 omap_crtc->flip_state = OMAP_PAGE_FLIP_QUEUED;
679 omap_crtc->flip_state = OMAP_PAGE_FLIP_IDLE;
683 fb = omap_crtc->flip_fb;
684 omap_crtc->flip_fb = NULL;
686 spin_unlock_irqrestore(&dev->event_lock, flags);
689 omap_plane_mode_set(crtc->primary, crtc, fb,
690 0, 0, mode->hdisplay, mode->vdisplay,
691 crtc->x, crtc->y, mode->hdisplay,
693 omap_crtc_flush(crtc);
696 drm_modeset_unlock(&crtc->mutex);
698 bo = omap_framebuffer_bo(fb, 0);
699 drm_gem_object_unreference_unlocked(bo);
700 drm_framebuffer_unreference(fb);
703 static void page_flip_cb(void *arg)
705 struct drm_crtc *crtc = arg;
706 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
707 struct omap_drm_private *priv = crtc->dev->dev_private;
709 /* avoid assumptions about what ctxt we are called from: */
710 queue_work(priv->wq, &omap_crtc->flip_work);
713 static int omap_crtc_page_flip(struct drm_crtc *crtc,
714 struct drm_framebuffer *fb,
715 struct drm_pending_vblank_event *event,
716 uint32_t page_flip_flags)
718 struct drm_device *dev = crtc->dev;
719 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
720 struct drm_plane *primary = crtc->primary;
721 struct drm_gem_object *bo;
724 DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
727 spin_lock_irqsave(&dev->event_lock, flags);
729 if (omap_crtc->flip_state != OMAP_PAGE_FLIP_IDLE) {
730 spin_unlock_irqrestore(&dev->event_lock, flags);
731 dev_err(dev->dev, "already a pending flip\n");
736 * Store a reference to the framebuffer queued for page flip in the CRTC
737 * private structure. We can't rely on crtc->primary->fb in the page
738 * flip worker, as a racing CRTC disable (due for instance to an
739 * explicit framebuffer deletion from userspace) would set that field to
740 * NULL before the worker gets a change to run.
742 drm_framebuffer_reference(fb);
743 omap_crtc->flip_fb = fb;
744 omap_crtc->flip_event = event;
745 omap_crtc->flip_state = OMAP_PAGE_FLIP_WAIT;
747 drm_atomic_set_fb_for_plane(primary->state, fb);
750 spin_unlock_irqrestore(&dev->event_lock, flags);
753 * Hold a reference temporarily until the crtc is updated
754 * and takes the reference to the bo. This avoids it
755 * getting freed from under us:
757 bo = omap_framebuffer_bo(fb, 0);
758 drm_gem_object_reference(bo);
760 omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
765 static int omap_crtc_set_property(struct drm_crtc *crtc,
766 struct drm_property *property, uint64_t val)
768 if (property == crtc->dev->mode_config.rotation_property) {
769 crtc->invert_dimensions =
770 !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
773 return omap_plane_set_property(crtc->primary, property, val);
776 static const struct drm_crtc_funcs omap_crtc_funcs = {
777 .reset = drm_atomic_helper_crtc_reset,
778 .set_config = drm_crtc_helper_set_config,
779 .destroy = omap_crtc_destroy,
780 .page_flip = omap_crtc_page_flip,
781 .set_property = omap_crtc_set_property,
782 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
783 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
786 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
787 .dpms = omap_crtc_dpms,
788 .mode_fixup = omap_crtc_mode_fixup,
789 .mode_set = omap_crtc_mode_set,
790 .prepare = omap_crtc_prepare,
791 .commit = omap_crtc_commit,
792 .mode_set_base = omap_crtc_mode_set_base,
793 .disable = omap_crtc_disable,
794 .enable = omap_crtc_enable,
797 /* -----------------------------------------------------------------------------
801 static const char *channel_names[] = {
802 [OMAP_DSS_CHANNEL_LCD] = "lcd",
803 [OMAP_DSS_CHANNEL_DIGIT] = "tv",
804 [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
805 [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
808 void omap_crtc_pre_init(void)
810 dss_install_mgr_ops(&mgr_ops);
813 void omap_crtc_pre_uninit(void)
815 dss_uninstall_mgr_ops();
818 /* initialize crtc */
819 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
820 struct drm_plane *plane, enum omap_channel channel, int id)
822 struct drm_crtc *crtc = NULL;
823 struct omap_crtc *omap_crtc;
824 struct omap_overlay_manager_info *info;
827 DBG("%s", channel_names[channel]);
829 omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
833 crtc = &omap_crtc->base;
835 INIT_WORK(&omap_crtc->flip_work, page_flip_worker);
836 init_waitqueue_head(&omap_crtc->flip_wait);
838 INIT_LIST_HEAD(&omap_crtc->pending_unpins);
840 init_completion(&omap_crtc->completion);
842 omap_crtc->channel = channel;
843 omap_crtc->name = channel_names[channel];
844 omap_crtc->pipe = id;
846 omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
847 omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
849 omap_crtc->error_irq.irqmask =
850 dispc_mgr_get_sync_lost_irq(channel);
851 omap_crtc->error_irq.irq = omap_crtc_error_irq;
852 omap_irq_register(dev, &omap_crtc->error_irq);
855 omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
857 /* TODO: fix hard-coded setup.. add properties! */
858 info = &omap_crtc->info;
859 info->default_color = 0x00000000;
860 info->trans_key = 0x00000000;
861 info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
862 info->trans_enabled = false;
864 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
871 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
873 omap_plane_install_properties(crtc->primary, &crtc->base);
875 omap_crtcs[channel] = omap_crtc;