dispc-compat.c 15 KB

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