aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2014-04-17 23:12:04 -0400
committerDave Airlie <airlied@redhat.com>2014-04-17 23:12:04 -0400
commitd62c3e7a73f87defb17651109a55d36adedadc6f (patch)
tree76de169974960e3dfc46de2829e357c8cf1539fc
parent90e48970c206a2dd7810a5d3dcf07effab956919 (diff)
parentf2d022aa421ca903a30f63b04528064b7eceaf5e (diff)
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
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c100
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c32
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c14
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c3
-rw-r--r--drivers/gpu/drm/omapdrm/omap_gem.c9
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c16
7 files changed, 133 insertions, 42 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 355157e4f78d..e3c47a8005ff 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -33,6 +33,7 @@ struct omap_crtc {
33 int pipe; 33 int pipe;
34 enum omap_channel channel; 34 enum omap_channel channel;
35 struct omap_overlay_manager_info info; 35 struct omap_overlay_manager_info info;
36 struct drm_encoder *current_encoder;
36 37
37 /* 38 /*
38 * Temporary: eventually this will go away, but it is needed 39 * Temporary: eventually this will go away, but it is needed
@@ -120,13 +121,25 @@ static void omap_crtc_start_update(struct omap_overlay_manager *mgr)
120{ 121{
121} 122}
122 123
124static void set_enabled(struct drm_crtc *crtc, bool enable);
125
123static int omap_crtc_enable(struct omap_overlay_manager *mgr) 126static 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 return 0; 135 return 0;
126} 136}
127 137
128static void omap_crtc_disable(struct omap_overlay_manager *mgr) 138static 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
132static void omap_crtc_set_timings(struct omap_overlay_manager *mgr, 145static void omap_crtc_set_timings(struct omap_overlay_manager *mgr,
@@ -184,7 +197,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
184 WARN_ON(omap_crtc->apply_irq.registered); 197 WARN_ON(omap_crtc->apply_irq.registered);
185 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); 198 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
186 199
187 omap_crtc->plane->funcs->destroy(omap_crtc->plane);
188 drm_crtc_cleanup(crtc); 200 drm_crtc_cleanup(crtc);
189 201
190 kfree(omap_crtc); 202 kfree(omap_crtc);
@@ -338,17 +350,23 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
338 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 350 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
339 struct drm_plane *primary = crtc->primary; 351 struct drm_plane *primary = crtc->primary;
340 struct drm_gem_object *bo; 352 struct drm_gem_object *bo;
353 unsigned long flags;
341 354
342 DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1, 355 DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
343 fb->base.id, event); 356 fb->base.id, event);
344 357
358 spin_lock_irqsave(&dev->event_lock, flags);
359
345 if (omap_crtc->old_fb) { 360 if (omap_crtc->old_fb) {
361 spin_unlock_irqrestore(&dev->event_lock, flags);
346 dev_err(dev->dev, "already a pending flip\n"); 362 dev_err(dev->dev, "already a pending flip\n");
347 return -EINVAL; 363 return -EINVAL;
348 } 364 }
349 365
350 omap_crtc->event = event; 366 omap_crtc->event = event;
351 primary->fb = fb; 367 omap_crtc->old_fb = primary->fb = fb;
368
369 spin_unlock_irqrestore(&dev->event_lock, flags);
352 370
353 /* 371 /*
354 * Hold a reference temporarily until the crtc is updated 372 * Hold a reference temporarily until the crtc is updated
@@ -528,38 +546,46 @@ static void set_enabled(struct drm_crtc *crtc, bool enable)
528 struct drm_device *dev = crtc->dev; 546 struct drm_device *dev = crtc->dev;
529 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 547 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
530 enum omap_channel channel = omap_crtc->channel; 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 if (dispc_mgr_is_enabled(channel) == enable) 553 if (dispc_mgr_is_enabled(channel) == enable)
534 return; 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 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); 560 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
538 561
539 if (dispc_mgr_get_framedone_irq(channel)) { 562 framedone_irq = dispc_mgr_get_framedone_irq(channel);
540 if (!enable) { 563 vsync_irq = dispc_mgr_get_vsync_irq(channel);
541 wait = omap_irq_wait_init(dev, 564
542 dispc_mgr_get_framedone_irq(channel), 1); 565 if (enable) {
543 } 566 wait = omap_irq_wait_init(dev, vsync_irq, 1);
544 } else { 567 } else {
545 /* 568 /*
546 * When we disable digit output, we need to wait until fields 569 * When we disable the digit output, we need to wait for
547 * are done. Otherwise the DSS is still working, and turning 570 * FRAMEDONE to know that DISPC has finished with the output.
548 * off the clocks prevents DSS from going to OFF mode. And when 571 *
549 * enabling, we need to wait for the extra sync losts 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, 576
552 dispc_mgr_get_vsync_irq(channel), 2); 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 dispc_mgr_enable(channel, enable); 583 dispc_mgr_enable(channel, enable);
556 584
557 if (wait) { 585 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
558 int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); 586 if (ret) {
559 if (ret) { 587 dev_err(dev->dev, "%s: timeout waiting for %s\n",
560 dev_err(dev->dev, "%s: timeout waiting for %s\n", 588 omap_crtc->name, enable ? "enable" : "disable");
561 omap_crtc->name, enable ? "enable" : "disable");
562 }
563 } 589 }
564 590
565 omap_irq_register(crtc->dev, &omap_crtc->error_irq); 591 omap_irq_register(crtc->dev, &omap_crtc->error_irq);
@@ -586,8 +612,12 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
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 if (!omap_crtc->enabled) { 620 if (!omap_crtc->enabled) {
590 set_enabled(&omap_crtc->base, false);
591 if (encoder) 621 if (encoder)
592 omap_encoder_set_enabled(encoder, false); 622 omap_encoder_set_enabled(encoder, false);
593 } else { 623 } else {
@@ -596,13 +626,7 @@ static void omap_crtc_pre_apply(struct omap_drm_apply *apply)
596 omap_encoder_update(encoder, omap_crtc->mgr, 626 omap_encoder_update(encoder, omap_crtc->mgr,
597 &omap_crtc->timings); 627 &omap_crtc->timings);
598 omap_encoder_set_enabled(encoder, true); 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 omap_crtc->full_update = false; 632 omap_crtc->full_update = false;
@@ -613,10 +637,30 @@ static void omap_crtc_post_apply(struct omap_drm_apply *apply)
613 /* nothing needed for post-apply */ 637 /* nothing needed for post-apply */
614} 638}
615 639
640void 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
616static const char *channel_names[] = { 659static const char *channel_names[] = {
617 [OMAP_DSS_CHANNEL_LCD] = "lcd", 660 [OMAP_DSS_CHANNEL_LCD] = "lcd",
618 [OMAP_DSS_CHANNEL_DIGIT] = "tv", 661 [OMAP_DSS_CHANNEL_DIGIT] = "tv",
619 [OMAP_DSS_CHANNEL_LCD2] = "lcd2", 662 [OMAP_DSS_CHANNEL_LCD2] = "lcd2",
663 [OMAP_DSS_CHANNEL_LCD3] = "lcd3",
620}; 664};
621 665
622void omap_crtc_pre_init(void) 666void omap_crtc_pre_init(void)
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index bf39fcc49e0f..c8270e4b26f3 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -513,12 +513,18 @@ static int dev_load(struct drm_device *dev, unsigned long flags)
513static int dev_unload(struct drm_device *dev) 513static int dev_unload(struct drm_device *dev)
514{ 514{
515 struct omap_drm_private *priv = dev->dev_private; 515 struct omap_drm_private *priv = dev->dev_private;
516 int i;
516 517
517 DBG("unload: dev=%p", dev); 518 DBG("unload: dev=%p", dev);
518 519
519 drm_kms_helper_poll_fini(dev); 520 drm_kms_helper_poll_fini(dev);
520 521
521 omap_fbdev_free(dev); 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 omap_modeset_free(dev); 528 omap_modeset_free(dev);
523 omap_gem_deinit(dev); 529 omap_gem_deinit(dev);
524 530
@@ -696,10 +702,11 @@ static int pdev_remove(struct platform_device *device)
696{ 702{
697 DBG(""); 703 DBG("");
698 704
705 drm_put_dev(platform_get_drvdata(device));
706
699 omap_disconnect_dssdevs(); 707 omap_disconnect_dssdevs();
700 omap_crtc_pre_uninit(); 708 omap_crtc_pre_uninit();
701 709
702 drm_put_dev(platform_get_drvdata(device));
703 return 0; 710 return 0;
704} 711}
705 712
@@ -726,18 +733,33 @@ static struct platform_driver pdev = {
726 733
727static int __init omap_drm_init(void) 734static int __init omap_drm_init(void)
728{ 735{
736 int r;
737
729 DBG("init"); 738 DBG("init");
730 if (platform_driver_register(&omap_dmm_driver)) { 739
731 /* we can continue on without DMM.. so not fatal */ 740 r = platform_driver_register(&omap_dmm_driver);
732 dev_err(NULL, "DMM registration failed\n"); 741 if (r) {
742 pr_err("DMM driver registration failed\n");
743 return r;
744 }
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;
733 } 751 }
734 return platform_driver_register(&pdev); 752
753 return 0;
735} 754}
736 755
737static void __exit omap_drm_fini(void) 756static void __exit omap_drm_fini(void)
738{ 757{
739 DBG("fini"); 758 DBG("fini");
759
740 platform_driver_unregister(&pdev); 760 platform_driver_unregister(&pdev);
761
762 platform_driver_unregister(&omap_dmm_driver);
741} 763}
742 764
743/* need late_initcall() so we load after dss_driver's are loaded */ 765/* need late_initcall() so we load after dss_driver's are loaded */
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 428b2981fd68..284b80fc3c54 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -163,6 +163,7 @@ void omap_crtc_pre_init(void);
163void omap_crtc_pre_uninit(void); 163void omap_crtc_pre_uninit(void);
164struct drm_crtc *omap_crtc_init(struct drm_device *dev, 164struct drm_crtc *omap_crtc_init(struct drm_device *dev,
165 struct drm_plane *plane, enum omap_channel channel, int id); 165 struct drm_plane *plane, enum omap_channel channel, int id);
166void omap_crtc_flush(struct drm_crtc *crtc);
166 167
167struct drm_plane *omap_plane_init(struct drm_device *dev, 168struct drm_plane *omap_plane_init(struct drm_device *dev,
168 int plane_id, bool private_plane); 169 int plane_id, bool private_plane);
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index d2b8c49bfb4a..8b019602ffe6 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -218,6 +218,20 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
218 info->rotation_type = OMAP_DSS_ROT_TILER; 218 info->rotation_type = OMAP_DSS_ROT_TILER;
219 info->screen_width = omap_gem_tiled_stride(plane->bo, orient); 219 info->screen_width = omap_gem_tiled_stride(plane->bo, orient);
220 } else { 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 info->paddr = get_linear_addr(plane, format, 0, x, y); 235 info->paddr = get_linear_addr(plane, format, 0, x, y);
222 info->rotation_type = OMAP_DSS_ROT_DMA; 236 info->rotation_type = OMAP_DSS_ROT_DMA;
223 info->screen_width = plane->pitch; 237 info->screen_width = plane->pitch;
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 002988d09021..1388ca7f87e8 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -371,6 +371,9 @@ void omap_fbdev_free(struct drm_device *dev)
371 371
372 fbdev = to_omap_fbdev(priv->fbdev); 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 /* this will free the backing object */ 377 /* this will free the backing object */
375 if (fbdev->fb) { 378 if (fbdev->fb) {
376 drm_framebuffer_unregister_private(fbdev->fb); 379 drm_framebuffer_unregister_private(fbdev->fb);
diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c
index c8d972763889..95dbce286a41 100644
--- a/drivers/gpu/drm/omapdrm/omap_gem.c
+++ b/drivers/gpu/drm/omapdrm/omap_gem.c
@@ -980,12 +980,9 @@ int omap_gem_resume(struct device *dev)
980#ifdef CONFIG_DEBUG_FS 980#ifdef CONFIG_DEBUG_FS
981void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m) 981void omap_gem_describe(struct drm_gem_object *obj, struct seq_file *m)
982{ 982{
983 struct drm_device *dev = obj->dev;
984 struct omap_gem_object *omap_obj = to_omap_bo(obj); 983 struct omap_gem_object *omap_obj = to_omap_bo(obj);
985 uint64_t off; 984 uint64_t off;
986 985
987 WARN_ON(!mutex_is_locked(&dev->struct_mutex));
988
989 off = drm_vma_node_start(&obj->vma_node); 986 off = drm_vma_node_start(&obj->vma_node);
990 987
991 seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d", 988 seq_printf(m, "%08x: %2d (%2d) %08llx %08Zx (%2d) %p %4d",
@@ -1050,10 +1047,10 @@ static inline bool is_waiting(struct omap_gem_sync_waiter *waiter)
1050{ 1047{
1051 struct omap_gem_object *omap_obj = waiter->omap_obj; 1048 struct omap_gem_object *omap_obj = waiter->omap_obj;
1052 if ((waiter->op & OMAP_GEM_READ) && 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 return true; 1051 return true;
1055 if ((waiter->op & OMAP_GEM_WRITE) && 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 return true; 1054 return true;
1058 return false; 1055 return false;
1059} 1056}
@@ -1229,6 +1226,8 @@ int omap_gem_op_async(struct drm_gem_object *obj, enum omap_gem_op op,
1229 } 1226 }
1230 1227
1231 spin_unlock(&sync_lock); 1228 spin_unlock(&sync_lock);
1229
1230 kfree(waiter);
1232 } 1231 }
1233 1232
1234 /* no waiting.. */ 1233 /* no waiting.. */
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 046d5e660c04..3cf31ee59aac 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -225,6 +225,11 @@ int omap_plane_mode_set(struct drm_plane *plane,
225 omap_plane->apply_done_cb.arg = arg; 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 plane->fb = fb; 233 plane->fb = fb;
229 plane->crtc = crtc; 234 plane->crtc = crtc;
230 235
@@ -241,10 +246,13 @@ static int omap_plane_update(struct drm_plane *plane,
241 struct omap_plane *omap_plane = to_omap_plane(plane); 246 struct omap_plane *omap_plane = to_omap_plane(plane);
242 omap_plane->enabled = true; 247 omap_plane->enabled = true;
243 248
244 if (plane->fb) 249 /* omap_plane_mode_set() takes adjusted src */
245 drm_framebuffer_unreference(plane->fb); 250 switch (omap_plane->win.rotation & 0xf) {
246 251 case BIT(DRM_ROTATE_90):
247 drm_framebuffer_reference(fb); 252 case BIT(DRM_ROTATE_270):
253 swap(src_w, src_h);
254 break;
255 }
248 256
249 return omap_plane_mode_set(plane, crtc, fb, 257 return omap_plane_mode_set(plane, crtc, fb,
250 crtc_x, crtc_y, crtc_w, crtc_h, 258 crtc_x, crtc_y, crtc_w, crtc_h,