diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-04-02 04:37:06 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2014-04-14 05:34:14 -0400 |
commit | 2ec8e3787ae6957f738bb133e755213b9d7c066e (patch) | |
tree | 47ec00c3ca196eeea817c8eab277f1952dbd973b /drivers/gpu | |
parent | c9eaa447e77efe77b7fa4c953bd62de8297fd6c5 (diff) |
drm/omap: fix output enable/disable sequence
At the moment it's quite easy to get the following errors when the HDMI
output is enabled or disabled:
[drm:omap_crtc_error_irq] *ERROR* tv: errors: 00008000
The reason for the errors is that the omapdrm driver doesn't properly
handle the sync-lost irqs that happen when enabling the DIGIT crtc,
which is used for HDMI and analog TV. The driver does disable the
sync-lost irq properly, but it fails to wait until the output has been
fully enabled (i.e. the first vsync), so the sync-lost errors are still
seen occasionally.
This patch makes the omapdrm act the same way as the omapfb does:
- When enabling a display, we'll wait for the first vsync.
- When disabling a display, we'll wait for framedone if available, or
odd and even vsyncs.
These changes make sure the output is fully enabled or disabled at the
end of the function.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Reported-by: Sanjay Singh Rawat <sanjay.rawat@linaro.org>
Reviewed-by: Rob Clark <robdclark@gmail.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r-- | drivers/gpu/drm/omapdrm/omap_crtc.c | 46 |
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 355157e4f78d..0acbe62901d9 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c | |||
@@ -528,38 +528,46 @@ static void set_enabled(struct drm_crtc *crtc, bool enable) | |||
528 | struct drm_device *dev = crtc->dev; | 528 | struct drm_device *dev = crtc->dev; |
529 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); | 529 | struct omap_crtc *omap_crtc = to_omap_crtc(crtc); |
530 | enum omap_channel channel = omap_crtc->channel; | 530 | enum omap_channel channel = omap_crtc->channel; |
531 | struct omap_irq_wait *wait = NULL; | 531 | struct omap_irq_wait *wait; |
532 | u32 framedone_irq, vsync_irq; | ||
533 | int ret; | ||
532 | 534 | ||
533 | if (dispc_mgr_is_enabled(channel) == enable) | 535 | if (dispc_mgr_is_enabled(channel) == enable) |
534 | return; | 536 | return; |
535 | 537 | ||
536 | /* ignore sync-lost irqs during enable/disable */ | 538 | /* |
539 | * Digit output produces some sync lost interrupts during the first | ||
540 | * frame when enabling, so we need to ignore those. | ||
541 | */ | ||
537 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); | 542 | omap_irq_unregister(crtc->dev, &omap_crtc->error_irq); |
538 | 543 | ||
539 | if (dispc_mgr_get_framedone_irq(channel)) { | 544 | framedone_irq = dispc_mgr_get_framedone_irq(channel); |
540 | if (!enable) { | 545 | vsync_irq = dispc_mgr_get_vsync_irq(channel); |
541 | wait = omap_irq_wait_init(dev, | 546 | |
542 | dispc_mgr_get_framedone_irq(channel), 1); | 547 | if (enable) { |
543 | } | 548 | wait = omap_irq_wait_init(dev, vsync_irq, 1); |
544 | } else { | 549 | } else { |
545 | /* | 550 | /* |
546 | * When we disable digit output, we need to wait until fields | 551 | * When we disable the digit output, we need to wait for |
547 | * are done. Otherwise the DSS is still working, and turning | 552 | * FRAMEDONE to know that DISPC has finished with the output. |
548 | * off the clocks prevents DSS from going to OFF mode. And when | 553 | * |
549 | * enabling, we need to wait for the extra sync losts | 554 | * OMAP2/3 does not have FRAMEDONE irq for digit output, and in |
555 | * that case we need to use vsync interrupt, and wait for both | ||
556 | * even and odd frames. | ||
550 | */ | 557 | */ |
551 | wait = omap_irq_wait_init(dev, | 558 | |
552 | dispc_mgr_get_vsync_irq(channel), 2); | 559 | if (framedone_irq) |
560 | wait = omap_irq_wait_init(dev, framedone_irq, 1); | ||
561 | else | ||
562 | wait = omap_irq_wait_init(dev, vsync_irq, 2); | ||
553 | } | 563 | } |
554 | 564 | ||
555 | dispc_mgr_enable(channel, enable); | 565 | dispc_mgr_enable(channel, enable); |
556 | 566 | ||
557 | if (wait) { | 567 | ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); |
558 | int ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); | 568 | if (ret) { |
559 | if (ret) { | 569 | dev_err(dev->dev, "%s: timeout waiting for %s\n", |
560 | dev_err(dev->dev, "%s: timeout waiting for %s\n", | 570 | omap_crtc->name, enable ? "enable" : "disable"); |
561 | omap_crtc->name, enable ? "enable" : "disable"); | ||
562 | } | ||
563 | } | 571 | } |
564 | 572 | ||
565 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); | 573 | omap_irq_register(crtc->dev, &omap_crtc->error_irq); |