diff options
-rw-r--r-- | drivers/video/omap2/dss/apply.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 184 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dss.h | 3 |
3 files changed, 122 insertions, 71 deletions
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 7cdc09641b1f..7a61a2f7765d 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
@@ -772,7 +772,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
772 | if (!dss_data.irq_enabled && need_isr()) | 772 | if (!dss_data.irq_enabled && need_isr()) |
773 | dss_register_vsync_isr(); | 773 | dss_register_vsync_isr(); |
774 | 774 | ||
775 | dispc_mgr_enable(mgr->id, true); | 775 | dispc_mgr_enable(mgr->id); |
776 | 776 | ||
777 | mgr_clear_shadow_dirty(mgr); | 777 | mgr_clear_shadow_dirty(mgr); |
778 | 778 | ||
@@ -1027,7 +1027,7 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
1027 | spin_unlock_irqrestore(&data_lock, flags); | 1027 | spin_unlock_irqrestore(&data_lock, flags); |
1028 | 1028 | ||
1029 | if (!mgr_manual_update(mgr)) | 1029 | if (!mgr_manual_update(mgr)) |
1030 | dispc_mgr_enable(mgr->id, true); | 1030 | dispc_mgr_enable(mgr->id); |
1031 | 1031 | ||
1032 | out: | 1032 | out: |
1033 | mutex_unlock(&apply_lock); | 1033 | mutex_unlock(&apply_lock); |
@@ -1052,7 +1052,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
1052 | goto out; | 1052 | goto out; |
1053 | 1053 | ||
1054 | if (!mgr_manual_update(mgr)) | 1054 | if (!mgr_manual_update(mgr)) |
1055 | dispc_mgr_enable(mgr->id, false); | 1055 | dispc_mgr_disable(mgr->id); |
1056 | 1056 | ||
1057 | spin_lock_irqsave(&data_lock, flags); | 1057 | spin_lock_irqsave(&data_lock, flags); |
1058 | 1058 | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index c50270e0afb4..6dd9eb4a2c5b 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -2589,7 +2589,7 @@ int dispc_ovl_enable(enum omap_plane plane, bool enable) | |||
2589 | return 0; | 2589 | return 0; |
2590 | } | 2590 | } |
2591 | 2591 | ||
2592 | static void dispc_disable_isr(void *data, u32 mask) | 2592 | static void dispc_mgr_disable_isr(void *data, u32 mask) |
2593 | { | 2593 | { |
2594 | struct completion *compl = data; | 2594 | struct completion *compl = data; |
2595 | complete(compl); | 2595 | complete(compl); |
@@ -2607,122 +2607,172 @@ bool dispc_mgr_is_enabled(enum omap_channel channel) | |||
2607 | return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | 2607 | return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); |
2608 | } | 2608 | } |
2609 | 2609 | ||
2610 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | 2610 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel) |
2611 | { | 2611 | { |
2612 | struct completion frame_done_completion; | 2612 | _enable_mgr_out(channel, true); |
2613 | bool is_on; | 2613 | } |
2614 | |||
2615 | static void dispc_mgr_disable_lcd_out(enum omap_channel channel) | ||
2616 | { | ||
2617 | DECLARE_COMPLETION_ONSTACK(framedone_compl); | ||
2614 | int r; | 2618 | int r; |
2615 | u32 irq; | 2619 | u32 irq; |
2616 | 2620 | ||
2617 | /* When we disable LCD output, we need to wait until frame is done. | 2621 | if (dispc_mgr_is_enabled(channel) == false) |
2618 | * Otherwise the DSS is still working, and turning off the clocks | 2622 | return; |
2619 | * prevents DSS from going to OFF mode */ | ||
2620 | is_on = dispc_mgr_is_enabled(channel); | ||
2621 | 2623 | ||
2622 | irq = mgr_desc[channel].framedone_irq; | 2624 | /* |
2625 | * When we disable LCD output, we need to wait for FRAMEDONE to know | ||
2626 | * that DISPC has finished with the LCD output. | ||
2627 | */ | ||
2623 | 2628 | ||
2624 | if (!enable && is_on) { | 2629 | irq = dispc_mgr_get_framedone_irq(channel); |
2625 | init_completion(&frame_done_completion); | ||
2626 | 2630 | ||
2627 | r = omap_dispc_register_isr(dispc_disable_isr, | 2631 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, |
2628 | &frame_done_completion, irq); | 2632 | irq); |
2633 | if (r) | ||
2634 | DSSERR("failed to register FRAMEDONE isr\n"); | ||
2629 | 2635 | ||
2630 | if (r) | 2636 | _enable_mgr_out(channel, false); |
2631 | DSSERR("failed to register FRAMEDONE isr\n"); | 2637 | |
2638 | /* if we couldn't register for framedone, just sleep and exit */ | ||
2639 | if (r) { | ||
2640 | msleep(100); | ||
2641 | return; | ||
2632 | } | 2642 | } |
2633 | 2643 | ||
2634 | _enable_mgr_out(channel, enable); | 2644 | if (!wait_for_completion_timeout(&framedone_compl, |
2645 | msecs_to_jiffies(100))) | ||
2646 | DSSERR("timeout waiting for FRAME DONE\n"); | ||
2635 | 2647 | ||
2636 | if (!enable && is_on) { | 2648 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, |
2637 | if (!wait_for_completion_timeout(&frame_done_completion, | 2649 | irq); |
2638 | msecs_to_jiffies(100))) | 2650 | if (r) |
2639 | DSSERR("timeout waiting for FRAME DONE\n"); | 2651 | DSSERR("failed to unregister FRAMEDONE isr\n"); |
2652 | } | ||
2640 | 2653 | ||
2641 | r = omap_dispc_unregister_isr(dispc_disable_isr, | 2654 | static void dispc_digit_out_enable_isr(void *data, u32 mask) |
2642 | &frame_done_completion, irq); | 2655 | { |
2656 | struct completion *compl = data; | ||
2643 | 2657 | ||
2644 | if (r) | 2658 | /* ignore any sync lost interrupts */ |
2645 | DSSERR("failed to unregister FRAMEDONE isr\n"); | 2659 | if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) |
2660 | complete(compl); | ||
2661 | } | ||
2662 | |||
2663 | static void dispc_mgr_enable_digit_out(void) | ||
2664 | { | ||
2665 | DECLARE_COMPLETION_ONSTACK(vsync_compl); | ||
2666 | int r; | ||
2667 | u32 irq_mask; | ||
2668 | |||
2669 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true) | ||
2670 | return; | ||
2671 | |||
2672 | /* | ||
2673 | * Digit output produces some sync lost interrupts during the first | ||
2674 | * frame when enabling. Those need to be ignored, so we register for the | ||
2675 | * sync lost irq to prevent the error handler from triggering. | ||
2676 | */ | ||
2677 | |||
2678 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | | ||
2679 | dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
2680 | |||
2681 | r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
2682 | irq_mask); | ||
2683 | if (r) { | ||
2684 | DSSERR("failed to register %x isr\n", irq_mask); | ||
2685 | return; | ||
2646 | } | 2686 | } |
2687 | |||
2688 | _enable_mgr_out(OMAP_DSS_CHANNEL_DIGIT, true); | ||
2689 | |||
2690 | /* wait for the first evsync */ | ||
2691 | if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) | ||
2692 | DSSERR("timeout waiting for digit out to start\n"); | ||
2693 | |||
2694 | r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
2695 | irq_mask); | ||
2696 | if (r) | ||
2697 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
2647 | } | 2698 | } |
2648 | 2699 | ||
2649 | static void dispc_mgr_enable_digit_out(bool enable) | 2700 | static void dispc_mgr_disable_digit_out(void) |
2650 | { | 2701 | { |
2651 | struct completion frame_done_completion; | 2702 | DECLARE_COMPLETION_ONSTACK(framedone_compl); |
2652 | enum dss_hdmi_venc_clk_source_select src; | 2703 | enum dss_hdmi_venc_clk_source_select src; |
2653 | int r, i; | 2704 | int r, i; |
2654 | u32 irq_mask; | 2705 | u32 irq_mask; |
2655 | int num_irqs; | 2706 | int num_irqs; |
2656 | 2707 | ||
2657 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == enable) | 2708 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false) |
2658 | return; | 2709 | return; |
2659 | 2710 | ||
2660 | src = dss_get_hdmi_venc_clk_source(); | 2711 | src = dss_get_hdmi_venc_clk_source(); |
2661 | 2712 | ||
2662 | if (enable) { | 2713 | /* |
2663 | unsigned long flags; | 2714 | * When we disable the digit output, we need to wait for FRAMEDONE to |
2664 | /* When we enable digit output, we'll get an extra digit | 2715 | * know that DISPC has finished with the output. For analog tv out we'll |
2665 | * sync lost interrupt, that we need to ignore */ | 2716 | * use vsync, as omap2/3 don't have framedone for TV. |
2666 | spin_lock_irqsave(&dispc.irq_lock, flags); | 2717 | */ |
2667 | dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
2668 | _omap_dispc_set_irqs(); | ||
2669 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
2670 | } | ||
2671 | |||
2672 | /* When we disable digit output, we need to wait until fields are done. | ||
2673 | * Otherwise the DSS is still working, and turning off the clocks | ||
2674 | * prevents DSS from going to OFF mode. And when enabling, we need to | ||
2675 | * wait for the extra sync losts */ | ||
2676 | init_completion(&frame_done_completion); | ||
2677 | 2718 | ||
2678 | if (src == DSS_HDMI_M_PCLK && enable == false) { | 2719 | if (src == DSS_HDMI_M_PCLK) { |
2679 | irq_mask = DISPC_IRQ_FRAMEDONETV; | 2720 | irq_mask = DISPC_IRQ_FRAMEDONETV; |
2680 | num_irqs = 1; | 2721 | num_irqs = 1; |
2681 | } else { | 2722 | } else { |
2682 | irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; | 2723 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); |
2683 | /* XXX I understand from TRM that we should only wait for the | 2724 | /* |
2684 | * current field to complete. But it seems we have to wait for | 2725 | * We need to wait for both even and odd vsyncs. Note that this |
2685 | * both fields */ | 2726 | * is not totally reliable, as we could get a vsync interrupt |
2727 | * before we disable the output, which leads to timeout in the | ||
2728 | * wait_for_completion. | ||
2729 | */ | ||
2686 | num_irqs = 2; | 2730 | num_irqs = 2; |
2687 | } | 2731 | } |
2688 | 2732 | ||
2689 | r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, | 2733 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, |
2690 | irq_mask); | 2734 | irq_mask); |
2691 | if (r) | 2735 | if (r) |
2692 | DSSERR("failed to register %x isr\n", irq_mask); | 2736 | DSSERR("failed to register %x isr\n", irq_mask); |
2693 | 2737 | ||
2694 | _enable_mgr_out(OMAP_DSS_CHANNEL_DIGIT, enable); | 2738 | _enable_mgr_out(OMAP_DSS_CHANNEL_DIGIT, false); |
2739 | |||
2740 | /* if we couldn't register the irq, just sleep and exit */ | ||
2741 | if (r) { | ||
2742 | msleep(100); | ||
2743 | return; | ||
2744 | } | ||
2695 | 2745 | ||
2696 | for (i = 0; i < num_irqs; ++i) { | 2746 | for (i = 0; i < num_irqs; ++i) { |
2697 | if (!wait_for_completion_timeout(&frame_done_completion, | 2747 | if (!wait_for_completion_timeout(&framedone_compl, |
2698 | msecs_to_jiffies(100))) | 2748 | msecs_to_jiffies(100))) |
2699 | DSSERR("timeout waiting for digit out to %s\n", | 2749 | DSSERR("timeout waiting for digit out to stop\n"); |
2700 | enable ? "start" : "stop"); | ||
2701 | } | 2750 | } |
2702 | 2751 | ||
2703 | r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, | 2752 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, |
2704 | irq_mask); | 2753 | irq_mask); |
2705 | if (r) | 2754 | if (r) |
2706 | DSSERR("failed to unregister %x isr\n", irq_mask); | 2755 | DSSERR("failed to unregister %x isr\n", irq_mask); |
2756 | } | ||
2707 | 2757 | ||
2708 | if (enable) { | 2758 | void dispc_mgr_enable(enum omap_channel channel) |
2709 | unsigned long flags; | 2759 | { |
2710 | spin_lock_irqsave(&dispc.irq_lock, flags); | 2760 | if (dss_mgr_is_lcd(channel)) |
2711 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT; | 2761 | dispc_mgr_enable_lcd_out(channel); |
2712 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); | 2762 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) |
2713 | _omap_dispc_set_irqs(); | 2763 | dispc_mgr_enable_digit_out(); |
2714 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | 2764 | else |
2715 | } | 2765 | WARN_ON(1); |
2716 | } | 2766 | } |
2717 | 2767 | ||
2718 | void dispc_mgr_enable(enum omap_channel channel, bool enable) | 2768 | void dispc_mgr_disable(enum omap_channel channel) |
2719 | { | 2769 | { |
2720 | if (dss_mgr_is_lcd(channel)) | 2770 | if (dss_mgr_is_lcd(channel)) |
2721 | dispc_mgr_enable_lcd_out(channel, enable); | 2771 | dispc_mgr_disable_lcd_out(channel); |
2722 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | 2772 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) |
2723 | dispc_mgr_enable_digit_out(enable); | 2773 | dispc_mgr_disable_digit_out(); |
2724 | else | 2774 | else |
2725 | BUG(); | 2775 | WARN_ON(1); |
2726 | } | 2776 | } |
2727 | 2777 | ||
2728 | void dispc_wb_enable(bool enable) | 2778 | void dispc_wb_enable(bool enable) |
@@ -2739,7 +2789,7 @@ void dispc_wb_enable(bool enable) | |||
2739 | if (!enable && is_on) { | 2789 | if (!enable && is_on) { |
2740 | init_completion(&frame_done_completion); | 2790 | init_completion(&frame_done_completion); |
2741 | 2791 | ||
2742 | r = omap_dispc_register_isr(dispc_disable_isr, | 2792 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, |
2743 | &frame_done_completion, irq); | 2793 | &frame_done_completion, irq); |
2744 | if (r) | 2794 | if (r) |
2745 | DSSERR("failed to register FRAMEDONEWB isr\n"); | 2795 | DSSERR("failed to register FRAMEDONEWB isr\n"); |
@@ -2752,7 +2802,7 @@ void dispc_wb_enable(bool enable) | |||
2752 | msecs_to_jiffies(100))) | 2802 | msecs_to_jiffies(100))) |
2753 | DSSERR("timeout waiting for FRAMEDONEWB\n"); | 2803 | DSSERR("timeout waiting for FRAMEDONEWB\n"); |
2754 | 2804 | ||
2755 | r = omap_dispc_unregister_isr(dispc_disable_isr, | 2805 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, |
2756 | &frame_done_completion, irq); | 2806 | &frame_done_completion, irq); |
2757 | if (r) | 2807 | if (r) |
2758 | DSSERR("failed to unregister FRAMEDONEWB isr\n"); | 2808 | DSSERR("failed to unregister FRAMEDONEWB isr\n"); |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index bf9b7a4c5065..fb891656f1f8 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -438,7 +438,8 @@ u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel); | |||
438 | bool dispc_mgr_go_busy(enum omap_channel channel); | 438 | bool dispc_mgr_go_busy(enum omap_channel channel); |
439 | void dispc_mgr_go(enum omap_channel channel); | 439 | void dispc_mgr_go(enum omap_channel channel); |
440 | bool dispc_mgr_is_enabled(enum omap_channel channel); | 440 | bool dispc_mgr_is_enabled(enum omap_channel channel); |
441 | void dispc_mgr_enable(enum omap_channel channel, bool enable); | 441 | void dispc_mgr_enable(enum omap_channel channel); |
442 | void dispc_mgr_disable(enum omap_channel channel); | ||
442 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); | 443 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); |
443 | void dispc_mgr_set_lcd_config(enum omap_channel channel, | 444 | void dispc_mgr_set_lcd_config(enum omap_channel channel, |
444 | const struct dss_lcd_mgr_config *config); | 445 | const struct dss_lcd_mgr_config *config); |