aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/omap2/dss/dispc.c5
-rw-r--r--drivers/video/omap2/dss/dsi.c116
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
2759static void dsi_framedone_timeout_work_callback(struct work_struct *work) 2763static 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
2801static void dsi_framedone_irq_callback(void *data, u32 mask) 2795static 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
2816static void dsi_handle_framedone(void) 2809static 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
2818static 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
2852static 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
2865int omap_dsi_prepare_update(struct omap_dss_device *dssdev, 2862int 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