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/drm_plane_helper.h> 24 #include "drm_crtc.h" 25 #include "drm_crtc_helper.h" 26 27 #define to_omap_crtc(x) container_of(x, struct omap_crtc, base) 28 29 struct omap_crtc { 30 struct drm_crtc base; 31 32 const char *name; 33 int pipe; 34 enum omap_channel channel; 35 struct omap_overlay_manager_info info; 36 struct drm_encoder *current_encoder; 37 38 /* 39 * Temporary: eventually this will go away, but it is needed 40 * for now to keep the output's happy. (They only need 41 * mgr->id.) Eventually this will be replaced w/ something 42 * more common-panel-framework-y 43 */ 44 struct omap_overlay_manager *mgr; 45 46 struct omap_video_timings timings; 47 bool enabled; 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 bool ignore_digit_sync_lost; 77 }; 78 79 /* ----------------------------------------------------------------------------- 80 * Helper Functions 81 */ 82 83 uint32_t pipe2vbl(struct drm_crtc *crtc) 84 { 85 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 86 87 return dispc_mgr_get_vsync_irq(omap_crtc->channel); 88 } 89 90 const struct omap_video_timings *omap_crtc_timings(struct drm_crtc *crtc) 91 { 92 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 93 return &omap_crtc->timings; 94 } 95 96 enum omap_channel omap_crtc_channel(struct drm_crtc *crtc) 97 { 98 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 99 return omap_crtc->channel; 100 } 101 102 /* ----------------------------------------------------------------------------- 103 * DSS Manager Functions 104 */ 105 106 /* 107 * Manager-ops, callbacks from output when they need to configure 108 * the upstream part of the video pipe. 109 * 110 * Most of these we can ignore until we add support for command-mode 111 * panels.. for video-mode the crtc-helpers already do an adequate 112 * job of sequencing the setup of the video pipe in the proper order 113 */ 114 115 /* ovl-mgr-id -> crtc */ 116 static struct omap_crtc *omap_crtcs[8]; 117 118 /* we can probably ignore these until we support command-mode panels: */ 119 static int omap_crtc_connect(struct omap_overlay_manager *mgr, 120 struct omap_dss_device *dst) 121 { 122 if (mgr->output) 123 return -EINVAL; 124 125 if ((mgr->supported_outputs & dst->id) == 0) 126 return -EINVAL; 127 128 dst->manager = mgr; 129 mgr->output = dst; 130 131 return 0; 132 } 133 134 static void omap_crtc_disconnect(struct omap_overlay_manager *mgr, 135 struct omap_dss_device *dst) 136 { 137 mgr->output->manager = NULL; 138 mgr->output = NULL; 139 } 140 141 static void omap_crtc_start_update(struct omap_overlay_manager *mgr) 142 { 143 } 144 145 /* Called only from CRTC pre_apply and suspend/resume handlers. */ 146 static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable) 147 { 148 struct drm_device *dev = crtc->dev; 149 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 150 enum omap_channel channel = omap_crtc->channel; 151 struct omap_irq_wait *wait; 152 u32 framedone_irq, vsync_irq; 153 int ret; 154 155 if (dispc_mgr_is_enabled(channel) == enable) 156 return; 157 158 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { 159 /* 160 * Digit output produces some sync lost interrupts during the 161 * first frame when enabling, so we need to ignore those. 162 */ 163 omap_crtc->ignore_digit_sync_lost = true; 164 } 165 166 framedone_irq = dispc_mgr_get_framedone_irq(channel); 167 vsync_irq = dispc_mgr_get_vsync_irq(channel); 168 169 if (enable) { 170 wait = omap_irq_wait_init(dev, vsync_irq, 1); 171 } else { 172 /* 173 * When we disable the digit output, we need to wait for 174 * FRAMEDONE to know that DISPC has finished with the output. 175 * 176 * OMAP2/3 does not have FRAMEDONE irq for digit output, and in 177 * that case we need to use vsync interrupt, and wait for both 178 * even and odd frames. 179 */ 180 181 if (framedone_irq) 182 wait = omap_irq_wait_init(dev, framedone_irq, 1); 183 else 184 wait = omap_irq_wait_init(dev, vsync_irq, 2); 185 } 186 187 dispc_mgr_enable(channel, enable); 188 189 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); 190 if (ret) { 191 dev_err(dev->dev, "%s: timeout waiting for %s\n", 192 omap_crtc->name, enable ? "enable" : "disable"); 193 } 194 195 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { 196 omap_crtc->ignore_digit_sync_lost = false; 197 /* make sure the irq handler sees the value above */ 198 mb(); 199 } 200 } 201 202 203 static int omap_crtc_enable(struct omap_overlay_manager *mgr) 204 { 205 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; 206 207 dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); 208 dispc_mgr_set_timings(omap_crtc->channel, 209 &omap_crtc->timings); 210 omap_crtc_set_enabled(&omap_crtc->base, true); 211 212 return 0; 213 } 214 215 static void omap_crtc_disable(struct omap_overlay_manager *mgr) 216 { 217 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; 218 219 omap_crtc_set_enabled(&omap_crtc->base, false); 220 } 221 222 static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, 223 const struct omap_video_timings *timings) 224 { 225 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; 226 DBG("%s", omap_crtc->name); 227 omap_crtc->timings = *timings; 228 } 229 230 static void omap_crtc_set_lcd_config(struct omap_overlay_manager *mgr, 231 const struct dss_lcd_mgr_config *config) 232 { 233 struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; 234 DBG("%s", omap_crtc->name); 235 dispc_mgr_set_lcd_config(omap_crtc->channel, config); 236 } 237 238 static int omap_crtc_register_framedone_handler( 239 struct omap_overlay_manager *mgr, 240 void (*handler)(void *), void *data) 241 { 242 return 0; 243 } 244 245 static void omap_crtc_unregister_framedone_handler( 246 struct omap_overlay_manager *mgr, 247 void (*handler)(void *), void *data) 248 { 249 } 250 251 static const struct dss_mgr_ops mgr_ops = { 252 .connect = omap_crtc_connect, 253 .disconnect = omap_crtc_disconnect, 254 .start_update = omap_crtc_start_update, 255 .enable = omap_crtc_enable, 256 .disable = omap_crtc_disable, 257 .set_timings = omap_crtc_set_timings, 258 .set_lcd_config = omap_crtc_set_lcd_config, 259 .register_framedone_handler = omap_crtc_register_framedone_handler, 260 .unregister_framedone_handler = omap_crtc_unregister_framedone_handler, 261 }; 262 263 /* ----------------------------------------------------------------------------- 264 * Apply Logic 265 */ 266 267 static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 268 { 269 struct omap_crtc *omap_crtc = 270 container_of(irq, struct omap_crtc, error_irq); 271 272 if (omap_crtc->ignore_digit_sync_lost) { 273 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT; 274 if (!irqstatus) 275 return; 276 } 277 278 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); 279 } 280 281 static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 282 { 283 struct omap_crtc *omap_crtc = 284 container_of(irq, struct omap_crtc, apply_irq); 285 struct drm_crtc *crtc = &omap_crtc->base; 286 287 if (!dispc_mgr_go_busy(omap_crtc->channel)) { 288 struct omap_drm_private *priv = 289 crtc->dev->dev_private; 290 DBG("%s: apply done", omap_crtc->name); 291 __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq); 292 queue_work(priv->wq, &omap_crtc->apply_work); 293 } 294 } 295 296 static void apply_worker(struct work_struct *work) 297 { 298 struct omap_crtc *omap_crtc = 299 container_of(work, struct omap_crtc, apply_work); 300 struct drm_crtc *crtc = &omap_crtc->base; 301 struct drm_device *dev = crtc->dev; 302 struct omap_drm_apply *apply, *n; 303 bool need_apply; 304 305 /* 306 * Synchronize everything on mode_config.mutex, to keep 307 * the callbacks and list modification all serialized 308 * with respect to modesetting ioctls from userspace. 309 */ 310 drm_modeset_lock(&crtc->mutex, NULL); 311 dispc_runtime_get(); 312 313 /* 314 * If we are still pending a previous update, wait.. when the 315 * pending update completes, we get kicked again. 316 */ 317 if (omap_crtc->apply_irq.registered) 318 goto out; 319 320 /* finish up previous apply's: */ 321 list_for_each_entry_safe(apply, n, 322 &omap_crtc->pending_applies, pending_node) { 323 apply->post_apply(apply); 324 list_del(&apply->pending_node); 325 } 326 327 need_apply = !list_empty(&omap_crtc->queued_applies); 328 329 /* then handle the next round of of queued apply's: */ 330 list_for_each_entry_safe(apply, n, 331 &omap_crtc->queued_applies, queued_node) { 332 apply->pre_apply(apply); 333 list_del(&apply->queued_node); 334 apply->queued = false; 335 list_add_tail(&apply->pending_node, 336 &omap_crtc->pending_applies); 337 } 338 339 if (need_apply) { 340 enum omap_channel channel = omap_crtc->channel; 341 342 DBG("%s: GO", omap_crtc->name); 343 344 if (dispc_mgr_is_enabled(channel)) { 345 dispc_mgr_go(channel); 346 omap_irq_register(dev, &omap_crtc->apply_irq); 347 } else { 348 struct omap_drm_private *priv = dev->dev_private; 349 queue_work(priv->wq, &omap_crtc->apply_work); 350 } 351 } 352 353 out: 354 dispc_runtime_put(); 355 drm_modeset_unlock(&crtc->mutex); 356 } 357 358 int omap_crtc_apply(struct drm_crtc *crtc, 359 struct omap_drm_apply *apply) 360 { 361 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 362 363 WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 364 365 /* no need to queue it again if it is already queued: */ 366 if (apply->queued) 367 return 0; 368 369 apply->queued = true; 370 list_add_tail(&apply->queued_node, &omap_crtc->queued_applies); 371 372 /* 373 * If there are no currently pending updates, then go ahead and 374 * kick the worker immediately, otherwise it will run again when 375 * the current update finishes. 376 */ 377 if (list_empty(&omap_crtc->pending_applies)) { 378 struct omap_drm_private *priv = crtc->dev->dev_private; 379 queue_work(priv->wq, &omap_crtc->apply_work); 380 } 381 382 return 0; 383 } 384 385 static void omap_crtc_pre_apply(struct omap_drm_apply *apply) 386 { 387 struct omap_crtc *omap_crtc = 388 container_of(apply, struct omap_crtc, apply); 389 struct drm_crtc *crtc = &omap_crtc->base; 390 struct omap_drm_private *priv = crtc->dev->dev_private; 391 struct drm_encoder *encoder = NULL; 392 unsigned int i; 393 394 DBG("%s: enabled=%d", omap_crtc->name, omap_crtc->enabled); 395 396 for (i = 0; i < priv->num_encoders; i++) { 397 if (priv->encoders[i]->crtc == crtc) { 398 encoder = priv->encoders[i]; 399 break; 400 } 401 } 402 403 if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder) 404 omap_encoder_set_enabled(omap_crtc->current_encoder, false); 405 406 omap_crtc->current_encoder = encoder; 407 408 if (!omap_crtc->enabled) { 409 if (encoder) 410 omap_encoder_set_enabled(encoder, false); 411 } else { 412 if (encoder) { 413 omap_encoder_set_enabled(encoder, false); 414 omap_encoder_update(encoder, omap_crtc->mgr, 415 &omap_crtc->timings); 416 omap_encoder_set_enabled(encoder, true); 417 } 418 } 419 } 420 421 static void omap_crtc_post_apply(struct omap_drm_apply *apply) 422 { 423 /* nothing needed for post-apply */ 424 } 425 426 void omap_crtc_flush(struct drm_crtc *crtc) 427 { 428 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 429 int loops = 0; 430 431 while (!list_empty(&omap_crtc->pending_applies) || 432 !list_empty(&omap_crtc->queued_applies) || 433 omap_crtc->event || omap_crtc->old_fb) { 434 435 if (++loops > 10) { 436 dev_err(crtc->dev->dev, 437 "omap_crtc_flush() timeout\n"); 438 break; 439 } 440 441 schedule_timeout_uninterruptible(msecs_to_jiffies(20)); 442 } 443 } 444 445 /* ----------------------------------------------------------------------------- 446 * CRTC Functions 447 */ 448 449 static void omap_crtc_destroy(struct drm_crtc *crtc) 450 { 451 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 452 453 DBG("%s", omap_crtc->name); 454 455 WARN_ON(omap_crtc->apply_irq.registered); 456 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); 457 458 drm_crtc_cleanup(crtc); 459 460 kfree(omap_crtc); 461 } 462 463 static void omap_crtc_dpms(struct drm_crtc *crtc, int mode) 464 { 465 struct omap_drm_private *priv = crtc->dev->dev_private; 466 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 467 bool enabled = (mode == DRM_MODE_DPMS_ON); 468 int i; 469 470 DBG("%s: %d", omap_crtc->name, mode); 471 472 if (enabled != omap_crtc->enabled) { 473 omap_crtc->enabled = enabled; 474 omap_crtc_apply(crtc, &omap_crtc->apply); 475 476 /* Enable/disable all planes associated with the CRTC. */ 477 for (i = 0; i < priv->num_planes; i++) { 478 struct drm_plane *plane = priv->planes[i]; 479 if (plane->crtc == crtc) 480 WARN_ON(omap_plane_set_enable(plane, enabled)); 481 } 482 } 483 } 484 485 static bool omap_crtc_mode_fixup(struct drm_crtc *crtc, 486 const struct drm_display_mode *mode, 487 struct drm_display_mode *adjusted_mode) 488 { 489 return true; 490 } 491 492 static int omap_crtc_mode_set(struct drm_crtc *crtc, 493 struct drm_display_mode *mode, 494 struct drm_display_mode *adjusted_mode, 495 int x, int y, 496 struct drm_framebuffer *old_fb) 497 { 498 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 499 500 mode = adjusted_mode; 501 502 DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", 503 omap_crtc->name, mode->base.id, mode->name, 504 mode->vrefresh, mode->clock, 505 mode->hdisplay, mode->hsync_start, 506 mode->hsync_end, mode->htotal, 507 mode->vdisplay, mode->vsync_start, 508 mode->vsync_end, mode->vtotal, 509 mode->type, mode->flags); 510 511 copy_timings_drm_to_omap(&omap_crtc->timings, mode); 512 513 /* 514 * The primary plane CRTC can be reset if the plane is disabled directly 515 * through the universal plane API. Set it again here. 516 */ 517 crtc->primary->crtc = crtc; 518 519 return omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb, 520 0, 0, mode->hdisplay, mode->vdisplay, 521 x, y, mode->hdisplay, mode->vdisplay, 522 NULL, NULL); 523 } 524 525 static void omap_crtc_prepare(struct drm_crtc *crtc) 526 { 527 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 528 DBG("%s", omap_crtc->name); 529 omap_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 530 } 531 532 static void omap_crtc_commit(struct drm_crtc *crtc) 533 { 534 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 535 DBG("%s", omap_crtc->name); 536 omap_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 537 } 538 539 static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 540 struct drm_framebuffer *old_fb) 541 { 542 struct drm_plane *plane = crtc->primary; 543 struct drm_display_mode *mode = &crtc->mode; 544 545 return omap_plane_mode_set(plane, crtc, crtc->primary->fb, 546 0, 0, mode->hdisplay, mode->vdisplay, 547 x, y, mode->hdisplay, mode->vdisplay, 548 NULL, NULL); 549 } 550 551 static void vblank_cb(void *arg) 552 { 553 struct drm_crtc *crtc = arg; 554 struct drm_device *dev = crtc->dev; 555 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 556 unsigned long flags; 557 struct drm_framebuffer *fb; 558 559 spin_lock_irqsave(&dev->event_lock, flags); 560 561 /* wakeup userspace */ 562 if (omap_crtc->event) 563 drm_send_vblank_event(dev, omap_crtc->pipe, omap_crtc->event); 564 565 fb = omap_crtc->old_fb; 566 567 omap_crtc->event = NULL; 568 omap_crtc->old_fb = NULL; 569 570 spin_unlock_irqrestore(&dev->event_lock, flags); 571 572 if (fb) 573 drm_framebuffer_unreference(fb); 574 } 575 576 static void page_flip_worker(struct work_struct *work) 577 { 578 struct omap_crtc *omap_crtc = 579 container_of(work, struct omap_crtc, page_flip_work); 580 struct drm_crtc *crtc = &omap_crtc->base; 581 struct drm_display_mode *mode = &crtc->mode; 582 struct drm_gem_object *bo; 583 584 drm_modeset_lock(&crtc->mutex, NULL); 585 omap_plane_mode_set(crtc->primary, crtc, crtc->primary->fb, 586 0, 0, mode->hdisplay, mode->vdisplay, 587 crtc->x, crtc->y, mode->hdisplay, mode->vdisplay, 588 vblank_cb, crtc); 589 drm_modeset_unlock(&crtc->mutex); 590 591 bo = omap_framebuffer_bo(crtc->primary->fb, 0); 592 drm_gem_object_unreference_unlocked(bo); 593 } 594 595 static void page_flip_cb(void *arg) 596 { 597 struct drm_crtc *crtc = arg; 598 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 599 struct omap_drm_private *priv = crtc->dev->dev_private; 600 601 /* avoid assumptions about what ctxt we are called from: */ 602 queue_work(priv->wq, &omap_crtc->page_flip_work); 603 } 604 605 static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, 606 struct drm_framebuffer *fb, 607 struct drm_pending_vblank_event *event, 608 uint32_t page_flip_flags) 609 { 610 struct drm_device *dev = crtc->dev; 611 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 612 struct drm_plane *primary = crtc->primary; 613 struct drm_gem_object *bo; 614 unsigned long flags; 615 616 DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1, 617 fb->base.id, event); 618 619 spin_lock_irqsave(&dev->event_lock, flags); 620 621 if (omap_crtc->old_fb) { 622 spin_unlock_irqrestore(&dev->event_lock, flags); 623 dev_err(dev->dev, "already a pending flip\n"); 624 return -EBUSY; 625 } 626 627 omap_crtc->event = event; 628 omap_crtc->old_fb = primary->fb = fb; 629 drm_framebuffer_reference(omap_crtc->old_fb); 630 631 spin_unlock_irqrestore(&dev->event_lock, flags); 632 633 /* 634 * Hold a reference temporarily until the crtc is updated 635 * and takes the reference to the bo. This avoids it 636 * getting freed from under us: 637 */ 638 bo = omap_framebuffer_bo(fb, 0); 639 drm_gem_object_reference(bo); 640 641 omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc); 642 643 return 0; 644 } 645 646 static int omap_crtc_set_property(struct drm_crtc *crtc, 647 struct drm_property *property, uint64_t val) 648 { 649 struct omap_drm_private *priv = crtc->dev->dev_private; 650 651 if (property == priv->rotation_prop) { 652 crtc->invert_dimensions = 653 !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); 654 } 655 656 return omap_plane_set_property(crtc->primary, property, val); 657 } 658 659 static const struct drm_crtc_funcs omap_crtc_funcs = { 660 .set_config = drm_crtc_helper_set_config, 661 .destroy = omap_crtc_destroy, 662 .page_flip = omap_crtc_page_flip_locked, 663 .set_property = omap_crtc_set_property, 664 }; 665 666 static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { 667 .dpms = omap_crtc_dpms, 668 .mode_fixup = omap_crtc_mode_fixup, 669 .mode_set = omap_crtc_mode_set, 670 .prepare = omap_crtc_prepare, 671 .commit = omap_crtc_commit, 672 .mode_set_base = omap_crtc_mode_set_base, 673 }; 674 675 /* ----------------------------------------------------------------------------- 676 * Init and Cleanup 677 */ 678 679 static const char *channel_names[] = { 680 [OMAP_DSS_CHANNEL_LCD] = "lcd", 681 [OMAP_DSS_CHANNEL_DIGIT] = "tv", 682 [OMAP_DSS_CHANNEL_LCD2] = "lcd2", 683 [OMAP_DSS_CHANNEL_LCD3] = "lcd3", 684 }; 685 686 void omap_crtc_pre_init(void) 687 { 688 dss_install_mgr_ops(&mgr_ops); 689 } 690 691 void omap_crtc_pre_uninit(void) 692 { 693 dss_uninstall_mgr_ops(); 694 } 695 696 /* initialize crtc */ 697 struct drm_crtc *omap_crtc_init(struct drm_device *dev, 698 struct drm_plane *plane, enum omap_channel channel, int id) 699 { 700 struct drm_crtc *crtc = NULL; 701 struct omap_crtc *omap_crtc; 702 struct omap_overlay_manager_info *info; 703 int ret; 704 705 DBG("%s", channel_names[channel]); 706 707 omap_crtc = kzalloc(sizeof(*omap_crtc), GFP_KERNEL); 708 if (!omap_crtc) 709 return NULL; 710 711 crtc = &omap_crtc->base; 712 713 INIT_WORK(&omap_crtc->page_flip_work, page_flip_worker); 714 INIT_WORK(&omap_crtc->apply_work, apply_worker); 715 716 INIT_LIST_HEAD(&omap_crtc->pending_applies); 717 INIT_LIST_HEAD(&omap_crtc->queued_applies); 718 719 omap_crtc->apply.pre_apply = omap_crtc_pre_apply; 720 omap_crtc->apply.post_apply = omap_crtc_post_apply; 721 722 omap_crtc->channel = channel; 723 omap_crtc->name = channel_names[channel]; 724 omap_crtc->pipe = id; 725 726 omap_crtc->apply_irq.irqmask = pipe2vbl(crtc); 727 omap_crtc->apply_irq.irq = omap_crtc_apply_irq; 728 729 omap_crtc->error_irq.irqmask = 730 dispc_mgr_get_sync_lost_irq(channel); 731 omap_crtc->error_irq.irq = omap_crtc_error_irq; 732 omap_irq_register(dev, &omap_crtc->error_irq); 733 734 /* temporary: */ 735 omap_crtc->mgr = omap_dss_get_overlay_manager(channel); 736 737 /* TODO: fix hard-coded setup.. add properties! */ 738 info = &omap_crtc->info; 739 info->default_color = 0x00000000; 740 info->trans_key = 0x00000000; 741 info->trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST; 742 info->trans_enabled = false; 743 744 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 745 &omap_crtc_funcs); 746 if (ret < 0) { 747 kfree(omap_crtc); 748 return NULL; 749 } 750 751 drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); 752 753 omap_plane_install_properties(crtc->primary, &crtc->base); 754 755 omap_crtcs[channel] = omap_crtc; 756 757 return crtc; 758 } 759