Commit d62c3e7a73f87defb17651109a55d36adedadc6f
Exists in
master
and in
13 other branches
Merge tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/…
…tomba/linux into drm-next Fixes for omapdrm, some of which were already present in 3.14, and some which appeared in 3.15-rc1: - fixes for primary-plane handling which caused crashes - fix all kinds of uninit issues which prevented from unloading the omapdrm module. - fixes for HDMI enable/disable issues * tag 'omapdrm-fixes-3.15' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: drm/omap: fix the handling of fb ref counts drm/omap: protect omap_crtc's event with event_lock spinlock drm/omap: Use old_fb to synchronize between successive page flips drm/omap: Fix crash when using LCD3 overlay manager drm/omap: gem sync: wait on correct events drm/omap: Fix memory leak in omap_gem_op_async drm/omap: remove warn from debugfs drm/omap: remove extra plane->destroy from crtc destroy drm/omap: print warning when rotating non-TILER fb drm/omap: fix missing unref to fb's buf object drm/omap: fix plane rotation drm/omap: fix enabling/disabling of video pipeline drm/omap: fix missing disable for unused encoder drm/omap: fix race issue when unloading omapdrm drm/omap: fix DMM driver (un)registration drm/omap: fix uninit order in pdev_remove() drm/omap: fix output enable/disable sequence
Showing 7 changed files Side-by-side Diff
drivers/gpu/drm/omapdrm/omap_crtc.c
... | ... | @@ -33,6 +33,7 @@ |
33 | 33 | int pipe; |
34 | 34 | enum omap_channel channel; |
35 | 35 | struct omap_overlay_manager_info info; |
36 | + struct drm_encoder *current_encoder; | |
36 | 37 | |
37 | 38 | /* |
38 | 39 | * Temporary: eventually this will go away, but it is needed |
39 | 40 | |
40 | 41 | |
... | ... | @@ -120,13 +121,25 @@ |
120 | 121 | { |
121 | 122 | } |
122 | 123 | |
124 | +static void set_enabled(struct drm_crtc *crtc, bool enable); | |
125 | + | |
123 | 126 | static int omap_crtc_enable(struct omap_overlay_manager *mgr) |
124 | 127 | { |
128 | + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; | |
129 | + | |
130 | + dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); | |
131 | + dispc_mgr_set_timings(omap_crtc->channel, | |
132 | + &omap_crtc->timings); | |
133 | + set_enabled(&omap_crtc->base, true); | |
134 | + | |
125 | 135 | return 0; |
126 | 136 | } |
127 | 137 | |
128 | 138 | static void omap_crtc_disable(struct omap_overlay_manager *mgr) |
129 | 139 | { |
140 | + struct omap_crtc *omap_crtc = omap_crtcs[mgr->id]; | |
141 | + | |
142 | + set_enabled(&omap_crtc->base, false); | |
130 | 143 | } |
131 | 144 | |
132 | 145 | static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, |
... | ... | @@ -184,7 +197,6 @@ |
184 | 197 | WARN_ON(omap_crtc->apply_irq.registered); |
185 | 198 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); |
186 | 199 | |
187 | - omap_crtc->plane->funcs->destroy(omap_crtc->plane); | |
188 | 200 | drm_crtc_cleanup(crtc); |
189 | 201 | |
190 | 202 | kfree(omap_crtc); |
191 | 203 | |
192 | 204 | |
193 | 205 | |
194 | 206 | |
... | ... | @@ -338,18 +350,24 @@ |
338 | 350 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
339 | 351 | struct drm_plane *primary = crtc->primary; |
340 | 352 | struct drm_gem_object *bo; |
353 | + unsigned long flags; | |
341 | 354 | |
342 | 355 | DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1, |
343 | 356 | fb->base.id, event); |
344 | 357 | |
358 | + spin_lock_irqsave(&dev->event_lock, flags); | |
359 | + | |
345 | 360 | if (omap_crtc->old_fb) { |
361 | + spin_unlock_irqrestore(&dev->event_lock, flags); | |
346 | 362 | dev_err(dev->dev, "already a pending flip\n"); |
347 | 363 | return -EINVAL; |
348 | 364 | } |
349 | 365 | |
350 | 366 | omap_crtc->event = event; |
351 | - primary->fb = fb; | |
367 | + omap_crtc->old_fb = primary->fb = fb; | |
352 | 368 | |
369 | + spin_unlock_irqrestore(&dev->event_lock, flags); | |
370 | + | |
353 | 371 | /* |
354 | 372 | * Hold a reference temporarily until the crtc is updated |
355 | 373 | * and takes the reference to the bo. This avoids it |
356 | 374 | |
357 | 375 | |
358 | 376 | |
359 | 377 | |
360 | 378 | |
... | ... | @@ -528,38 +546,46 @@ |
528 | 546 | struct drm_device *dev = crtc->dev; |
529 | 547 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
530 | 548 | enum omap_channel channel = omap_crtc->channel; |
531 | - struct omap_irq_wait *wait = NULL; | |
549 | + struct omap_irq_wait *wait; | |
550 | + u32 framedone_irq, vsync_irq; | |
551 | + int ret; | |
532 | 552 | |
533 | 553 | if (dispc_mgr_is_enabled(channel) == enable) |
534 | 554 | return; |
535 | 555 | |
536 | - /* ignore sync-lost irqs during enable/disable */ | |
556 | + /* | |
557 | + * Digit output produces some sync lost interrupts during the first | |
558 | + * frame when enabling, so we need to ignore those. | |
559 | + */ | |
537 | 560 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); |
538 | 561 | |
539 | - if (dispc_mgr_get_framedone_irq(channel)) { | |
540 | - if (!enable) { | |
541 | - wait = omap_irq_wait_init(dev, | |
542 | - dispc_mgr_get_framedone_irq(channel), 1); | |
543 | - } | |
562 | + framedone_irq = dispc_mgr_get_framedone_irq(channel); | |
563 | + vsync_irq = dispc_mgr_get_vsync_irq(channel); | |
564 | + | |
565 | + if (enable) { | |
566 | + wait = omap_irq_wait_init(dev, vsync_irq, 1); | |
544 | 567 | } else { |
545 | 568 | /* |
546 | - * When we disable digit output, we need to wait until fields | |
547 | - * are done. Otherwise the DSS is still working, and turning | |
548 | - * off the clocks prevents DSS from going to OFF mode. And when | |
549 | - * enabling, we need to wait for the extra sync losts | |
569 | + * When we disable the digit output, we need to wait for | |
570 | + * FRAMEDONE to know that DISPC has finished with the output. | |
571 | + * | |
572 | + * OMAP2/3 does not have FRAMEDONE irq for digit output, and in | |
573 | + * that case we need to use vsync interrupt, and wait for both | |
574 | + * even and odd frames. | |
550 | 575 | */ |
551 | - wait = omap_irq_wait_init(dev, | |
552 | - dispc_mgr_get_vsync_irq(channel), 2); | |
576 | + | |
577 | + if (framedone_irq) | |
578 | + wait = omap_irq_wait_init(dev, framedone_irq, 1); | |
579 | + else | |
580 | + wait = omap_irq_wait_init(dev, vsync_irq, 2); | |
553 | 581 | } |
554 | 582 | |
555 | 583 | dispc_mgr_enable(channel, enable); |
556 | 584 | |
557 | - if (wait) { | |
558 | - int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | |
559 | - if (ret) { | |
560 | - dev_err(dev->dev, "%s: timeout waiting for %s\n", | |
561 | - omap_crtc->name, enable ? "enable" : "disable"); | |
562 | - } | |
585 | + ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | |
586 | + if (ret) { | |
587 | + dev_err(dev->dev, "%s: timeout waiting for %s\n", | |
588 | + omap_crtc->name, enable ? "enable" : "disable"); | |
563 | 589 | } |
564 | 590 | |
565 | 591 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); |
566 | 592 | |
... | ... | @@ -586,8 +612,12 @@ |
586 | 612 | } |
587 | 613 | } |
588 | 614 | |
615 | + if (omap_crtc->current_encoder && encoder != omap_crtc->current_encoder) | |
616 | + omap_encoder_set_enabled(omap_crtc->current_encoder, false); | |
617 | + | |
618 | + omap_crtc->current_encoder = encoder; | |
619 | + | |
589 | 620 | if (!omap_crtc->enabled) { |
590 | - set_enabled(&omap_crtc->base, false); | |
591 | 621 | if (encoder) |
592 | 622 | omap_encoder_set_enabled(encoder, false); |
593 | 623 | } else { |
594 | 624 | |
... | ... | @@ -596,13 +626,7 @@ |
596 | 626 | omap_encoder_update(encoder, omap_crtc->mgr, |
597 | 627 | &omap_crtc->timings); |
598 | 628 | omap_encoder_set_enabled(encoder, true); |
599 | - omap_crtc->full_update = false; | |
600 | 629 | } |
601 | - | |
602 | - dispc_mgr_setup(omap_crtc->channel, &omap_crtc->info); | |
603 | - dispc_mgr_set_timings(omap_crtc->channel, | |
604 | - &omap_crtc->timings); | |
605 | - set_enabled(&omap_crtc->base, true); | |
606 | 630 | } |
607 | 631 | |
608 | 632 | omap_crtc->full_update = false; |
609 | 633 | |
... | ... | @@ -613,10 +637,30 @@ |
613 | 637 | /* nothing needed for post-apply */ |
614 | 638 | } |
615 | 639 | |
640 | +void omap_crtc_flush(struct drm_crtc *crtc) | |
641 | +{ | |
642 | + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | |
643 | + int loops = 0; | |
644 | + | |
645 | + while (!list_empty(&omap_crtc->pending_applies) || | |
646 | + !list_empty(&omap_crtc->queued_applies) || | |
647 | + omap_crtc->event || omap_crtc->old_fb) { | |
648 | + | |
649 | + if (++loops > 10) { | |
650 | + dev_err(crtc->dev->dev, | |
651 | + "omap_crtc_flush() timeout\n"); | |
652 | + break; | |
653 | + } | |
654 | + | |
655 | + schedule_timeout_uninterruptible(msecs_to_jiffies(20)); | |
656 | + } | |
657 | +} | |
658 | + | |
616 | 659 | static const char *channel_names[] = { |
617 | 660 | [OMAP_DSS_CHANNEL_LCD] = "lcd", |
618 | 661 | [OMAP_DSS_CHANNEL_DIGIT] = "tv", |
619 | 662 | [OMAP_DSS_CHANNEL_LCD2] = "lcd2", |
663 | + [OMAP_DSS_CHANNEL_LCD3] = "lcd3", | |
620 | 664 | }; |
621 | 665 | |
622 | 666 | void omap_crtc_pre_init(void) |
drivers/gpu/drm/omapdrm/omap_drv.c
... | ... | @@ -513,12 +513,18 @@ |
513 | 513 | static int dev_unload(struct drm_device *dev) |
514 | 514 | { |
515 | 515 | struct omap_drm_private *priv = dev->dev_private; |
516 | + int i; | |
516 | 517 | |
517 | 518 | DBG("unload: dev=%p", dev); |
518 | 519 | |
519 | 520 | drm_kms_helper_poll_fini(dev); |
520 | 521 | |
521 | 522 | omap_fbdev_free(dev); |
523 | + | |
524 | + /* flush crtcs so the fbs get released */ | |
525 | + for (i = 0; i < priv->num_crtcs; i++) | |
526 | + omap_crtc_flush(priv->crtcs[i]); | |
527 | + | |
522 | 528 | omap_modeset_free(dev); |
523 | 529 | omap_gem_deinit(dev); |
524 | 530 | |
525 | 531 | |
... | ... | @@ -696,10 +702,11 @@ |
696 | 702 | { |
697 | 703 | DBG(""); |
698 | 704 | |
705 | + drm_put_dev(platform_get_drvdata(device)); | |
706 | + | |
699 | 707 | omap_disconnect_dssdevs(); |
700 | 708 | omap_crtc_pre_uninit(); |
701 | 709 | |
702 | - drm_put_dev(platform_get_drvdata(device)); | |
703 | 710 | return 0; |
704 | 711 | } |
705 | 712 | |
706 | 713 | |
707 | 714 | |
708 | 715 | |
709 | 716 | |
... | ... | @@ -726,18 +733,33 @@ |
726 | 733 | |
727 | 734 | static int __init omap_drm_init(void) |
728 | 735 | { |
736 | + int r; | |
737 | + | |
729 | 738 | DBG("init"); |
730 | - if (platform_driver_register(&omap_dmm_driver)) { | |
731 | - /* we can continue on without DMM.. so not fatal */ | |
732 | - dev_err(NULL, "DMM registration failed\n"); | |
739 | + | |
740 | + r = platform_driver_register(&omap_dmm_driver); | |
741 | + if (r) { | |
742 | + pr_err("DMM driver registration failed\n"); | |
743 | + return r; | |
733 | 744 | } |
734 | - return platform_driver_register(&pdev); | |
745 | + | |
746 | + r = platform_driver_register(&pdev); | |
747 | + if (r) { | |
748 | + pr_err("omapdrm driver registration failed\n"); | |
749 | + platform_driver_unregister(&omap_dmm_driver); | |
750 | + return r; | |
751 | + } | |
752 | + | |
753 | + return 0; | |
735 | 754 | } |
736 | 755 | |
737 | 756 | static void __exit omap_drm_fini(void) |
738 | 757 | { |
739 | 758 | DBG("fini"); |
759 | + | |
740 | 760 | platform_driver_unregister(&pdev); |
761 | + | |
762 | + platform_driver_unregister(&omap_dmm_driver); | |
741 | 763 | } |
742 | 764 | |
743 | 765 | /* need late_initcall() so we load after dss_driver's are loaded */ |
drivers/gpu/drm/omapdrm/omap_drv.h
... | ... | @@ -163,6 +163,7 @@ |
163 | 163 | void omap_crtc_pre_uninit(void); |
164 | 164 | struct drm_crtc *omap_crtc_init(struct drm_device *dev, |
165 | 165 | struct drm_plane *plane, enum omap_channel channel, int id); |
166 | +void omap_crtc_flush(struct drm_crtc *crtc); | |
166 | 167 | |
167 | 168 | struct drm_plane *omap_plane_init(struct drm_device *dev, |
168 | 169 | int plane_id, bool private_plane); |
drivers/gpu/drm/omapdrm/omap_fb.c
... | ... | @@ -218,6 +218,20 @@ |
218 | 218 | info->rotation_type = OMAP_DSS_ROT_TILER; |
219 | 219 | info->screen_width = omap_gem_tiled_stride(plane->bo, orient); |
220 | 220 | } else { |
221 | + switch (win->rotation & 0xf) { | |
222 | + case 0: | |
223 | + case BIT(DRM_ROTATE_0): | |
224 | + /* OK */ | |
225 | + break; | |
226 | + | |
227 | + default: | |
228 | + dev_warn(fb->dev->dev, | |
229 | + "rotation '%d' ignored for non-tiled fb\n", | |
230 | + win->rotation); | |
231 | + win->rotation = 0; | |
232 | + break; | |
233 | + } | |
234 | + | |
221 | 235 | info->paddr = get_linear_addr(plane, format, 0, x, y); |
222 | 236 | info->rotation_type = OMAP_DSS_ROT_DMA; |
223 | 237 | info->screen_width = plane->pitch; |
drivers/gpu/drm/omapdrm/omap_fbdev.c
... | ... | @@ -371,6 +371,9 @@ |
371 | 371 | |
372 | 372 | fbdev = to_omap_fbdev(priv->fbdev); |
373 | 373 | |
374 | + /* release the ref taken in omap_fbdev_create() */ | |
375 | + omap_gem_put_paddr(fbdev->bo); | |
376 | + | |
374 | 377 | /* this will free the backing object */ |
375 | 378 | if (fbdev->fb) { |
376 | 379 | drm_framebuffer_unregister_private(fbdev->fb); |
drivers/gpu/drm/omapdrm/omap_gem.c
... | ... | @@ -980,12 +980,9 @@ |
980 | 980 | #ifdef CONFIG_DEBUG_FS |
981 | 981 | void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) |
982 | 982 | { |
983 | - struct drm_device *dev = obj->dev; | |
984 | 983 | struct omap_gem_object *omap_obj = to_omap_bo(obj); |
985 | 984 | uint64_t off; |
986 | 985 | |
987 | - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); | |
988 | - | |
989 | 986 | off = drm_vma_node_start(&obj->vma_node); |
990 | 987 | |
991 | 988 | seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", |
992 | 989 | |
... | ... | @@ -1050,10 +1047,10 @@ |
1050 | 1047 | { |
1051 | 1048 | struct omap_gem_object *omap_obj = waiter->omap_obj; |
1052 | 1049 | if ((waiter->op & OMAP_GEM_READ) && |
1053 | - (omap_obj->sync->read_complete < waiter->read_target)) | |
1050 | + (omap_obj->sync->write_complete < waiter->write_target)) | |
1054 | 1051 | return true; |
1055 | 1052 | if ((waiter->op & OMAP_GEM_WRITE) && |
1056 | - (omap_obj->sync->write_complete < waiter->write_target)) | |
1053 | + (omap_obj->sync->read_complete < waiter->read_target)) | |
1057 | 1054 | return true; |
1058 | 1055 | return false; |
1059 | 1056 | } |
... | ... | @@ -1229,6 +1226,8 @@ |
1229 | 1226 | } |
1230 | 1227 | |
1231 | 1228 | spin_unlock(&sync_lock); |
1229 | + | |
1230 | + kfree(waiter); | |
1232 | 1231 | } |
1233 | 1232 | |
1234 | 1233 | /* no waiting.. */ |
drivers/gpu/drm/omapdrm/omap_plane.c
... | ... | @@ -225,6 +225,11 @@ |
225 | 225 | omap_plane->apply_done_cb.arg = arg; |
226 | 226 | } |
227 | 227 | |
228 | + if (plane->fb) | |
229 | + drm_framebuffer_unreference(plane->fb); | |
230 | + | |
231 | + drm_framebuffer_reference(fb); | |
232 | + | |
228 | 233 | plane->fb = fb; |
229 | 234 | plane->crtc = crtc; |
230 | 235 | |
... | ... | @@ -241,10 +246,13 @@ |
241 | 246 | struct omap_plane *omap_plane = to_omap_plane(plane); |
242 | 247 | omap_plane->enabled = true; |
243 | 248 | |
244 | - if (plane->fb) | |
245 | - drm_framebuffer_unreference(plane->fb); | |
246 | - | |
247 | - drm_framebuffer_reference(fb); | |
249 | + /* omap_plane_mode_set() takes adjusted src */ | |
250 | + switch (omap_plane->win.rotation & 0xf) { | |
251 | + case BIT(DRM_ROTATE_90): | |
252 | + case BIT(DRM_ROTATE_270): | |
253 | + swap(src_w, src_h); | |
254 | + break; | |
255 | + } | |
248 | 256 | |
249 | 257 | return omap_plane_mode_set(plane, crtc, fb, |
250 | 258 | crtc_x, crtc_y, crtc_w, crtc_h, |