1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Texas Instruments
4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
7 #define DSS_SUBSYS_NAME "APPLY"
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/spinlock.h>
13 #include <linux/jiffies.h>
14 #include <linux/delay.h>
15 #include <linux/interrupt.h>
16 #include <linux/seq_file.h>
18 #include <video/omapfb_dss.h>
21 #include "dss_features.h"
22 #include "dispc-compat.h"
24 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
26 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
27 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
28 DISPC_IRQ_SYNC_LOST | \
29 DISPC_IRQ_SYNC_LOST_DIGIT)
31 #define DISPC_MAX_NR_ISRS 8
33 struct omap_dispc_isr_data
{
39 struct dispc_irq_stats
{
40 unsigned long last_reset
;
48 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
50 struct work_struct error_work
;
52 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
53 spinlock_t irq_stats_lock
;
54 struct dispc_irq_stats irq_stats
;
59 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
60 static void dispc_dump_irqs(struct seq_file
*s
)
63 struct dispc_irq_stats stats
;
65 spin_lock_irqsave(&dispc_compat
.irq_stats_lock
, flags
);
67 stats
= dispc_compat
.irq_stats
;
68 memset(&dispc_compat
.irq_stats
, 0, sizeof(dispc_compat
.irq_stats
));
69 dispc_compat
.irq_stats
.last_reset
= jiffies
;
71 spin_unlock_irqrestore(&dispc_compat
.irq_stats_lock
, flags
);
73 seq_printf(s
, "period %u ms\n",
74 jiffies_to_msecs(jiffies
- stats
.last_reset
));
76 seq_printf(s
, "irqs %d\n", stats
.irq_count
);
78 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1])
84 PIS(ACBIAS_COUNT_STAT
);
86 PIS(GFX_FIFO_UNDERFLOW
);
90 PIS(VID1_FIFO_UNDERFLOW
);
92 PIS(VID2_FIFO_UNDERFLOW
);
94 if (dss_feat_get_num_ovls() > 3) {
95 PIS(VID3_FIFO_UNDERFLOW
);
101 if (dss_has_feature(FEAT_MGR_LCD2
)) {
104 PIS(ACBIAS_COUNT_STAT2
);
107 if (dss_has_feature(FEAT_MGR_LCD3
)) {
110 PIS(ACBIAS_COUNT_STAT3
);
117 /* dispc.irq_lock has to be locked by the caller */
118 static void _omap_dispc_set_irqs(void)
122 struct omap_dispc_isr_data
*isr_data
;
124 mask
= dispc_compat
.irq_error_mask
;
126 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
127 isr_data
= &dispc_compat
.registered_isr
[i
];
129 if (isr_data
->isr
== NULL
)
132 mask
|= isr_data
->mask
;
135 dispc_write_irqenable(mask
);
138 int omap_dispc_register_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
143 struct omap_dispc_isr_data
*isr_data
;
148 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
150 /* check for duplicate entry */
151 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
152 isr_data
= &dispc_compat
.registered_isr
[i
];
153 if (isr_data
->isr
== isr
&& isr_data
->arg
== arg
&&
154 isr_data
->mask
== mask
) {
163 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
164 isr_data
= &dispc_compat
.registered_isr
[i
];
166 if (isr_data
->isr
!= NULL
)
171 isr_data
->mask
= mask
;
180 _omap_dispc_set_irqs();
182 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
186 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
190 EXPORT_SYMBOL(omap_dispc_register_isr
);
192 int omap_dispc_unregister_isr(omap_dispc_isr_t isr
, void *arg
, u32 mask
)
197 struct omap_dispc_isr_data
*isr_data
;
199 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
201 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
202 isr_data
= &dispc_compat
.registered_isr
[i
];
203 if (isr_data
->isr
!= isr
|| isr_data
->arg
!= arg
||
204 isr_data
->mask
!= mask
)
207 /* found the correct isr */
209 isr_data
->isr
= NULL
;
210 isr_data
->arg
= NULL
;
218 _omap_dispc_set_irqs();
220 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
224 EXPORT_SYMBOL(omap_dispc_unregister_isr
);
226 static void print_irq_status(u32 status
)
228 if ((status
& dispc_compat
.irq_error_mask
) == 0)
231 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
233 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
236 PIS(GFX_FIFO_UNDERFLOW
),
237 PIS(VID1_FIFO_UNDERFLOW
),
238 PIS(VID2_FIFO_UNDERFLOW
),
239 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW
) : "",
241 PIS(SYNC_LOST_DIGIT
),
242 dss_has_feature(FEAT_MGR_LCD2
) ? PIS(SYNC_LOST2
) : "",
243 dss_has_feature(FEAT_MGR_LCD3
) ? PIS(SYNC_LOST3
) : "");
247 /* Called from dss.c. Note that we don't touch clocks here,
248 * but we presume they are on because we got an IRQ. However,
249 * an irq handler may turn the clocks off, so we may not have
250 * clock later in the function. */
251 static irqreturn_t
omap_dispc_irq_handler(int irq
, void *arg
)
254 u32 irqstatus
, irqenable
;
256 u32 unhandled_errors
;
257 struct omap_dispc_isr_data
*isr_data
;
258 struct omap_dispc_isr_data registered_isr
[DISPC_MAX_NR_ISRS
];
260 spin_lock(&dispc_compat
.irq_lock
);
262 irqstatus
= dispc_read_irqstatus();
263 irqenable
= dispc_read_irqenable();
265 /* IRQ is not for us */
266 if (!(irqstatus
& irqenable
)) {
267 spin_unlock(&dispc_compat
.irq_lock
);
271 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
272 spin_lock(&dispc_compat
.irq_stats_lock
);
273 dispc_compat
.irq_stats
.irq_count
++;
274 dss_collect_irq_stats(irqstatus
, dispc_compat
.irq_stats
.irqs
);
275 spin_unlock(&dispc_compat
.irq_stats_lock
);
278 print_irq_status(irqstatus
);
280 /* Ack the interrupt. Do it here before clocks are possibly turned
282 dispc_clear_irqstatus(irqstatus
);
283 /* flush posted write */
284 dispc_read_irqstatus();
286 /* make a copy and unlock, so that isrs can unregister
288 memcpy(registered_isr
, dispc_compat
.registered_isr
,
289 sizeof(registered_isr
));
291 spin_unlock(&dispc_compat
.irq_lock
);
293 for (i
= 0; i
< DISPC_MAX_NR_ISRS
; i
++) {
294 isr_data
= ®istered_isr
[i
];
299 if (isr_data
->mask
& irqstatus
) {
300 isr_data
->isr(isr_data
->arg
, irqstatus
);
301 handledirqs
|= isr_data
->mask
;
305 spin_lock(&dispc_compat
.irq_lock
);
307 unhandled_errors
= irqstatus
& ~handledirqs
& dispc_compat
.irq_error_mask
;
309 if (unhandled_errors
) {
310 dispc_compat
.error_irqs
|= unhandled_errors
;
312 dispc_compat
.irq_error_mask
&= ~unhandled_errors
;
313 _omap_dispc_set_irqs();
315 schedule_work(&dispc_compat
.error_work
);
318 spin_unlock(&dispc_compat
.irq_lock
);
323 static void dispc_error_worker(struct work_struct
*work
)
328 static const unsigned fifo_underflow_bits
[] = {
329 DISPC_IRQ_GFX_FIFO_UNDERFLOW
,
330 DISPC_IRQ_VID1_FIFO_UNDERFLOW
,
331 DISPC_IRQ_VID2_FIFO_UNDERFLOW
,
332 DISPC_IRQ_VID3_FIFO_UNDERFLOW
,
335 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
336 errors
= dispc_compat
.error_irqs
;
337 dispc_compat
.error_irqs
= 0;
338 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
342 for (i
= 0; i
< omap_dss_get_num_overlays(); ++i
) {
343 struct omap_overlay
*ovl
;
346 ovl
= omap_dss_get_overlay(i
);
347 bit
= fifo_underflow_bits
[i
];
350 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
357 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
358 struct omap_overlay_manager
*mgr
;
361 mgr
= omap_dss_get_overlay_manager(i
);
362 bit
= dispc_mgr_get_sync_lost_irq(i
);
367 DSSERR("SYNC_LOST on channel %s, restarting the output "
368 "with video overlays disabled\n",
371 dss_mgr_disable(mgr
);
373 for (j
= 0; j
< omap_dss_get_num_overlays(); ++j
) {
374 struct omap_overlay
*ovl
;
375 ovl
= omap_dss_get_overlay(j
);
377 if (ovl
->id
!= OMAP_DSS_GFX
&&
386 if (errors
& DISPC_IRQ_OCP_ERR
) {
388 for (i
= 0; i
< omap_dss_get_num_overlay_managers(); ++i
) {
389 struct omap_overlay_manager
*mgr
;
391 mgr
= omap_dss_get_overlay_manager(i
);
392 dss_mgr_disable(mgr
);
396 spin_lock_irqsave(&dispc_compat
.irq_lock
, flags
);
397 dispc_compat
.irq_error_mask
|= errors
;
398 _omap_dispc_set_irqs();
399 spin_unlock_irqrestore(&dispc_compat
.irq_lock
, flags
);
404 int dss_dispc_initialize_irq(void)
408 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
409 spin_lock_init(&dispc_compat
.irq_stats_lock
);
410 dispc_compat
.irq_stats
.last_reset
= jiffies
;
411 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs
);
414 spin_lock_init(&dispc_compat
.irq_lock
);
416 memset(dispc_compat
.registered_isr
, 0,
417 sizeof(dispc_compat
.registered_isr
));
419 dispc_compat
.irq_error_mask
= DISPC_IRQ_MASK_ERROR
;
420 if (dss_has_feature(FEAT_MGR_LCD2
))
421 dispc_compat
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST2
;
422 if (dss_has_feature(FEAT_MGR_LCD3
))
423 dispc_compat
.irq_error_mask
|= DISPC_IRQ_SYNC_LOST3
;
424 if (dss_feat_get_num_ovls() > 3)
425 dispc_compat
.irq_error_mask
|= DISPC_IRQ_VID3_FIFO_UNDERFLOW
;
428 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
431 dispc_clear_irqstatus(dispc_read_irqstatus());
433 INIT_WORK(&dispc_compat
.error_work
, dispc_error_worker
);
435 _omap_dispc_set_irqs();
437 r
= dispc_request_irq(omap_dispc_irq_handler
, &dispc_compat
);
439 DSSERR("dispc_request_irq failed\n");
446 void dss_dispc_uninitialize_irq(void)
448 dispc_free_irq(&dispc_compat
);
451 static void dispc_mgr_disable_isr(void *data
, u32 mask
)
453 struct completion
*compl = data
;
457 static void dispc_mgr_enable_lcd_out(enum omap_channel channel
)
459 dispc_mgr_enable(channel
, true);
462 static void dispc_mgr_disable_lcd_out(enum omap_channel channel
)
464 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
468 if (!dispc_mgr_is_enabled(channel
))
472 * When we disable LCD output, we need to wait for FRAMEDONE to know
473 * that DISPC has finished with the LCD output.
476 irq
= dispc_mgr_get_framedone_irq(channel
);
478 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
481 DSSERR("failed to register FRAMEDONE isr\n");
483 dispc_mgr_enable(channel
, false);
485 /* if we couldn't register for framedone, just sleep and exit */
491 if (!wait_for_completion_timeout(&framedone_compl
,
492 msecs_to_jiffies(100)))
493 DSSERR("timeout waiting for FRAME DONE\n");
495 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
498 DSSERR("failed to unregister FRAMEDONE isr\n");
501 static void dispc_digit_out_enable_isr(void *data
, u32 mask
)
503 struct completion
*compl = data
;
505 /* ignore any sync lost interrupts */
506 if (mask
& (DISPC_IRQ_EVSYNC_EVEN
| DISPC_IRQ_EVSYNC_ODD
))
510 static void dispc_mgr_enable_digit_out(void)
512 DECLARE_COMPLETION_ONSTACK(vsync_compl
);
516 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
))
520 * Digit output produces some sync lost interrupts during the first
521 * frame when enabling. Those need to be ignored, so we register for the
522 * sync lost irq to prevent the error handler from triggering.
525 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
) |
526 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT
);
528 r
= omap_dispc_register_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
531 DSSERR("failed to register %x isr\n", irq_mask
);
535 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, true);
537 /* wait for the first evsync */
538 if (!wait_for_completion_timeout(&vsync_compl
, msecs_to_jiffies(100)))
539 DSSERR("timeout waiting for digit out to start\n");
541 r
= omap_dispc_unregister_isr(dispc_digit_out_enable_isr
, &vsync_compl
,
544 DSSERR("failed to unregister %x isr\n", irq_mask
);
547 static void dispc_mgr_disable_digit_out(void)
549 DECLARE_COMPLETION_ONSTACK(framedone_compl
);
554 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT
))
558 * When we disable the digit output, we need to wait for FRAMEDONE to
559 * know that DISPC has finished with the output.
562 irq_mask
= dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT
);
567 * omap 2/3 don't have framedone irq for TV, so we need to use
571 irq_mask
= dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT
);
573 * We need to wait for both even and odd vsyncs. Note that this
574 * is not totally reliable, as we could get a vsync interrupt
575 * before we disable the output, which leads to timeout in the
576 * wait_for_completion.
581 r
= omap_dispc_register_isr(dispc_mgr_disable_isr
, &framedone_compl
,
584 DSSERR("failed to register %x isr\n", irq_mask
);
586 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT
, false);
588 /* if we couldn't register the irq, just sleep and exit */
594 for (i
= 0; i
< num_irqs
; ++i
) {
595 if (!wait_for_completion_timeout(&framedone_compl
,
596 msecs_to_jiffies(100)))
597 DSSERR("timeout waiting for digit out to stop\n");
600 r
= omap_dispc_unregister_isr(dispc_mgr_disable_isr
, &framedone_compl
,
603 DSSERR("failed to unregister %x isr\n", irq_mask
);
606 void dispc_mgr_enable_sync(enum omap_channel channel
)
608 if (dss_mgr_is_lcd(channel
))
609 dispc_mgr_enable_lcd_out(channel
);
610 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
611 dispc_mgr_enable_digit_out();
616 void dispc_mgr_disable_sync(enum omap_channel channel
)
618 if (dss_mgr_is_lcd(channel
))
619 dispc_mgr_disable_lcd_out(channel
);
620 else if (channel
== OMAP_DSS_CHANNEL_DIGIT
)
621 dispc_mgr_disable_digit_out();
626 static inline void dispc_irq_wait_handler(void *data
, u32 mask
)
628 complete((struct completion
*)data
);
631 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask
,
632 unsigned long timeout
)
637 DECLARE_COMPLETION_ONSTACK(completion
);
639 r
= omap_dispc_register_isr(dispc_irq_wait_handler
, &completion
,
645 time_left
= wait_for_completion_interruptible_timeout(&completion
,
648 omap_dispc_unregister_isr(dispc_irq_wait_handler
, &completion
, irqmask
);
653 if (time_left
== -ERESTARTSYS
)