aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorTomi Valkeinen <tomi.valkeinen@nokia.com>2010-06-09 08:31:01 -0400
committerTomi Valkeinen <tomi.valkeinen@nokia.com>2010-08-05 09:52:02 -0400
commitab83b14c829e35436b423947bb5b151133314346 (patch)
tree8e56254ceaaf33c2fe4651e4d744a4a1d0070693 /drivers
parent9ecd96842bc6312fdb2f84b6379a6f92686e2fd0 (diff)
OMAP: DSS2: DSI: use BTA to end the frame transfer
Previously a work was started on FRAMEDONE interrupt, and this work either sent a BTA synchronously or looped until TE_SIZE was zero, to wait for the end of the transfer. This patch changes a BTA to be sent asynchronously from FRAMEDONE interrupt, and when a BTA interrupt is received, the transfer is finished. This way we do the whole process asynchronously, and also inside interrupt context. This will give us much better latency to handle the end of the frame than with the previous work based solution. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
Diffstat (limited to 'drivers')
-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