diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2012-10-10 05:48:31 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2012-10-18 06:11:13 -0400 |
commit | b111224900ed743cc5a5f4feafdc910b9e8e736c (patch) | |
tree | 9c015352f19594800c0fabe1227f6cd39d7037c7 /drivers/video/omap2 | |
parent | cb699200af1626a4c718018f28b7737bf56496e5 (diff) |
OMAPDSS: DISPC: cleanup lcd/digit enable/disable
We currently have a single function to enable and disable the manager
output for LCD and DIGIT. The functions are a bit complex, as handling
both enable and disable require some extra steps to ensure that the
output is enabled or disabled properly without errors before exiting the
function.
The code can be made simpler to understand by splitting the functions
into separate enable and disable functions. We'll also clean up the
comments and some parameter names at the same time.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video/omap2')
-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); |