linux/drivers/video/fbdev/omap2/omapfb/dss/dispc-compat.c
<<
>>
Prefs
   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/omapfb_dss.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_FB_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_FB_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_FB_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 = &registered_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
 334static 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                        ovl->disable(ovl);
 364                        msleep(50);
 365                }
 366        }
 367
 368        for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
 369                struct omap_overlay_manager *mgr;
 370                unsigned bit;
 371
 372                mgr = omap_dss_get_overlay_manager(i);
 373                bit = dispc_mgr_get_sync_lost_irq(i);
 374
 375                if (bit & errors) {
 376                        int j;
 377
 378                        DSSERR("SYNC_LOST on channel %s, restarting the output "
 379                                        "with video overlays disabled\n",
 380                                        mgr->name);
 381
 382                        dss_mgr_disable(mgr);
 383
 384                        for (j = 0; j < omap_dss_get_num_overlays(); ++j) {
 385                                struct omap_overlay *ovl;
 386                                ovl = omap_dss_get_overlay(j);
 387
 388                                if (ovl->id != OMAP_DSS_GFX &&
 389                                                ovl->manager == mgr)
 390                                        ovl->disable(ovl);
 391                        }
 392
 393                        dss_mgr_enable(mgr);
 394                }
 395        }
 396
 397        if (errors & DISPC_IRQ_OCP_ERR) {
 398                DSSERR("OCP_ERR\n");
 399                for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
 400                        struct omap_overlay_manager *mgr;
 401
 402                        mgr = omap_dss_get_overlay_manager(i);
 403                        dss_mgr_disable(mgr);
 404                }
 405        }
 406
 407        spin_lock_irqsave(&dispc_compat.irq_lock, flags);
 408        dispc_compat.irq_error_mask |= errors;
 409        _omap_dispc_set_irqs();
 410        spin_unlock_irqrestore(&dispc_compat.irq_lock, flags);
 411
 412        dispc_runtime_put();
 413}
 414
 415int dss_dispc_initialize_irq(void)
 416{
 417        int r;
 418
 419#ifdef CONFIG_FB_OMAP2_DSS_COLLECT_IRQ_STATS
 420        spin_lock_init(&dispc_compat.irq_stats_lock);
 421        dispc_compat.irq_stats.last_reset = jiffies;
 422        dss_debugfs_create_file("dispc_irq", dispc_dump_irqs);
 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))
 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))
 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))
 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
 637static inline void dispc_irq_wait_handler(void *data, u32 mask)
 638{
 639        complete((struct completion *)data);
 640}
 641
 642int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
 643                unsigned long timeout)
 644{
 645
 646        int r;
 647        long time_left;
 648        DECLARE_COMPLETION_ONSTACK(completion);
 649
 650        r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
 651                        irqmask);
 652
 653        if (r)
 654                return r;
 655
 656        time_left = wait_for_completion_interruptible_timeout(&completion,
 657                        timeout);
 658
 659        omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
 660
 661        if (time_left == 0)
 662                return -ETIMEDOUT;
 663
 664        if (time_left == -ERESTARTSYS)
 665                return -ERESTARTSYS;
 666
 667        return 0;
 668}
 669