2 * Copyright (C) 2012 Texas Instruments
3 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
18 #define DSS_SUBSYS_NAME "APPLY"
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <linux/spinlock.h>
24 #include <linux/jiffies.h>
25 #include <linux/delay.h>
27 #include <video/omapdss.h>
30 #include "dss_features.h"
31 #include "dispc-compat.h"
33 static void dispc_mgr_disable_isr(void *data
, u32 mask
)
35 struct completion
*compl = data
;
39 static void dispc_mgr_enable_lcd_out(enum omap_channel channel
)
41 dispc_mgr_enable(channel
, true);
44 static void dispc_mgr_disable_lcd_out(enum omap_channel channel
)
46 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
50 if (dispc_mgr_is_enabled(channel
) == false)
54 * When we disable LCD output, we need to wait for FRAMEDONE to know
55 * that DISPC has finished with the LCD output.
58 irq
= dispc_mgr_get_framedone_irq(channel
);
60 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
63 DSSERR("failed to register FRAMEDONE isr\n");
65 dispc_mgr_enable(channel
, false);
67 /* if we couldn't register for framedone, just sleep and exit */
73 if (!wait_for_completion_timeout(&framedone_compl
,
74 msecs_to_jiffies(100)))
75 DSSERR("timeout waiting for FRAME DONE\n");
77 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
80 DSSERR("failed to unregister FRAMEDONE isr\n");
83 static void dispc_digit_out_enable_isr(void *data
, u32 mask
)
85 struct completion
*compl = data
;
87 /* ignore any sync lost interrupts */
88 if (mask
& (DISPC_IRQ_EVSYNC_EVEN
| DISPC_IRQ_EVSYNC_ODD
))
92 static void dispc_mgr_enable_digit_out(void)
94 DECLARE_COMPLETION_ONSTACK(vsync_compl
);
98 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
) == true)
102 * Digit output produces some sync lost interrupts during the first
103 * frame when enabling. Those need to be ignored, so we register for the
104 * sync lost irq to prevent the error handler from triggering.
107 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
) |
108 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT
);
110 r
= omap_dispc_register_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
113 DSSERR("failed to register %x isr\n", irq_mask
);
117 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, true);
119 /* wait for the first evsync */
120 if (!wait_for_completion_timeout(&vsync_compl
, msecs_to_jiffies(100)))
121 DSSERR("timeout waiting for digit out to start\n");
123 r
= omap_dispc_unregister_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
126 DSSERR("failed to unregister %x isr\n", irq_mask
);
129 static void dispc_mgr_disable_digit_out(void)
131 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
136 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
) == false)
140 * When we disable the digit output, we need to wait for FRAMEDONE to
141 * know that DISPC has finished with the output.
144 irq_mask
= dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT
);
149 * omap 2/3 don't have framedone irq for TV, so we need to use
153 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
);
155 * We need to wait for both even and odd vsyncs. Note that this
156 * is not totally reliable, as we could get a vsync interrupt
157 * before we disable the output, which leads to timeout in the
158 * wait_for_completion.
163 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
166 DSSERR("failed to register %x isr\n", irq_mask
);
168 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, false);
170 /* if we couldn't register the irq, just sleep and exit */
176 for (i
= 0; i
< num_irqs
; ++i
) {
177 if (!wait_for_completion_timeout(&framedone_compl
,
178 msecs_to_jiffies(100)))
179 DSSERR("timeout waiting for digit out to stop\n");
182 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
185 DSSERR("failed to unregister %x isr\n", irq_mask
);
188 void dispc_mgr_enable_sync(enum omap_channel channel
)
190 if (dss_mgr_is_lcd(channel
))
191 dispc_mgr_enable_lcd_out(channel
);
192 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
193 dispc_mgr_enable_digit_out();
198 void dispc_mgr_disable_sync(enum omap_channel channel
)
200 if (dss_mgr_is_lcd(channel
))
201 dispc_mgr_disable_lcd_out(channel
);
202 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
203 dispc_mgr_disable_digit_out();
208 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask
,
209 unsigned long timeout
)
211 void dispc_irq_wait_handler(void *data
, u32 mask
)
213 complete((struct completion
*)data
);
217 DECLARE_COMPLETION_ONSTACK(completion
);
219 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
225 timeout
= wait_for_completion_interruptible_timeout(&completion
,
228 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
233 if (timeout
== -ERESTARTSYS
)