linux/drivers/gpu/drm/omapdrm/omap_crtc.c
<<
>>
Prefs
   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
  77uint32_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 */
  94static struct omap_crtc *omap_crtcs[8];
  95
  96/* we can probably ignore these until we support command-mode panels: */
  97static 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
 112static 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
 119static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
 120{
 121}
 122
 123static int omap_crtc_enable(struct omap_overlay_manager *mgr)
 124{
 125        return 0;
 126}
 127
 128static void omap_crtc_disable(struct omap_overlay_manager *mgr)
 129{
 130}
 131
 132static 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
 141static 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
 149static int omap_crtc_register_framedone_handler(
 150                struct omap_overlay_manager *mgr,
 151                void (*handler)(void *), void *data)
 152{
 153        return 0;
 154}
 155
 156static void omap_crtc_unregister_framedone_handler(
 157                struct omap_overlay_manager *mgr,
 158                void (*handler)(void *), void *data)
 159{
 160}
 161
 162static 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
 178static 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
 193static 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
 219static 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
 226static 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
 255static 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
 262static 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
 269static 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
 283static 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
 302static 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
 322static 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
 332static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 333                 struct drm_framebuffer *fb,
 334                 struct drm_pending_vblank_event *event)
 335{
 336        struct drm_device *dev = crtc->dev;
 337        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 338        struct drm_gem_object *bo;
 339
 340        DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
 341                        fb->base.id, event);
 342
 343        if (omap_crtc->old_fb) {
 344                dev_err(dev->dev, "already a pending flip\n");
 345                return -EINVAL;
 346        }
 347
 348        omap_crtc->event = event;
 349        crtc->fb = fb;
 350
 351        /*
 352         * Hold a reference temporarily until the crtc is updated
 353         * and takes the reference to the bo.  This avoids it
 354         * getting freed from under us:
 355         */
 356        bo = omap_framebuffer_bo(fb, 0);
 357        drm_gem_object_reference(bo);
 358
 359        omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc);
 360
 361        return 0;
 362}
 363
 364static int omap_crtc_set_property(struct drm_crtc *crtc,
 365                struct drm_property *property, uint64_t val)
 366{
 367        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 368        struct omap_drm_private *priv = crtc->dev->dev_private;
 369
 370        if (property == priv->rotation_prop) {
 371                crtc->invert_dimensions =
 372                                !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270)));
 373        }
 374
 375        return omap_plane_set_property(omap_crtc->plane, property, val);
 376}
 377
 378static const struct drm_crtc_funcs omap_crtc_funcs = {
 379        .set_config = drm_crtc_helper_set_config,
 380        .destroy = omap_crtc_destroy,
 381        .page_flip = omap_crtc_page_flip_locked,
 382        .set_property = omap_crtc_set_property,
 383};
 384
 385static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = {
 386        .dpms = omap_crtc_dpms,
 387        .mode_fixup = omap_crtc_mode_fixup,
 388        .mode_set = omap_crtc_mode_set,
 389        .prepare = omap_crtc_prepare,
 390        .commit = omap_crtc_commit,
 391        .mode_set_base = omap_crtc_mode_set_base,
 392};
 393
 394const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc)
 395{
 396        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 397        return &omap_crtc->timings;
 398}
 399
 400enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
 401{
 402        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 403        return omap_crtc->channel;
 404}
 405
 406static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 407{
 408        struct omap_crtc *omap_crtc =
 409                        container_of(irq, struct omap_crtc, error_irq);
 410        struct drm_crtc *crtc = &omap_crtc->base;
 411        DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
 412        /* avoid getting in a flood, unregister the irq until next vblank */
 413        omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
 414}
 415
 416static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
 417{
 418        struct omap_crtc *omap_crtc =
 419                        container_of(irq, struct omap_crtc, apply_irq);
 420        struct drm_crtc *crtc = &omap_crtc->base;
 421
 422        if (!omap_crtc->error_irq.registered)
 423                omap_irq_register(crtc->dev, &omap_crtc->error_irq);
 424
 425        if (!dispc_mgr_go_busy(omap_crtc->channel)) {
 426                struct omap_drm_private *priv =
 427                                crtc->dev->dev_private;
 428                DBG("%s: apply done", omap_crtc->name);
 429                omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
 430                queue_work(priv->wq, &omap_crtc->apply_work);
 431        }
 432}
 433
 434static void apply_worker(struct work_struct *work)
 435{
 436        struct omap_crtc *omap_crtc =
 437                        container_of(work, struct omap_crtc, apply_work);
 438        struct drm_crtc *crtc = &omap_crtc->base;
 439        struct drm_device *dev = crtc->dev;
 440        struct omap_drm_apply *apply, *n;
 441        bool need_apply;
 442
 443        /*
 444         * Synchronize everything on mode_config.mutex, to keep
 445         * the callbacks and list modification all serialized
 446         * with respect to modesetting ioctls from userspace.
 447         */
 448        mutex_lock(&crtc->mutex);
 449        dispc_runtime_get();
 450
 451        /*
 452         * If we are still pending a previous update, wait.. when the
 453         * pending update completes, we get kicked again.
 454         */
 455        if (omap_crtc->apply_irq.registered)
 456                goto out;
 457
 458        /* finish up previous apply's: */
 459        list_for_each_entry_safe(apply, n,
 460                        &omap_crtc->pending_applies, pending_node) {
 461                apply->post_apply(apply);
 462                list_del(&apply->pending_node);
 463        }
 464
 465        need_apply = !list_empty(&omap_crtc->queued_applies);
 466
 467        /* then handle the next round of of queued apply's: */
 468        list_for_each_entry_safe(apply, n,
 469                        &omap_crtc->queued_applies, queued_node) {
 470                apply->pre_apply(apply);
 471                list_del(&apply->queued_node);
 472                apply->queued = false;
 473                list_add_tail(&apply->pending_node,
 474                                &omap_crtc->pending_applies);
 475        }
 476
 477        if (need_apply) {
 478                enum omap_channel channel = omap_crtc->channel;
 479
 480                DBG("%s: GO", omap_crtc->name);
 481
 482                if (dispc_mgr_is_enabled(channel)) {
 483                        omap_irq_register(dev, &omap_crtc->apply_irq);
 484                        dispc_mgr_go(channel);
 485                } else {
 486                        struct omap_drm_private *priv = dev->dev_private;
 487                        queue_work(priv->wq, &omap_crtc->apply_work);
 488                }
 489        }
 490
 491out:
 492        dispc_runtime_put();
 493        mutex_unlock(&crtc->mutex);
 494}
 495
 496int omap_crtc_apply(struct drm_crtc *crtc,
 497                struct omap_drm_apply *apply)
 498{
 499        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 500
 501        WARN_ON(!mutex_is_locked(&crtc->mutex));
 502
 503        /* no need to queue it again if it is already queued: */
 504        if (apply->queued)
 505                return 0;
 506
 507        apply->queued = true;
 508        list_add_tail(&apply->queued_node, &omap_crtc->queued_applies);
 509
 510        /*
 511         * If there are no currently pending updates, then go ahead and
 512         * kick the worker immediately, otherwise it will run again when
 513         * the current update finishes.
 514         */
 515        if (list_empty(&omap_crtc->pending_applies)) {
 516                struct omap_drm_private *priv = crtc->dev->dev_private;
 517                queue_work(priv->wq, &omap_crtc->apply_work);
 518        }
 519
 520        return 0;
 521}
 522
 523/* called only from apply */
 524static void set_enabled(struct drm_crtc *crtc, bool enable)
 525{
 526        struct drm_device *dev = crtc->dev;
 527        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
 528        enum omap_channel channel = omap_crtc->channel;
 529        struct omap_irq_wait *wait = NULL;
 530
 531        if (dispc_mgr_is_enabled(channel) == enable)
 532                return;
 533
 534        /* ignore sync-lost irqs during enable/disable */
 535        omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
 536
 537        if (dispc_mgr_get_framedone_irq(channel)) {
 538                if (!enable) {
 539                        wait = omap_irq_wait_init(dev,
 540                                        dispc_mgr_get_framedone_irq(channel), 1);
 541                }
 542        } else {
 543                /*
 544                 * When we disable digit output, we need to wait until fields
 545                 * are done.  Otherwise the DSS is still working, and turning
 546                 * off the clocks prevents DSS from going to OFF mode. And when
 547                 * enabling, we need to wait for the extra sync losts
 548                 */
 549                wait = omap_irq_wait_init(dev,
 550                                dispc_mgr_get_vsync_irq(channel), 2);
 551        }
 552
 553        dispc_mgr_enable(channel, enable);
 554
 555        if (wait) {
 556                int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
 557                if (ret) {
 558                        dev_err(dev->dev, "%s: timeout waiting for %s\n",
 559                                        omap_crtc->name, enable ? "enable" : "disable");
 560                }
 561        }
 562
 563        omap_irq_register(crtc->dev, &omap_crtc->error_irq);
 564}
 565
 566static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
 567{
 568        struct omap_crtc *omap_crtc =
 569                        container_of(apply, struct omap_crtc, apply);
 570        struct drm_crtc *crtc = &omap_crtc->base;
 571        struct drm_encoder *encoder = NULL;
 572
 573        DBG("%s: enabled=%d, full=%d", omap_crtc->name,
 574                        omap_crtc->enabled, omap_crtc->full_update);
 575
 576        if (omap_crtc->full_update) {
 577                struct omap_drm_private *priv = crtc->dev->dev_private;
 578                int i;
 579                for (i = 0; i < priv->num_encoders; i++) {
 580                        if (priv->encoders[i]->crtc == crtc) {
 581                                encoder = priv->encoders[i];
 582                                break;
 583                        }
 584                }
 585        }
 586
 587        if (!omap_crtc->enabled) {
 588                set_enabled(&omap_crtc->base, false);
 589                if (encoder)
 590                        omap_encoder_set_enabled(encoder, false);
 591        } else {
 592                if (encoder) {
 593                        omap_encoder_set_enabled(encoder, false);
 594                        omap_encoder_update(encoder, omap_crtc->mgr,
 595                                        &omap_crtc->timings);
 596                        omap_encoder_set_enabled(encoder, true);
 597                        omap_crtc->full_update = false;
 598                }
 599
 600                dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info);
 601                dispc_mgr_set_timings(omap_crtc->channel,
 602                                &omap_crtc->timings);
 603                set_enabled(&omap_crtc->base, true);
 604        }
 605
 606        omap_crtc->full_update = false;
 607}
 608
 609static void omap_crtc_post_apply(struct omap_drm_apply *apply)
 610{
 611        /* nothing needed for post-apply */
 612}
 613
 614static const char *channel_names[] = {
 615                [OMAP_DSS_CHANNEL_LCD] = "lcd",
 616                [OMAP_DSS_CHANNEL_DIGIT] = "tv",
 617                [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
 618};
 619
 620void omap_crtc_pre_init(void)
 621{
 622        dss_install_mgr_ops(&mgr_ops);
 623}
 624
 625/* initialize crtc */
 626struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 627                struct drm_plane *plane, enum omap_channel channel, int id)
 628{
 629        struct drm_crtc *crtc = NULL;
 630        struct omap_crtc *omap_crtc;
 631        struct omap_overlay_manager_info *info;
 632
 633        DBG("%s", channel_names[channel]);
 634
 635        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
 636        if (!omap_crtc)
 637                goto fail;
 638
 639        crtc = &omap_crtc->base;
 640
 641        INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
 642        INIT_WORK(&omap_crtc->apply_work, apply_worker);
 643
 644        INIT_LIST_HEAD(&omap_crtc->pending_applies);
 645        INIT_LIST_HEAD(&omap_crtc->queued_applies);
 646
 647        omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
 648        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 649
 650        omap_crtc->channel = channel;
 651        omap_crtc->plane = plane;
 652        omap_crtc->plane->crtc = crtc;
 653        omap_crtc->name = channel_names[channel];
 654        omap_crtc->pipe = id;
 655
 656        omap_crtc->apply_irq.irqmask = pipe2vbl(crtc);
 657        omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
 658
 659        omap_crtc->error_irq.irqmask =
 660                        dispc_mgr_get_sync_lost_irq(channel);
 661        omap_crtc->error_irq.irq = omap_crtc_error_irq;
 662        omap_irq_register(dev, &omap_crtc->error_irq);
 663
 664        /* temporary: */
 665        omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
 666
 667        /* TODO: fix hard-coded setup.. add properties! */
 668        info = &omap_crtc->info;
 669        info->default_color = 0x00000000;
 670        info->trans_key = 0x00000000;
 671        info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
 672        info->trans_enabled = false;
 673
 674        drm_crtc_init(dev, crtc, &omap_crtc_funcs);
 675        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 676
 677        omap_plane_install_properties(omap_crtc->plane, &crtc->base);
 678
 679        omap_crtcs[channel] = omap_crtc;
 680
 681        return crtc;
 682
 683fail:
 684        if (crtc)
 685                omap_crtc_destroy(crtc);
 686
 687        return NULL;
 688}
 689