aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbdev/omap2/dss/dispc-compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/omap2/dss/dispc-compat.c')
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc-compat.c666
1 files changed, 666 insertions, 0 deletions
<if((evsel->attr.sample_type & PERF_SAMPLE_RAW) && sample->raw_size >0) {char*event_str;#ifdef SUPPORT_OLD_POWER_EVENTSstruct power_entry_old *peo; peo = (void*)te;#endif/* * FIXME: use evsel, its already mapped from id to perf_evsel, * remove perf_header__find_event infrastructure bits. * Mapping all these "power:cpu_idle" strings to the tracepoint * ID and then just comparing against evsel->attr.config. * * e.g.: * * if (evsel->attr.config == power_cpu_idle_id) */ event_str =perf_header__find_event(te->type);if(!event_str)return0;if(sample->cpu > numcpus) numcpus = sample->cpu;if(strcmp(event_str,"power:cpu_idle") ==0) {struct power_processor_entry *ppe = (void*)te;if(ppe->state == (u32)PWR_EVENT_EXIT)c_state_end(ppe->cpu_id, sample->time);elsec_state_start(ppe->cpu_id, sample->time, ppe->state);}else if(strcmp(event_str,"power:cpu_frequency") ==0) {struct power_processor_entry *ppe = (void*)te;p_state_change(ppe->cpu_id, sample->time, ppe->state);}else if(strcmp(event_str,"sched:sched_wakeup") ==0)sched_wakeup(sample->cpu, sample->time, sample->pid, te);else if(strcmp(event_str,"sched:sched_switch") ==0)sched_switch(sample->cpu, sample->time, te);#ifdef SUPPORT_OLD_POWER_EVENTSif(use_old_power_events) {if(strcmp(event_str,"power:power_start") ==0)c_state_start(peo->cpu_id, sample->time, peo->value);else if(strcmp(event_str,"power:power_end") ==0)c_state_end(sample->cpu, sample->time);else if(strcmp(event_str,"power:power_frequency") ==0)p_state_change(peo->cpu_id, sample->time, peo->value);}#endif}return0;}/* * After the last sample we need to wrap up the current C/P state * and close out each CPU for these. */static voidend_sample_processing(void){ u64 cpu;struct power_event *pwr;for(cpu =0; cpu <= numcpus; cpu++) { pwr =malloc(sizeof(struct power_event));if(!pwr)return;memset(pwr,0,sizeof(struct power_event));/* C state */#if 0 pwr->state = cpus_cstate_state[cpu]; pwr->start_time = cpus_cstate_start_times[cpu]; pwr->end_time = last_time; pwr->cpu = cpu; pwr->type = CSTATE; pwr->next = power_events; power_events = pwr;#endif/* P state */ pwr =malloc(sizeof(struct power_event));if(!pwr)return;memset(pwr,0,sizeof(struct power_event)); pwr->state = cpus_pstate_state[cpu]; pwr->start_time = cpus_pstate_start_times[cpu]; pwr->end_time = last_time; pwr->cpu = cpu; pwr->type = PSTATE; pwr->next = power_events;if(!pwr->start_time) pwr->start_time = first_time;if(!pwr->state) pwr->state = min_freq; power_events = pwr;}}/* * Sort the pid datastructure */static voidsort_pids(void){struct per_pid *new_list, *p, *cursor, *prev;/* sort by ppid first, then by pid, lowest to highest */ new_list = NULL;while(all_data) { p = all_data; all_data = p->next; p->next = NULL;if(new_list == NULL) { new_list = p; p->next = NULL;continue;} prev = NULL; cursor = new_list;while(cursor) {if(cursor->ppid > p->ppid ||(cursor->ppid == p->ppid && cursor->pid > p->pid)) {/* must insert before */if(prev) { p->next = prev->next; prev->next = p; cursor = NULL;continue;}else{ p->next = new_list; new_list = p; cursor = NULL;continue;}} prev = cursor; cursor = cursor->next;if(!cursor) prev->next = p;}} all_data = new_list;}static voiddraw_c_p_states(void){struct power_event *pwr; pwr = power_events;/* * two pass drawing so that the P state bars are on top of the C state blocks */while(pwr) {if(pwr->type == CSTATE)svg_cstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state); pwr = pwr->next;} pwr = power_events;while(pwr) {if(pwr->type == PSTATE) {if(!pwr->state) pwr->state = min_freq;svg_pstate(pwr->cpu, pwr->start_time, pwr->end_time, pwr->state);} pwr = pwr->next;}}static voiddraw_wakeups(void){struct wake_event *we;struct per_pid *p;struct per_pidcomm *c; we = wake_events;while(we) {int from =0, to =0;char*task_from = NULL, *task_to = NULL;/* locate the column of the waker and wakee */ p = all_data;while(p) {if(p->pid == we->waker || p->pid == we->wakee) { c = p->all;while(c) {if(c->Y && c->start_time <= we->time && c->end_time >= we->time) {if(p->pid == we->waker && !from) { from = c->Y; task_from =strdup(c->comm);}if(p->pid == we->wakee && !to) { to = c->Y; task_to =strdup(c->comm);}} c = c->next;} c = p->all;while(c) {if(p->pid == we->waker && !from) { from = c->Y; task_from =strdup(c->comm);}if(p->pid == we->wakee && !to) { to = c->Y; task_to =strdup(c->comm);} c = c->next;}} p = p->next;}if(!task_from) { task_from =malloc(40);sprintf(task_from,"[%i]", we->waker);}if(!task_to) { task_to =malloc(40);sprintf(task_to,"[%i]", we->wakee);}if(we->waker == -1)svg_interrupt(we->time, to);else if(from && to &&abs(from - to) ==1)svg_wakeline(we->time, from, to);elsesvg_partial_wakeline(we->time, from, task_from, to, task_to); we = we->next;free(task_from);free(task_to);}}static voiddraw_cpu_usage(void){struct per_pid *p;struct per_pidcomm *c;struct cpu_sample *sample; p = all_data;while(p) { c = p->all;while(c) { sample = c->samples;while(sample) {if(sample->type == TYPE_RUNNING)svg_process(sample->cpu, sample->start_time, sample->end_time,"sample", c->comm); sample = sample->next;} c = c->next;} p = p->next;}}static voiddraw_process_bars(void){struct per_pid *p;struct per_pidcomm *c;struct cpu_sample *sample;int Y =0; Y =2* numcpus +2; p = all_data;while(p) { c = p->all;while(c) {if(!c->display) { c->Y =0; c = c->next;continue;}svg_box(Y, c->start_time, c->end_time,"process"); sample = c->samples;while(sample) {if(sample->type == TYPE_RUNNING)svg_sample(Y, sample->cpu, sample->start_time, sample->end_time);if(sample->type == TYPE_BLOCKED)svg_box(Y, sample->start_time, sample->end_time,"blocked");if(sample->type == TYPE_WAITING)svg_waiting(Y, sample->start_time, sample->end_time); sample = sample->next;}if(c->comm) {char comm[256];if(c->total_time >5000000000)/* 5 seconds */sprintf(comm,"%s:%i (%2.2fs)", c->comm, p->pid, c->total_time /1000000000.0);elsesprintf(comm,"%s:%i (%3.1fms)", c->comm, p->pid, c->total_time /1000000.0);svg_text(Y, c->start_time, comm);} c->Y = Y; Y++; c = c->next;} p = p->next;}}static voidadd_process_filter(const char*string){struct process_filter *filt;int pid; pid =strtoull(string, NULL,10); filt =malloc(sizeof(struct process_filter));if(!filt)return;>
diff --git a/drivers/video/fbdev/omap2/dss/dispc-compat.c b/drivers/video/fbdev/omap2/dss/dispc-compat.c
new file mode 100644
index 000000000000..83779c2b292a
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/dispc-compat.c
@@ -0,0 +1,666 @@
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
44struct omap_dispc_isr_data {
45 omap_dispc_isr_t isr;
46 void *arg;
47 u32 mask;
48};
49
50struct dispc_irq_stats {
51 unsigned long last_reset;
52 unsigned irq_count;
53 unsigned irqs[32];
54};
55
56static 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
71static 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 */
129static 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
149int 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;
196err:
197 spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
198
199 return ret;
200}
201EXPORT_SYMBOL(omap_dispc_register_isr);
202
203int 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}
235EXPORT_SYMBOL(omap_dispc_unregister_isr);
236
237static 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. */
262static 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 423#endif
424
425 spin_lock_init(&dispc_compat.irq_lock);
426
427 memset(dispc_compat.registered_isr, 0,
428 sizeof(dispc_compat.registered_isr));
429
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;
437
438 /*
439 * there's SYNC_LOST_DIGIT waiting after enabling the DSS,
440 * so clear it
441 */
442 dispc_clear_irqstatus(dispc_read_irqstatus());
443
444 INIT_WORK(&dispc_compat.error_work, dispc_error_worker);
445
446 _omap_dispc_set_irqs();
447
448 r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat);
449 if (r) {
450 DSSERR("dispc_request_irq failed\n");
451 return r;
452 }
453
454 return 0;
455}
456
457void dss_dispc_uninitialize_irq(void)
458{
459 dispc_free_irq(&dispc_compat);
460}
461
462static void dispc_mgr_disable_isr(void *data, u32 mask)
463{
464 struct completion *compl = data;
465 complete(compl);
466}
467
468static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
469{
470 dispc_mgr_enable(channel, true);
471}
472
473static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
474{
475 DECLARE_COMPLETION_ONSTACK(framedone_compl);
476 int r;
477 u32 irq;
478
479 if (dispc_mgr_is_enabled(channel) == false)
480 return;
481
482 /*
483 * When we disable LCD output, we need to wait for FRAMEDONE to know
484 * that DISPC has finished with the LCD output.
485 */
486
487 irq = dispc_mgr_get_framedone_irq(channel);
488
489 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
490 irq);
491 if (r)
492 DSSERR("failed to register FRAMEDONE isr\n");
493
494 dispc_mgr_enable(channel, false);
495
496 /* if we couldn't register for framedone, just sleep and exit */
497 if (r) {
498 msleep(100);
499 return;
500 }
501
502 if (!wait_for_completion_timeout(&framedone_compl,
503 msecs_to_jiffies(100)))
504 DSSERR("timeout waiting for FRAME DONE\n");
505
506 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
507 irq);
508 if (r)
509 DSSERR("failed to unregister FRAMEDONE isr\n");
510}
511
512static void dispc_digit_out_enable_isr(void *data, u32 mask)
513{
514 struct completion *compl = data;
515
516 /* ignore any sync lost interrupts */
517 if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
518 complete(compl);
519}
520
521static void dispc_mgr_enable_digit_out(void)
522{
523 DECLARE_COMPLETION_ONSTACK(vsync_compl);
524 int r;
525 u32 irq_mask;
526
527 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
528 return;
529
530 /*
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.
534 */
535
536 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
537 dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
538
539 r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
540 irq_mask);
541 if (r) {
542 DSSERR("failed to register %x isr\n", irq_mask);
543 return;
544 }
545
546 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
547
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");
551
552 r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
553 irq_mask);
554 if (r)
555 DSSERR("failed to unregister %x isr\n", irq_mask);
556}
557
558static void dispc_mgr_disable_digit_out(void)
559{
560 DECLARE_COMPLETION_ONSTACK(framedone_compl);
561 int r, i;
562 u32 irq_mask;
563 int num_irqs;
564
565 if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
566 return;
567
568 /*
569 * When we disable the digit output, we need to wait for FRAMEDONE to
570 * know that DISPC has finished with the output.
571 */
572
573 irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
574 num_irqs = 1;
575
576 if (!irq_mask) {
577 /*
578 * omap 2/3 don't have framedone irq for TV, so we need to use
579 * vsyncs for this.
580 */
581
582 irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
583 /*
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.
588 */
589 num_irqs = 2;
590 }
591
592 r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
593 irq_mask);
594 if (r)
595 DSSERR("failed to register %x isr\n", irq_mask);
596
597 dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
598
599 /* if we couldn't register the irq, just sleep and exit */
600 if (r) {
601 msleep(100);
602 return;
603 }
604
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");
609 }
610
611 r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
612 irq_mask);
613 if (r)
614 DSSERR("failed to unregister %x isr\n", irq_mask);
615}
616
617void dispc_mgr_enable_sync(enum omap_channel channel)
618{
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();
623 else
624 WARN_ON(1);
625}
626
627void dispc_mgr_disable_sync(enum omap_channel channel)
628{
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();
633 else
634 WARN_ON(1);
635}
636
637int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
638 unsigned long timeout)
639{
640 void dispc_irq_wait_handler(void *data, u32 mask)
641 {
642 complete((struct completion *)data);
643 }
644
645 int r;
646 DECLARE_COMPLETION_ONSTACK(completion);
647
648 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
649 irqmask);
650
651 if (r)
652 return r;
653
654 timeout = wait_for_completion_interruptible_timeout(&completion,
655 timeout);
656
657 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
658
659 if (timeout == 0)
660 return -ETIMEDOUT;
661
662 if (timeout == -ERESTARTSYS)
663 return -ERESTARTSYS;
664
665 return 0;
666}