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>
26 #include <linux/interrupt.h>
27 #include <linux/seq_file.h>
29 #include <video/omapfb_dss.h>
32 #include "dss_features.h"
33 #include "dispc-compat.h"
35 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
37 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
38 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
39 DISPC_IRQ_SYNC_LOST | \
40 DISPC_IRQ_SYNC_LOST_DIGIT)
42 #define DISPC_MAX_NR_ISRS 8
44 struct omap_dispc_isr_data
{
50 struct dispc_irq_stats
{
51 unsigned long last_reset
;
59 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
61 struct work_struct error_work
;
63 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
64 spinlock_t irq_stats_lock
;
65 struct dispc_irq_stats irq_stats
;
70 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
71 static void dispc_dump_irqs(struct seq_file
*s
)
74 struct dispc_irq_stats stats
;
76 spin_lock_irqsave(&dispc_compat
.irq_stats_lock
, flags
);
78 stats
= dispc_compat
.irq_stats
;
79 memset(&dispc_compat
.irq_stats
, 0, sizeof(dispc_compat
.irq_stats
));
80 dispc_compat
.irq_stats
.last_reset
= jiffies
;
82 spin_unlock_irqrestore(&dispc_compat
.irq_stats_lock
, flags
);
84 seq_printf(s
, "period %u ms\n",
85 jiffies_to_msecs(jiffies
- stats
.last_reset
));
87 seq_printf(s
, "irqs %d\n", stats
.irq_count
);
89 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
95 PIS(ACBIAS_COUNT_STAT
);
97 PIS(GFX_FIFO_UNDERFLOW
);
101 PIS(VID1_FIFO_UNDERFLOW
);
103 PIS(VID2_FIFO_UNDERFLOW
);
105 if (dss_feat_get_num_ovls() > 3) {
106 PIS(VID3_FIFO_UNDERFLOW
);
110 PIS(SYNC_LOST_DIGIT
);
112 if (dss_has_feature(FEAT_MGR_LCD2
)) {
115 PIS(ACBIAS_COUNT_STAT2
);
118 if (dss_has_feature(FEAT_MGR_LCD3
)) {
121 PIS(ACBIAS_COUNT_STAT3
);
128 /* dispc.irq_lock has to be locked by the caller */
129 static void _omap_dispc_set_irqs(void)
133 struct omap_dispc_isr_data
*isr_data
;
135 mask
= dispc_compat
.irq_error_mask
;
137 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
138 isr_data
= &dispc_compat
.registered_isr
[i
];
140 if (isr_data
->isr
== NULL
)
143 mask
|= isr_data
->mask
;
146 dispc_write_irqenable(mask
);
149 int omap_dispc_register_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
154 struct omap_dispc_isr_data
*isr_data
;
159 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
161 /* check for duplicate entry */
162 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
163 isr_data
= &dispc_compat
.registered_isr
[i
];
164 if (isr_data
->isr
== isr
&& isr_data
->arg
== arg
&&
165 isr_data
->mask
== mask
) {
174 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
175 isr_data
= &dispc_compat
.registered_isr
[i
];
177 if (isr_data
->isr
!= NULL
)
182 isr_data
->mask
= mask
;
191 _omap_dispc_set_irqs();
193 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
197 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
201 EXPORT_SYMBOL(omap_dispc_register_isr
);
203 int omap_dispc_unregister_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
208 struct omap_dispc_isr_data
*isr_data
;
210 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
212 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
213 isr_data
= &dispc_compat
.registered_isr
[i
];
214 if (isr_data
->isr
!= isr
|| isr_data
->arg
!= arg
||
215 isr_data
->mask
!= mask
)
218 /* found the correct isr */
220 isr_data
->isr
= NULL
;
221 isr_data
->arg
= NULL
;
229 _omap_dispc_set_irqs();
231 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
235 EXPORT_SYMBOL(omap_dispc_unregister_isr
);
237 static void print_irq_status(u32 status
)
239 if ((status
& dispc_compat
.irq_error_mask
) == 0)
242 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
244 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
247 PIS(GFX_FIFO_UNDERFLOW
),
248 PIS(VID1_FIFO_UNDERFLOW
),
249 PIS(VID2_FIFO_UNDERFLOW
),
250 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW
) : "",
252 PIS(SYNC_LOST_DIGIT
),
253 dss_has_feature(FEAT_MGR_LCD2
) ? PIS(SYNC_LOST2
) : "",
254 dss_has_feature(FEAT_MGR_LCD3
) ? PIS(SYNC_LOST3
) : "");
258 /* Called from dss.c. Note that we don't touch clocks here,
259 * but we presume they are on because we got an IRQ. However,
260 * an irq handler may turn the clocks off, so we may not have
261 * clock later in the function. */
262 static irqreturn_t
omap_dispc_irq_handler(int irq
, void *arg
)
265 u32 irqstatus
, irqenable
;
267 u32 unhandled_errors
;
268 struct omap_dispc_isr_data
*isr_data
;
269 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
271 spin_lock(&dispc_compat
.irq_lock
);
273 irqstatus
= dispc_read_irqstatus();
274 irqenable
= dispc_read_irqenable();
276 /* IRQ is not for us */
277 if (!(irqstatus
& irqenable
)) {
278 spin_unlock(&dispc_compat
.irq_lock
);
282 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
283 spin_lock(&dispc_compat
.irq_stats_lock
);
284 dispc_compat
.irq_stats
.irq_count
++;
285 dss_collect_irq_stats(irqstatus
, dispc_compat
.irq_stats
.irqs
);
286 spin_unlock(&dispc_compat
.irq_stats_lock
);
289 print_irq_status(irqstatus
);
291 /* Ack the interrupt. Do it here before clocks are possibly turned
293 dispc_clear_irqstatus(irqstatus
);
294 /* flush posted write */
295 dispc_read_irqstatus();
297 /* make a copy and unlock, so that isrs can unregister
299 memcpy(registered_isr
, dispc_compat
.registered_isr
,
300 sizeof(registered_isr
));
302 spin_unlock(&dispc_compat
.irq_lock
);
304 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
305 isr_data
= ®istered_isr
[i
];
310 if (isr_data
->mask
& irqstatus
) {
311 isr_data
->isr(isr_data
->arg
, irqstatus
);
312 handledirqs
|= isr_data
->mask
;
316 spin_lock(&dispc_compat
.irq_lock
);
318 unhandled_errors
= irqstatus
& ~handledirqs
& dispc_compat
.irq_error_mask
;
320 if (unhandled_errors
) {
321 dispc_compat
.error_irqs
|= unhandled_errors
;
323 dispc_compat
.irq_error_mask
&= ~unhandled_errors
;
324 _omap_dispc_set_irqs();
326 schedule_work(&dispc_compat
.error_work
);
329 spin_unlock(&dispc_compat
.irq_lock
);
334 static void dispc_error_worker(struct work_struct
*work
)
339 static const unsigned fifo_underflow_bits
[] = {
340 DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
341 DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
342 DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
343 DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
346 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
347 errors
= dispc_compat
.error_irqs
;
348 dispc_compat
.error_irqs
= 0;
349 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
353 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
354 struct omap_overlay
*ovl
;
357 ovl
= omap_dss_get_overlay(i
);
358 bit
= fifo_underflow_bits
[i
];
361 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
368 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
369 struct omap_overlay_manager
*mgr
;
372 mgr
= omap_dss_get_overlay_manager(i
);
373 bit
= dispc_mgr_get_sync_lost_irq(i
);
378 DSSERR("SYNC_LOST on channel %s, restarting the output "
379 "with video overlays disabled\n",
382 dss_mgr_disable(mgr
);
384 for (j
= 0; j
< omap_dss_get_num_overlays(); ++j
) {
385 struct omap_overlay
*ovl
;
386 ovl
= omap_dss_get_overlay(j
);
388 if (ovl
->id
!= OMAP_DSS_GFX
&&
397 if (errors
& DISPC_IRQ_OCP_ERR
) {
399 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
400 struct omap_overlay_manager
*mgr
;
402 mgr
= omap_dss_get_overlay_manager(i
);
403 dss_mgr_disable(mgr
);
407 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
408 dispc_compat
.irq_error_mask
|= errors
;
409 _omap_dispc_set_irqs();
410 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
415 int dss_dispc_initialize_irq(void)
419 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
420 spin_lock_init(&dispc_compat
.irq_stats_lock
);
421 dispc_compat
.irq_stats
.last_reset
= jiffies
;
422 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs
);
425 spin_lock_init(&dispc_compat
.irq_lock
);
427 memset(dispc_compat
.registered_isr
, 0,
428 sizeof(dispc_compat
.registered_isr
));
430 dispc_compat
.irq_error_mask
= DISPC_IRQ_MASK_ERROR
;
431 if (dss_has_feature(FEAT_MGR_LCD2
))
432 dispc_compat
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST2
;
433 if (dss_has_feature(FEAT_MGR_LCD3
))
434 dispc_compat
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST3
;
435 if (dss_feat_get_num_ovls() > 3)
436 dispc_compat
.irq_error_mask
|= DISPC_IRQ_VID3_FIFO_UNDERFLOW
;
439 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
442 dispc_clear_irqstatus(dispc_read_irqstatus());
444 INIT_WORK(&dispc_compat
.error_work
, dispc_error_worker
);
446 _omap_dispc_set_irqs();
448 r
= dispc_request_irq(omap_dispc_irq_handler
, &dispc_compat
);
450 DSSERR("dispc_request_irq failed\n");
457 void dss_dispc_uninitialize_irq(void)
459 dispc_free_irq(&dispc_compat
);
462 static void dispc_mgr_disable_isr(void *data
, u32 mask
)
464 struct completion
*compl = data
;
468 static void dispc_mgr_enable_lcd_out(enum omap_channel channel
)
470 dispc_mgr_enable(channel
, true);
473 static void dispc_mgr_disable_lcd_out(enum omap_channel channel
)
475 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
479 if (!dispc_mgr_is_enabled(channel
))
483 * When we disable LCD output, we need to wait for FRAMEDONE to know
484 * that DISPC has finished with the LCD output.
487 irq
= dispc_mgr_get_framedone_irq(channel
);
489 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
492 DSSERR("failed to register FRAMEDONE isr\n");
494 dispc_mgr_enable(channel
, false);
496 /* if we couldn't register for framedone, just sleep and exit */
502 if (!wait_for_completion_timeout(&framedone_compl
,
503 msecs_to_jiffies(100)))
504 DSSERR("timeout waiting for FRAME DONE\n");
506 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
509 DSSERR("failed to unregister FRAMEDONE isr\n");
512 static void dispc_digit_out_enable_isr(void *data
, u32 mask
)
514 struct completion
*compl = data
;
516 /* ignore any sync lost interrupts */
517 if (mask
& (DISPC_IRQ_EVSYNC_EVEN
| DISPC_IRQ_EVSYNC_ODD
))
521 static void dispc_mgr_enable_digit_out(void)
523 DECLARE_COMPLETION_ONSTACK(vsync_compl
);
527 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
))
531 * Digit output produces some sync lost interrupts during the first
532 * frame when enabling. Those need to be ignored, so we register for the
533 * sync lost irq to prevent the error handler from triggering.
536 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
) |
537 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT
);
539 r
= omap_dispc_register_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
542 DSSERR("failed to register %x isr\n", irq_mask
);
546 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, true);
548 /* wait for the first evsync */
549 if (!wait_for_completion_timeout(&vsync_compl
, msecs_to_jiffies(100)))
550 DSSERR("timeout waiting for digit out to start\n");
552 r
= omap_dispc_unregister_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
555 DSSERR("failed to unregister %x isr\n", irq_mask
);
558 static void dispc_mgr_disable_digit_out(void)
560 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
565 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
))
569 * When we disable the digit output, we need to wait for FRAMEDONE to
570 * know that DISPC has finished with the output.
573 irq_mask
= dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT
);
578 * omap 2/3 don't have framedone irq for TV, so we need to use
582 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
);
584 * We need to wait for both even and odd vsyncs. Note that this
585 * is not totally reliable, as we could get a vsync interrupt
586 * before we disable the output, which leads to timeout in the
587 * wait_for_completion.
592 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
595 DSSERR("failed to register %x isr\n", irq_mask
);
597 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, false);
599 /* if we couldn't register the irq, just sleep and exit */
605 for (i
= 0; i
< num_irqs
; ++i
) {
606 if (!wait_for_completion_timeout(&framedone_compl
,
607 msecs_to_jiffies(100)))
608 DSSERR("timeout waiting for digit out to stop\n");
611 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
614 DSSERR("failed to unregister %x isr\n", irq_mask
);
617 void dispc_mgr_enable_sync(enum omap_channel channel
)
619 if (dss_mgr_is_lcd(channel
))
620 dispc_mgr_enable_lcd_out(channel
);
621 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
622 dispc_mgr_enable_digit_out();
627 void dispc_mgr_disable_sync(enum omap_channel channel
)
629 if (dss_mgr_is_lcd(channel
))
630 dispc_mgr_disable_lcd_out(channel
);
631 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
632 dispc_mgr_disable_digit_out();
637 static inline void dispc_irq_wait_handler(void *data
, u32 mask
)
639 complete((struct completion
*)data
);
642 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask
,
643 unsigned long timeout
)
648 DECLARE_COMPLETION_ONSTACK(completion
);
650 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
656 time_left
= wait_for_completion_interruptible_timeout(&completion
,
659 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
664 if (time_left
== -ERESTARTSYS
)