This source file includes following definitions.
- dispc_dump_irqs
- _omap_dispc_set_irqs
- omap_dispc_register_isr
- omap_dispc_unregister_isr
- print_irq_status
- omap_dispc_irq_handler
- dispc_error_worker
- dss_dispc_initialize_irq
- dss_dispc_uninitialize_irq
- dispc_mgr_disable_isr
- dispc_mgr_enable_lcd_out
- dispc_mgr_disable_lcd_out
- dispc_digit_out_enable_isr
- dispc_mgr_enable_digit_out
- dispc_mgr_disable_digit_out
- dispc_mgr_enable_sync
- dispc_mgr_disable_sync
- dispc_irq_wait_handler
- omap_dispc_wait_for_irq_interruptible_timeout
1
2
3
4
5
6
7 #define DSS_SUBSYS_NAME "APPLY"
8
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>
17
18 #include <video/omapfb_dss.h>
19
20 #include "dss.h"
21 #include "dss_features.h"
22 #include "dispc-compat.h"
23
24 #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
25 DISPC_IRQ_OCP_ERR | \
26 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
27 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
28 DISPC_IRQ_SYNC_LOST | \
29 DISPC_IRQ_SYNC_LOST_DIGIT)
30
31 #define DISPC_MAX_NR_ISRS 8
32
33 struct omap_dispc_isr_data {
34 omap_dispc_isr_t isr;
35 void *arg;
36 u32 mask;
37 };
38
39 struct dispc_irq_stats {
40 unsigned long last_reset;
41 unsigned irq_count;
42 unsigned irqs[32];
43 };
44
45 static struct {
46 spinlock_t irq_lock;
47 u32 irq_error_mask;
48 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
49 u32 error_irqs;
50 struct work_struct error_work;
51
52 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
53 spinlock_t irq_stats_lock;
54 struct dispc_irq_stats irq_stats;
55 #endif
56 } dispc_compat;
57
58
59 #ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
60 static void dispc_dump_irqs(struct seq_file *s)
61 {
62 unsigned long flags;
63 struct dispc_irq_stats stats;
64
65 spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags);
66
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;
70
71 spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags);
72
73 seq_printf(s, "period %u ms\n",
74 jiffies_to_msecs(jiffies - stats.last_reset));
75
76 seq_printf(s, "irqs %d\n", stats.irq_count);
77 #define PIS(x) \
78 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
79
80 PIS(FRAMEDONE);
81 PIS(VSYNC);
82 PIS(EVSYNC_EVEN);
83 PIS(EVSYNC_ODD);
84 PIS(ACBIAS_COUNT_STAT);
85 PIS(PROG_LINE_NUM);
86 PIS(GFX_FIFO_UNDERFLOW);
87 PIS(GFX_END_WIN);
88 PIS(PAL_GAMMA_MASK);
89 PIS(OCP_ERR);
90 PIS(VID1_FIFO_UNDERFLOW);
91 PIS(VID1_END_WIN);
92 PIS(VID2_FIFO_UNDERFLOW);
93 PIS(VID2_END_WIN);
94 if (dss_feat_get_num_ovls() > 3) {
95 PIS(VID3_FIFO_UNDERFLOW);
96 PIS(VID3_END_WIN);
97 }
98 PIS(SYNC_LOST);
99 PIS(SYNC_LOST_DIGIT);
100 PIS(WAKEUP);
101 if (dss_has_feature(FEAT_MGR_LCD2)) {
102 PIS(FRAMEDONE2);
103 PIS(VSYNC2);
104 PIS(ACBIAS_COUNT_STAT2);
105 PIS(SYNC_LOST2);
106 }
107 if (dss_has_feature(FEAT_MGR_LCD3)) {
108 PIS(FRAMEDONE3);
109 PIS(VSYNC3);
110 PIS(ACBIAS_COUNT_STAT3);
111 PIS(SYNC_LOST3);
112 }
113 #undef PIS
114 }
115 #endif
116
117
118 static void _omap_dispc_set_irqs(void)
119 {
120 u32 mask;
121 int i;
122 struct omap_dispc_isr_data *isr_data;
123
124 mask = dispc_compat.irq_error_mask;
125
126 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
127 isr_data = &dispc_compat.registered_isr[i];
128
129 if (isr_data->isr == NULL)
130 continue;
131
132 mask |= isr_data->mask;
133 }
134
135 dispc_write_irqenable(mask);
136 }
137
138 int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
139 {
140 int i;
141 int ret;
142 unsigned long flags;
143 struct omap_dispc_isr_data *isr_data;
144
145 if (isr == NULL)
146 return -EINVAL;
147
148 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
149
150
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) {
155 ret = -EINVAL;
156 goto err;
157 }
158 }
159
160 isr_data = NULL;
161 ret = -EBUSY;
162
163 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
164 isr_data = &dispc_compat.registered_isr[i];
165
166 if (isr_data->isr != NULL)
167 continue;
168
169 isr_data->isr = isr;
170 isr_data->arg = arg;
171 isr_data->mask = mask;
172 ret = 0;
173
174 break;
175 }
176
177 if (ret)
178 goto err;
179
180 _omap_dispc_set_irqs();
181
182 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
183
184 return 0;
185 err:
186 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
187
188 return ret;
189 }
190 EXPORT_SYMBOL(omap_dispc_register_isr);
191
192 int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
193 {
194 int i;
195 unsigned long flags;
196 int ret = -EINVAL;
197 struct omap_dispc_isr_data *isr_data;
198
199 spin_lock_irqsave(&dispc_compat.irq_lock, flags);
200
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)
205 continue;
206
207
208
209 isr_data->isr = NULL;
210 isr_data->arg = NULL;
211 isr_data->mask = 0;
212
213 ret = 0;
214 break;
215 }
216
217 if (ret == 0)
218 _omap_dispc_set_irqs();
219
220 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
221
222 return ret;
223 }
224 EXPORT_SYMBOL(omap_dispc_unregister_isr);
225
226 static void print_irq_status(u32 status)
227 {
228 if ((status & dispc_compat.irq_error_mask) == 0)
229 return;
230
231 #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : ""
232
233 pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n",
234 status,
235 PIS(OCP_ERR),
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) : "",
240 PIS(SYNC_LOST),
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) : "");
244 #undef PIS
245 }
246
247
248
249
250
251 static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
252 {
253 int i;
254 u32 irqstatus, irqenable;
255 u32 handledirqs = 0;
256 u32 unhandled_errors;
257 struct omap_dispc_isr_data *isr_data;
258 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
259
260 spin_lock(&dispc_compat.irq_lock);
261
262 irqstatus = dispc_read_irqstatus();
263 irqenable = dispc_read_irqenable();
264
265
266 if (!(irqstatus & irqenable)) {
267 spin_unlock(&dispc_compat.irq_lock);
268 return IRQ_NONE;
269 }
270
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);
276 #endif
277
278 print_irq_status(irqstatus);
279
280
281
282 dispc_clear_irqstatus(irqstatus);
283
284 dispc_read_irqstatus();
285
286
287
288 memcpy(registered_isr, dispc_compat.registered_isr,
289 sizeof(registered_isr));
290
291 spin_unlock(&dispc_compat.irq_lock);
292
293 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
294 isr_data = ®istered_isr[i];
295
296 if (!isr_data->isr)
297 continue;
298
299 if (isr_data->mask & irqstatus) {
300 isr_data->isr(isr_data->arg, irqstatus);
301 handledirqs |= isr_data->mask;
302 }
303 }
304
305 spin_lock(&dispc_compat.irq_lock);
306
307 unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask;
308
309 if (unhandled_errors) {
310 dispc_compat.error_irqs |= unhandled_errors;
311
312 dispc_compat.irq_error_mask &= ~unhandled_errors;
313 _omap_dispc_set_irqs();
314
315 schedule_work(&dispc_compat.error_work);
316 }
317
318 spin_unlock(&dispc_compat.irq_lock);
319
320 return IRQ_HANDLED;
321 }
322
323 static void dispc_error_worker(struct work_struct *work)
324 {
325 int i;
326 u32 errors;
327 unsigned long flags;
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,
333 };
334
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);
339
340 dispc_runtime_get();
341
342 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
343 struct omap_overlay *ovl;
344 unsigned bit;
345
346 ovl = omap_dss_get_overlay(i);
347 bit = fifo_underflow_bits[i];
348
349 if (bit & errors) {
350 DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n",
351 ovl->name);
352 ovl->disable(ovl);
353 msleep(50);
354 }
355 }
356
357 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
358 struct omap_overlay_manager *mgr;
359 unsigned bit;
360
361 mgr = omap_dss_get_overlay_manager(i);
362 bit = dispc_mgr_get_sync_lost_irq(i);
363
364 if (bit & errors) {
365 int j;
366
367 DSSERR("SYNC_LOST on channel %s, restarting the output "
368 "with video overlays disabled\n",
369 mgr->name);
370
371 dss_mgr_disable(mgr);
372
373 for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
374 struct omap_overlay *ovl;
375 ovl = omap_dss_get_overlay(j);
376
377 if (ovl->id != OMAP_DSS_GFX &&
378 ovl->manager == mgr)
379 ovl->disable(ovl);
380 }
381
382 dss_mgr_enable(mgr);
383 }
384 }
385
386 if (errors & DISPC_IRQ_OCP_ERR) {
387 DSSERR("OCP_ERR\n");
388 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
389 struct omap_overlay_manager *mgr;
390
391 mgr = omap_dss_get_overlay_manager(i);
392 dss_mgr_disable(mgr);
393 }
394 }
395
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);
400
401 dispc_runtime_put();
402 }
403
404 int dss_dispc_initialize_irq(void)
405 {
406 int r;
407
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);
412 #endif
413
414 spin_lock_init(&dispc_compat.irq_lock);
415
416 memset(dispc_compat.registered_isr, 0,
417 sizeof(dispc_compat.registered_isr));
418
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;
426
427
428
429
430
431 dispc_clear_irqstatus(dispc_read_irqstatus());
432
433 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
434
435 _omap_dispc_set_irqs();
436
437 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
438 if (r) {
439 DSSERR("dispc_request_irq failed\n");
440 return r;
441 }
442
443 return 0;
444 }
445
446 void dss_dispc_uninitialize_irq(void)
447 {
448 dispc_free_irq(&dispc_compat);
449 }
450
451 static void dispc_mgr_disable_isr(void *data, u32 mask)
452 {
453 struct completion *compl = data;
454 complete(compl);
455 }
456
457 static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
458 {
459 dispc_mgr_enable(channel, true);
460 }
461
462 static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
463 {
464 DECLARE_COMPLETION_ONSTACK(framedone_compl);
465 int r;
466 u32 irq;
467
468 if (!dispc_mgr_is_enabled(channel))
469 return;
470
471
472
473
474
475
476 irq = dispc_mgr_get_framedone_irq(channel);
477
478 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
479 irq);
480 if (r)
481 DSSERR("failed to register FRAMEDONE isr\n");
482
483 dispc_mgr_enable(channel, false);
484
485
486 if (r) {
487 msleep(100);
488 return;
489 }
490
491 if (!wait_for_completion_timeout(&framedone_compl,
492 msecs_to_jiffies(100)))
493 DSSERR("timeout waiting for FRAME DONE\n");
494
495 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
496 irq);
497 if (r)
498 DSSERR("failed to unregister FRAMEDONE isr\n");
499 }
500
501 static void dispc_digit_out_enable_isr(void *data, u32 mask)
502 {
503 struct completion *compl = data;
504
505
506 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
507 complete(compl);
508 }
509
510 static void dispc_mgr_enable_digit_out(void)
511 {
512 DECLARE_COMPLETION_ONSTACK(vsync_compl);
513 int r;
514 u32 irq_mask;
515
516 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
517 return;
518
519
520
521
522
523
524
525 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
526 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
527
528 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
529 irq_mask);
530 if (r) {
531 DSSERR("failed to register %x isr\n", irq_mask);
532 return;
533 }
534
535 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
536
537
538 if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
539 DSSERR("timeout waiting for digit out to start\n");
540
541 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
542 irq_mask);
543 if (r)
544 DSSERR("failed to unregister %x isr\n", irq_mask);
545 }
546
547 static void dispc_mgr_disable_digit_out(void)
548 {
549 DECLARE_COMPLETION_ONSTACK(framedone_compl);
550 int r, i;
551 u32 irq_mask;
552 int num_irqs;
553
554 if (!dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT))
555 return;
556
557
558
559
560
561
562 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
563 num_irqs = 1;
564
565 if (!irq_mask) {
566
567
568
569
570
571 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
572
573
574
575
576
577
578 num_irqs = 2;
579 }
580
581 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
582 irq_mask);
583 if (r)
584 DSSERR("failed to register %x isr\n", irq_mask);
585
586 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
587
588
589 if (r) {
590 msleep(100);
591 return;
592 }
593
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");
598 }
599
600 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
601 irq_mask);
602 if (r)
603 DSSERR("failed to unregister %x isr\n", irq_mask);
604 }
605
606 void dispc_mgr_enable_sync(enum omap_channel channel)
607 {
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();
612 else
613 WARN_ON(1);
614 }
615
616 void dispc_mgr_disable_sync(enum omap_channel channel)
617 {
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();
622 else
623 WARN_ON(1);
624 }
625
626 static inline void dispc_irq_wait_handler(void *data, u32 mask)
627 {
628 complete((struct completion *)data);
629 }
630
631 int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
632 unsigned long timeout)
633 {
634
635 int r;
636 long time_left;
637 DECLARE_COMPLETION_ONSTACK(completion);
638
639 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
640 irqmask);
641
642 if (r)
643 return r;
644
645 time_left = wait_for_completion_interruptible_timeout(&completion,
646 timeout);
647
648 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
649
650 if (time_left == 0)
651 return -ETIMEDOUT;
652
653 if (time_left == -ERESTARTSYS)
654 return -ERESTARTSYS;
655
656 return 0;
657 }