1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2012 Texas Instruments
4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
5 */
6
7 #define DSS_SUBSYS_NAME "APPLY"
8
9 #include <linux/export.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/jiffies.h>
15 #include <linux/delay.h>
16 #include <linux/interrupt.h>
17 #include <linux/seq_file.h>
18
19 #include <video/omapfb_dss.h>
20
21 #include "dss.h"
22 #include "dss_features.h"
23 #include "dispc-compat.h"
24
25 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
26 DISPC_IRQ_OCP_ERR | \
27 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
28 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
29 DISPC_IRQ_SYNC_LOST | \
30 DISPC_IRQ_SYNC_LOST_DIGIT)
31
32 #define DISPC_MAX_NR_ISRS 8
33
34 struct omap_dispc_isr_data {
35 omap_dispc_isr_t isr;
36 void *arg;
37 u32 mask;
38 };
39
40 struct dispc_irq_stats {
41 unsigned long last_reset;
42 unsigned irq_count;
43 unsigned irqs[32];
44 };
45
46 static struct {
47 spinlock_t irq_lock;
48 u32 irq_error_mask;
49 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
50 u32 error_irqs;
51 struct work_struct error_work;
52
53 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
54 spinlock_t irq_stats_lock;
55 struct dispc_irq_stats irq_stats;
56 #endif
57 } dispc_compat;
58
59
60 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
dispc_dump_irqs(struct seq_file * s)61 static void dispc_dump_irqs(struct seq_file *s)
62 {
63 unsigned long flags;
64 struct dispc_irq_stats stats;
65
66 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
67
68 stats = dispc_compat.irq_stats;
69 memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats));
70 dispc_compat.irq_stats.last_reset = jiffies;
71
72 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
73
74 seq_printf(s, "period %u ms\n",
75 jiffies_to_msecs(jiffies - stats.last_reset));
76
77 seq_printf(s, "irqs %d\n", stats.irq_count);
78 #define PIS(x) \
79 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1])
80
81 PIS(FRAMEDONE);
82 PIS(VSYNC);
83 PIS(EVSYNC_EVEN);
84 PIS(EVSYNC_ODD);
85 PIS(ACBIAS_COUNT_STAT);
86 PIS(PROG_LINE_NUM);
87 PIS(GFX_FIFO_UNDERFLOW);
88 PIS(GFX_END_WIN);
89 PIS(PAL_GAMMA_MASK);
90 PIS(OCP_ERR);
91 PIS(VID1_FIFO_UNDERFLOW);
92 PIS(VID1_END_WIN);
93 PIS(VID2_FIFO_UNDERFLOW);
94 PIS(VID2_END_WIN);
95 if (dss_feat_get_num_ovls() > 3) {
96 PIS(VID3_FIFO_UNDERFLOW);
97 PIS(VID3_END_WIN);
98 }
99 PIS(SYNC_LOST);
100 PIS(SYNC_LOST_DIGIT);
101 PIS(WAKEUP);
102 if (dss_has_feature(FEAT_MGR_LCD2)) {
103 PIS(FRAMEDONE2);
104 PIS(VSYNC2);
105 PIS(ACBIAS_COUNT_STAT2);
106 PIS(SYNC_LOST2);
107 }
108 if (dss_has_feature(FEAT_MGR_LCD3)) {
109 PIS(FRAMEDONE3);
110 PIS(VSYNC3);
111 PIS(ACBIAS_COUNT_STAT3);
112 PIS(SYNC_LOST3);
113 }
114 #undef PIS
115 }
116 #endif
117
118 /* dispc.irq_lock has to be locked by the caller */
_omap_dispc_set_irqs(void)119 static void _omap_dispc_set_irqs(void)
120 {
121 u32 mask;
122 int i;
123 struct omap_dispc_isr_data *isr_data;
124
125 mask = dispc_compat.irq_error_mask;
126
127 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
128 isr_data = &dispc_compat.registered_isr[i];
129
130 if (isr_data->isr == NULL)
131 continue;
132
133 mask |= isr_data->mask;
134 }
135
136 dispc_write_irqenable(mask);
137 }
138
omap_dispc_register_isr(omap_dispc_isr_t isr,void * arg,u32 mask)139 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
140 {
141 int i;
142 int ret;
143 unsigned long flags;
144 struct omap_dispc_isr_data *isr_data;
145
146 if (isr == NULL)
147 return -EINVAL;
148
149 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
150
151 /* check for duplicate entry */
152 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
153 isr_data = &dispc_compat.registered_isr[i];
154 if (isr_data->isr == isr && isr_data->arg == arg &&
155 isr_data->mask == mask) {
156 ret = -EINVAL;
157 goto err;
158 }
159 }
160
161 isr_data = NULL;
162 ret = -EBUSY;
163
164 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
165 isr_data = &dispc_compat.registered_isr[i];
166
167 if (isr_data->isr != NULL)
168 continue;
169
170 isr_data->isr = isr;
171 isr_data->arg = arg;
172 isr_data->mask = mask;
173 ret = 0;
174
175 break;
176 }
177
178 if (ret)
179 goto err;
180
181 _omap_dispc_set_irqs();
182
183 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
184
185 return 0;
186 err:
187 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
188
189 return ret;
190 }
191 EXPORT_SYMBOL(omap_dispc_register_isr);
192
omap_dispc_unregister_isr(omap_dispc_isr_t isr,void * arg,u32 mask)193 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
194 {
195 int i;
196 unsigned long flags;
197 int ret = -EINVAL;
198 struct omap_dispc_isr_data *isr_data;
199
200 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
201
202 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
203 isr_data = &dispc_compat.registered_isr[i];
204 if (isr_data->isr != isr || isr_data->arg != arg ||
205 isr_data->mask != mask)
206 continue;
207
208 /* found the correct isr */
209
210 isr_data->isr = NULL;
211 isr_data->arg = NULL;
212 isr_data->mask = 0;
213
214 ret = 0;
215 break;
216 }
217
218 if (ret == 0)
219 _omap_dispc_set_irqs();
220
221 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
222
223 return ret;
224 }
225 EXPORT_SYMBOL(omap_dispc_unregister_isr);
226
print_irq_status(u32 status)227 static void print_irq_status(u32 status)
228 {
229 if ((status & dispc_compat.irq_error_mask) == 0)
230 return;
231
232 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
233
234 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
235 status,
236 PIS(OCP_ERR),
237 PIS(GFX_FIFO_UNDERFLOW),
238 PIS(VID1_FIFO_UNDERFLOW),
239 PIS(VID2_FIFO_UNDERFLOW),
240 dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "",
241 PIS(SYNC_LOST),
242 PIS(SYNC_LOST_DIGIT),
243 dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "",
244 dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : "");
245 #undef PIS
246 }
247
248 /* Called from dss.c. Note that we don't touch clocks here,
249 * but we presume they are on because we got an IRQ. However,
250 * an irq handler may turn the clocks off, so we may not have
251 * clock later in the function. */
omap_dispc_irq_handler(int irq,void * arg)252 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
253 {
254 int i;
255 u32 irqstatus, irqenable;
256 u32 handledirqs = 0;
257 u32 unhandled_errors;
258 struct omap_dispc_isr_data *isr_data;
259 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
260
261 spin_lock(&dispc_compat.irq_lock);
262
263 irqstatus = dispc_read_irqstatus();
264 irqenable = dispc_read_irqenable();
265
266 /* IRQ is not for us */
267 if (!(irqstatus & irqenable)) {
268 spin_unlock(&dispc_compat.irq_lock);
269 return IRQ_NONE;
270 }
271
272 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
273 spin_lock(&dispc_compat.irq_stats_lock);
274 dispc_compat.irq_stats.irq_count++;
275 dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs);
276 spin_unlock(&dispc_compat.irq_stats_lock);
277 #endif
278
279 print_irq_status(irqstatus);
280
281 /* Ack the interrupt. Do it here before clocks are possibly turned
282 * off */
283 dispc_clear_irqstatus(irqstatus);
284 /* flush posted write */
285 dispc_read_irqstatus();
286
287 /* make a copy and unlock, so that isrs can unregister
288 * themselves */
289 memcpy(registered_isr, dispc_compat.registered_isr,
290 sizeof(registered_isr));
291
292 spin_unlock(&dispc_compat.irq_lock);
293
294 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
295 isr_data = ®istered_isr[i];
296
297 if (!isr_data->isr)
298 continue;
299
300 if (isr_data->mask & irqstatus) {
301 isr_data->isr(isr_data->arg, irqstatus);
302 handledirqs |= isr_data->mask;
303 }
304 }
305
306 spin_lock(&dispc_compat.irq_lock);
307
308 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
309
310 if (unhandled_errors) {
311 dispc_compat.error_irqs |= unhandled_errors;
312
313 dispc_compat.irq_error_mask &= ~unhandled_errors;
314 _omap_dispc_set_irqs();
315
316 schedule_work(&dispc_compat.error_work);
317 }
318
319 spin_unlock(&dispc_compat.irq_lock);
320
321 return IRQ_HANDLED;
322 }
323
dispc_error_worker(struct work_struct * work)324 static void dispc_error_worker(struct work_struct *work)
325 {
326 int i;
327 u32 errors;
328 unsigned long flags;
329 static const unsigned fifo_underflow_bits[] = {
330 DISPC_IRQ_GFX_FIFO_UNDERFLOW,
331 DISPC_IRQ_VID1_FIFO_UNDERFLOW,
332 DISPC_IRQ_VID2_FIFO_UNDERFLOW,
333 DISPC_IRQ_VID3_FIFO_UNDERFLOW,
334 };
335
336 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
337 errors = dispc_compat.error_irqs;
338 dispc_compat.error_irqs = 0;
339 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
340
341 dispc_runtime_get();
342
343 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
344 struct omap_overlay *ovl;
345 unsigned bit;
346
347 ovl = omap_dss_get_overlay(i);
348 bit = fifo_underflow_bits[i];
349
350 if (bit & errors) {
351 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
352 ovl->name);
353 ovl->disable(ovl);
354 msleep(50);
355 }
356 }
357
358 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
359 struct omap_overlay_manager *mgr;
360 unsigned bit;
361
362 mgr = omap_dss_get_overlay_manager(i);
363 bit = dispc_mgr_get_sync_lost_irq(i);
364
365 if (bit & errors) {
366 int j;
367
368 DSSERR("SYNC_LOST on channel %s, restarting the output "
369 "with video overlays disabled\n",
370 mgr->name);
371
372 dss_mgr_disable(mgr);
373
374 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
375 struct omap_overlay *ovl;
376 ovl = omap_dss_get_overlay(j);
377
378 if (ovl->id != OMAP_DSS_GFX &&
379 ovl->manager == mgr)
380 ovl->disable(ovl);
381 }
382
383 dss_mgr_enable(mgr);
384 }
385 }
386
387 if (errors & DISPC_IRQ_OCP_ERR) {
388 DSSERR("OCP_ERR\n");
389 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
390 struct omap_overlay_manager *mgr;
391
392 mgr = omap_dss_get_overlay_manager(i);
393 dss_mgr_disable(mgr);
394 }
395 }
396
397 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
398 dispc_compat.irq_error_mask |= errors;
399 _omap_dispc_set_irqs();
400 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
401
402 dispc_runtime_put();
403 }
404
dss_dispc_initialize_irq(void)405 int dss_dispc_initialize_irq(void)
406 {
407 int r;
408
409 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
410 spin_lock_init(&dispc_compat.irq_stats_lock);
411 dispc_compat.irq_stats.last_reset = jiffies;
412 dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
413 #endif
414
415 spin_lock_init(&dispc_compat.irq_lock);
416
417 memset(dispc_compat.registered_isr, 0,
418 sizeof(dispc_compat.registered_isr));
419
420 dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR;
421 if (dss_has_feature(FEAT_MGR_LCD2))
422 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2;
423 if (dss_has_feature(FEAT_MGR_LCD3))
424 dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3;
425 if (dss_feat_get_num_ovls() > 3)
426 dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW;
427
428 /*
429 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
430 * so clear it
431 */
432 dispc_clear_irqstatus(dispc_read_irqstatus());
433
434 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
435
436 _omap_dispc_set_irqs();
437
438 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
439 if (r) {
440 DSSERR("dispc_request_irq failed\n");
441 return r;
442 }
443
444 return 0;
445 }
446
dss_dispc_uninitialize_irq(void)447 void dss_dispc_uninitialize_irq(void)
448 {
449 dispc_free_irq(&dispc_compat);
450 }
451
dispc_mgr_disable_isr(void * data,u32 mask)452 static void dispc_mgr_disable_isr(void *data, u32 mask)
453 {
454 struct completion *compl = data;
455 complete(compl);
456 }
457
dispc_mgr_enable_lcd_out(enum omap_channel channel)458 static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
459 {
460 dispc_mgr_enable(channel, true);
461 }
462
dispc_mgr_disable_lcd_out(enum omap_channel channel)463 static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
464 {
465 DECLARE_COMPLETION_ONSTACK(framedone_compl);
466 int r;
467 u32 irq;
468
469 if (!dispc_mgr_is_enabled(channel))
470 return;
471
472 /*
473 * When we disable LCD output, we need to wait for FRAMEDONE to know
474 * that DISPC has finished with the LCD output.
475 */
476
477 irq = dispc_mgr_get_framedone_irq(channel);
478
479 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
480 irq);
481 if (r)
482 DSSERR("failed to register FRAMEDONE isr\n");
483
484 dispc_mgr_enable(channel, false);
485
486 /* if we couldn't register for framedone, just sleep and exit */
487 if (r) {
488 msleep(100);
489 return;
490 }
491
492 if (!wait_for_completion_timeout(&framedone_compl,
493 msecs_to_jiffies(100)))
494 DSSERR("timeout waiting for FRAME DONE\n");
495
496 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
497 irq);
498 if (r)
499 DSSERR("failed to unregister FRAMEDONE isr\n");
500 }
501
dispc_digit_out_enable_isr(void * data,u32 mask)502 static void dispc_digit_out_enable_isr(void *data, u32 mask)
503 {
504 struct completion *compl = data;
505
506 /* ignore any sync lost interrupts */
507 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
508 complete(compl);
509 }
510
dispc_mgr_enable_digit_out(void)511 static void dispc_mgr_enable_digit_out(void)
512 {
513 DECLARE_COMPLETION_ONSTACK(vsync_compl);
514 int r;
515 u32 irq_mask;
516
517 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
518 return;
519
520 /*
521 * Digit output produces some sync lost interrupts during the first
522 * frame when enabling. Those need to be ignored, so we register for the
523 * sync lost irq to prevent the error handler from triggering.
524 */
525
526 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
527 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
528
529 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
530 irq_mask);
531 if (r) {
532 DSSERR("failed to register %x isr\n", irq_mask);
533 return;
534 }
535
536 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
537
538 /* wait for the first evsync */
539 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
540 DSSERR("timeout waiting for digit out to start\n");
541
542 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
543 irq_mask);
544 if (r)
545 DSSERR("failed to unregister %x isr\n", irq_mask);
546 }
547
dispc_mgr_disable_digit_out(void)548 static void dispc_mgr_disable_digit_out(void)
549 {
550 DECLARE_COMPLETION_ONSTACK(framedone_compl);
551 int r, i;
552 u32 irq_mask;
553 int num_irqs;
554
555 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
556 return;
557
558 /*
559 * When we disable the digit output, we need to wait for FRAMEDONE to
560 * know that DISPC has finished with the output.
561 */
562
563 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
564 num_irqs = 1;
565
566 if (!irq_mask) {
567 /*
568 * omap 2/3 don't have framedone irq for TV, so we need to use
569 * vsyncs for this.
570 */
571
572 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
573 /*
574 * We need to wait for both even and odd vsyncs. Note that this
575 * is not totally reliable, as we could get a vsync interrupt
576 * before we disable the output, which leads to timeout in the
577 * wait_for_completion.
578 */
579 num_irqs = 2;
580 }
581
582 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
583 irq_mask);
584 if (r)
585 DSSERR("failed to register %x isr\n", irq_mask);
586
587 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
588
589 /* if we couldn't register the irq, just sleep and exit */
590 if (r) {
591 msleep(100);
592 return;
593 }
594
595 for (i = 0; i < num_irqs; ++i) {
596 if (!wait_for_completion_timeout(&framedone_compl,
597 msecs_to_jiffies(100)))
598 DSSERR("timeout waiting for digit out to stop\n");
599 }
600
601 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
602 irq_mask);
603 if (r)
604 DSSERR("failed to unregister %x isr\n", irq_mask);
605 }
606
dispc_mgr_enable_sync(enum omap_channel channel)607 void dispc_mgr_enable_sync(enum omap_channel channel)
608 {
609 if (dss_mgr_is_lcd(channel))
610 dispc_mgr_enable_lcd_out(channel);
611 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
612 dispc_mgr_enable_digit_out();
613 else
614 WARN_ON(1);
615 }
616
dispc_mgr_disable_sync(enum omap_channel channel)617 void dispc_mgr_disable_sync(enum omap_channel channel)
618 {
619 if (dss_mgr_is_lcd(channel))
620 dispc_mgr_disable_lcd_out(channel);
621 else if (channel == OMAP_DSS_CHANNEL_DIGIT)
622 dispc_mgr_disable_digit_out();
623 else
624 WARN_ON(1);
625 }
626
dispc_irq_wait_handler(void * data,u32 mask)627 static inline void dispc_irq_wait_handler(void *data, u32 mask)
628 {
629 complete((struct completion *)data);
630 }
631
omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,unsigned long timeout)632 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
633 unsigned long timeout)
634 {
635
636 int r;
637 long time_left;
638 DECLARE_COMPLETION_ONSTACK(completion);
639
640 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
641 irqmask);
642
643 if (r)
644 return r;
645
646 time_left = wait_for_completion_interruptible_timeout(&completion,
647 timeout);
648
649 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
650
651 if (time_left == 0)
652 return -ETIMEDOUT;
653
654 if (time_left == -ERESTARTSYS)
655 return -ERESTARTSYS;
656
657 return 0;
658 }
659