diff options
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 5 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 116 |
2 files changed, 58 insertions, 63 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b8c16034f1ea..5ecdc0004094 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
34 | #include <linux/hardirq.h> | ||
34 | 35 | ||
35 | #include <plat/sram.h> | 36 | #include <plat/sram.h> |
36 | #include <plat/clock.h> | 37 | #include <plat/clock.h> |
@@ -3028,7 +3029,7 @@ void dispc_fake_vsync_irq(void) | |||
3028 | u32 irqstatus = DISPC_IRQ_VSYNC; | 3029 | u32 irqstatus = DISPC_IRQ_VSYNC; |
3029 | int i; | 3030 | int i; |
3030 | 3031 | ||
3031 | local_irq_disable(); | 3032 | WARN_ON(!in_interrupt()); |
3032 | 3033 | ||
3033 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | 3034 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { |
3034 | struct omap_dispc_isr_data *isr_data; | 3035 | struct omap_dispc_isr_data *isr_data; |
@@ -3040,8 +3041,6 @@ void dispc_fake_vsync_irq(void) | |||
3040 | if (isr_data->mask & irqstatus) | 3041 | if (isr_data->mask & irqstatus) |
3041 | isr_data->isr(isr_data->arg, irqstatus); | 3042 | isr_data->isr(isr_data->arg, irqstatus); |
3042 | } | 3043 | } |
3043 | |||
3044 | local_irq_enable(); | ||
3045 | } | 3044 | } |
3046 | #endif | 3045 | #endif |
3047 | 3046 | ||
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index bbed3a13f9a4..32297b4f7abb 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -232,6 +232,7 @@ static struct | |||
232 | unsigned pll_locked; | 232 | unsigned pll_locked; |
233 | 233 | ||
234 | struct completion bta_completion; | 234 | struct completion bta_completion; |
235 | void (*bta_callback)(void); | ||
235 | 236 | ||
236 | int update_channel; | 237 | int update_channel; |
237 | struct dsi_update_region update_region; | 238 | struct dsi_update_region update_region; |
@@ -240,7 +241,6 @@ static struct | |||
240 | 241 | ||
241 | struct workqueue_struct *workqueue; | 242 | struct workqueue_struct *workqueue; |
242 | 243 | ||
243 | struct work_struct framedone_work; | ||
244 | void (*framedone_callback)(int, void *); | 244 | void (*framedone_callback)(int, void *); |
245 | void *framedone_data; | 245 | void *framedone_data; |
246 | 246 | ||
@@ -511,9 +511,13 @@ void dsi_irq_handler(void) | |||
511 | dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); | 511 | dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); |
512 | #endif | 512 | #endif |
513 | 513 | ||
514 | if (vcstatus & DSI_VC_IRQ_BTA) | 514 | if (vcstatus & DSI_VC_IRQ_BTA) { |
515 | complete(&dsi.bta_completion); | 515 | complete(&dsi.bta_completion); |
516 | 516 | ||
517 | if (dsi.bta_callback) | ||
518 | dsi.bta_callback(); | ||
519 | } | ||
520 | |||
517 | if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { | 521 | if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { |
518 | DSSERR("DSI VC(%d) error, vc irqstatus %x\n", | 522 | DSSERR("DSI VC(%d) error, vc irqstatus %x\n", |
519 | i, vcstatus); | 523 | i, vcstatus); |
@@ -2756,69 +2760,70 @@ static void dsi_te_timeout(unsigned long arg) | |||
2756 | } | 2760 | } |
2757 | #endif | 2761 | #endif |
2758 | 2762 | ||
2759 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) | 2763 | static void dsi_handle_framedone(int error) |
2760 | { | 2764 | { |
2761 | int r; | ||
2762 | const int channel = dsi.update_channel; | 2765 | const int channel = dsi.update_channel; |
2763 | 2766 | ||
2764 | DSSERR("Framedone not received for 250ms!\n"); | 2767 | cancel_delayed_work(&dsi.framedone_timeout_work); |
2765 | 2768 | ||
2766 | /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after | 2769 | dsi_vc_disable_bta_irq(channel); |
2767 | * 250ms which would conflict with this timeout work. What should be | ||
2768 | * done is first cancel the transfer on the HW, and then cancel the | ||
2769 | * possibly scheduled framedone work */ | ||
2770 | 2770 | ||
2771 | /* SIDLEMODE back to smart-idle */ | 2771 | /* SIDLEMODE back to smart-idle */ |
2772 | dispc_enable_sidle(); | 2772 | dispc_enable_sidle(); |
2773 | 2773 | ||
2774 | dsi.bta_callback = NULL; | ||
2775 | |||
2774 | if (dsi.te_enabled) { | 2776 | if (dsi.te_enabled) { |
2775 | /* enable LP_RX_TO again after the TE */ | 2777 | /* enable LP_RX_TO again after the TE */ |
2776 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ | 2778 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ |
2777 | } | 2779 | } |
2778 | 2780 | ||
2779 | /* Send BTA after the frame. We need this for the TE to work, as TE | ||
2780 | * trigger is only sent for BTAs without preceding packet. Thus we need | ||
2781 | * to BTA after the pixel packets so that next BTA will cause TE | ||
2782 | * trigger. | ||
2783 | * | ||
2784 | * This is not needed when TE is not in use, but we do it anyway to | ||
2785 | * make sure that the transfer has been completed. It would be more | ||
2786 | * optimal, but more complex, to wait only just before starting next | ||
2787 | * transfer. */ | ||
2788 | r = dsi_vc_send_bta_sync(channel); | ||
2789 | if (r) | ||
2790 | DSSERR("BTA after framedone failed\n"); | ||
2791 | |||
2792 | /* RX_FIFO_NOT_EMPTY */ | 2781 | /* RX_FIFO_NOT_EMPTY */ |
2793 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | 2782 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { |
2794 | DSSERR("Received error during frame transfer:\n"); | 2783 | DSSERR("Received error during frame transfer:\n"); |
2795 | dsi_vc_flush_receive_data(channel); | 2784 | dsi_vc_flush_receive_data(channel); |
2785 | if (!error) | ||
2786 | error = -EIO; | ||
2796 | } | 2787 | } |
2797 | 2788 | ||
2798 | dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); | 2789 | dsi.framedone_callback(error, dsi.framedone_data); |
2790 | |||
2791 | if (!error) | ||
2792 | dsi_perf_show("DISPC"); | ||
2799 | } | 2793 | } |
2800 | 2794 | ||
2801 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 2795 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) |
2802 | { | 2796 | { |
2803 | int r; | 2797 | /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after |
2804 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 2798 | * 250ms which would conflict with this timeout work. What should be |
2805 | * turns itself off. However, DSI still has the pixels in its buffers, | 2799 | * done is first cancel the transfer on the HW, and then cancel the |
2806 | * and is sending the data. | 2800 | * possibly scheduled framedone work. However, cancelling the transfer |
2807 | */ | 2801 | * on the HW is buggy, and would probably require resetting the whole |
2802 | * DSI */ | ||
2808 | 2803 | ||
2809 | /* SIDLEMODE back to smart-idle */ | 2804 | DSSERR("Framedone not received for 250ms!\n"); |
2810 | dispc_enable_sidle(); | ||
2811 | 2805 | ||
2812 | r = queue_work(dsi.workqueue, &dsi.framedone_work); | 2806 | dsi_handle_framedone(-ETIMEDOUT); |
2813 | BUG_ON(r == 0); | ||
2814 | } | 2807 | } |
2815 | 2808 | ||
2816 | static void dsi_handle_framedone(void) | 2809 | static void dsi_framedone_bta_callback(void) |
2810 | { | ||
2811 | dsi_handle_framedone(0); | ||
2812 | |||
2813 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
2814 | dispc_fake_vsync_irq(); | ||
2815 | #endif | ||
2816 | } | ||
2817 | |||
2818 | static void dsi_framedone_irq_callback(void *data, u32 mask) | ||
2817 | { | 2819 | { |
2818 | int r; | ||
2819 | const int channel = dsi.update_channel; | 2820 | const int channel = dsi.update_channel; |
2821 | int r; | ||
2820 | 2822 | ||
2821 | DSSDBG("FRAMEDONE\n"); | 2823 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and |
2824 | * turns itself off. However, DSI still has the pixels in its buffers, | ||
2825 | * and is sending the data. | ||
2826 | */ | ||
2822 | 2827 | ||
2823 | if (dsi.te_enabled) { | 2828 | if (dsi.te_enabled) { |
2824 | /* enable LP_RX_TO again after the TE */ | 2829 | /* enable LP_RX_TO again after the TE */ |
@@ -2833,33 +2838,25 @@ static void dsi_handle_framedone(void) | |||
2833 | * This is not needed when TE is not in use, but we do it anyway to | 2838 | * This is not needed when TE is not in use, but we do it anyway to |
2834 | * make sure that the transfer has been completed. It would be more | 2839 | * make sure that the transfer has been completed. It would be more |
2835 | * optimal, but more complex, to wait only just before starting next | 2840 | * optimal, but more complex, to wait only just before starting next |
2836 | * transfer. */ | 2841 | * transfer. |
2837 | r = dsi_vc_send_bta_sync(channel); | 2842 | * |
2838 | if (r) | 2843 | * Also, as there's no interrupt telling when the transfer has been |
2839 | DSSERR("BTA after framedone failed\n"); | 2844 | * done and the channel could be reconfigured, the only way is to |
2840 | 2845 | * busyloop until TE_SIZE is zero. With BTA we can do this | |
2841 | /* RX_FIFO_NOT_EMPTY */ | 2846 | * asynchronously. |
2842 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | 2847 | * */ |
2843 | DSSERR("Received error during frame transfer:\n"); | ||
2844 | dsi_vc_flush_receive_data(channel); | ||
2845 | } | ||
2846 | |||
2847 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
2848 | dispc_fake_vsync_irq(); | ||
2849 | #endif | ||
2850 | } | ||
2851 | |||
2852 | static void dsi_framedone_work_callback(struct work_struct *work) | ||
2853 | { | ||
2854 | DSSDBGF(); | ||
2855 | 2848 | ||
2856 | cancel_delayed_work_sync(&dsi.framedone_timeout_work); | 2849 | dsi.bta_callback = dsi_framedone_bta_callback; |
2857 | 2850 | ||
2858 | dsi_handle_framedone(); | 2851 | barrier(); |
2859 | 2852 | ||
2860 | dsi_perf_show("DISPC"); | 2853 | dsi_vc_enable_bta_irq(channel); |
2861 | 2854 | ||
2862 | dsi.framedone_callback(0, dsi.framedone_data); | 2855 | r = dsi_vc_send_bta(channel); |
2856 | if (r) { | ||
2857 | DSSERR("BTA after framedone failed\n"); | ||
2858 | dsi_handle_framedone(-EIO); | ||
2859 | } | ||
2863 | } | 2860 | } |
2864 | 2861 | ||
2865 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | 2862 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
@@ -3246,7 +3243,6 @@ int dsi_init(struct platform_device *pdev) | |||
3246 | if (dsi.workqueue == NULL) | 3243 | if (dsi.workqueue == NULL) |
3247 | return -ENOMEM; | 3244 | return -ENOMEM; |
3248 | 3245 | ||
3249 | INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); | ||
3250 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, | 3246 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, |
3251 | dsi_framedone_timeout_work_callback); | 3247 | dsi_framedone_timeout_work_callback); |
3252 | 3248 | ||