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