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                 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
 365static 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
 379static 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
 386static 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
 395const 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
 401enum 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
 407static 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
 417static 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
 435static 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
 492out:
 493        dispc_runtime_put();
 494        mutex_unlock(&crtc->mutex);
 495}
 496
 497int 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 */
 525static 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
 567static 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
 610static void omap_crtc_post_apply(struct omap_drm_apply *apply)
 611{
 612        /* nothing needed for post-apply */
 613}
 614
 615static const char *channel_names[] = {
 616                [OMAP_DSS_CHANNEL_LCD] = "lcd",
 617                [OMAP_DSS_CHANNEL_DIGIT] = "tv",
 618                [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
 619};
 620
 621void omap_crtc_pre_init(void)
 622{
 623        dss_install_mgr_ops(&mgr_ops);
 624}
 625
 626void omap_crtc_pre_uninit(void)
 627{
 628        dss_uninstall_mgr_ops();
 629}
 630
 631/* initialize crtc */
 632struct drm_crtc *omap_crtc_init(struct drm_device *dev,
 633                struct drm_plane *plane, enum omap_channel channel, int id)
 634{
 635        struct drm_crtc *crtc = NULL;
 636        struct omap_crtc *omap_crtc;
 637        struct omap_overlay_manager_info *info;
 638
 639        DBG("%s", channel_names[channel]);
 640
 641        omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL);
 642        if (!omap_crtc)
 643                goto fail;
 644
 645        crtc = &omap_crtc->base;
 646
 647        INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker);
 648        INIT_WORK(&omap_crtc->apply_work, apply_worker);
 649
 650        INIT_LIST_HEAD(&omap_crtc->pending_applies);
 651        INIT_LIST_HEAD(&omap_crtc->queued_applies);
 652
 653        omap_crtc->apply.pre_apply  = omap_crtc_pre_apply;
 654        omap_crtc->apply.post_apply = omap_crtc_post_apply;
 655
 656        omap_crtc->channel = channel;
 657        omap_crtc->plane = plane;
 658        omap_crtc->plane->crtc = crtc;
 659        omap_crtc->name = channel_names[channel];
 660        omap_crtc->pipe = id;
 661
 662        omap_crtc->apply_irq.irqmask = pipe2vbl(crtc);
 663        omap_crtc->apply_irq.irq = omap_crtc_apply_irq;
 664
 665        omap_crtc->error_irq.irqmask =
 666                        dispc_mgr_get_sync_lost_irq(channel);
 667        omap_crtc->error_irq.irq = omap_crtc_error_irq;
 668        omap_irq_register(dev, &omap_crtc->error_irq);
 669
 670        /* temporary: */
 671        omap_crtc->mgr = omap_dss_get_overlay_manager(channel);
 672
 673        /* TODO: fix hard-coded setup.. add properties! */
 674        info = &omap_crtc->info;
 675        info->default_color = 0x00000000;
 676        info->trans_key = 0x00000000;
 677        info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
 678        info->trans_enabled = false;
 679
 680        drm_crtc_init(dev, crtc, &omap_crtc_funcs);
 681        drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs);
 682
 683        omap_plane_install_properties(omap_crtc->plane, &crtc->base);
 684
 685        omap_crtcs[channel] = omap_crtc;
 686
 687        return crtc;
 688
 689fail:
 690        if (crtc)
 691                omap_crtc_destroy(crtc);
 692
 693        return NULL;
 694}
 695