dispc-compat.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 <video/omapdss.h>
  25. #include "dss.h"
  26. #include "dss_features.h"
  27. #include "dispc-compat.h"
  28. static void dispc_mgr_disable_isr(void *data, u32 mask)
  29. {
  30. struct completion *compl = data;
  31. complete(compl);
  32. }
  33. static void dispc_mgr_enable_lcd_out(enum omap_channel channel)
  34. {
  35. dispc_mgr_enable(channel, true);
  36. }
  37. static void dispc_mgr_disable_lcd_out(enum omap_channel channel)
  38. {
  39. DECLARE_COMPLETION_ONSTACK(framedone_compl);
  40. int r;
  41. u32 irq;
  42. if (dispc_mgr_is_enabled(channel) == false)
  43. return;
  44. /*
  45. * When we disable LCD output, we need to wait for FRAMEDONE to know
  46. * that DISPC has finished with the LCD output.
  47. */
  48. irq = dispc_mgr_get_framedone_irq(channel);
  49. r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
  50. irq);
  51. if (r)
  52. DSSERR("failed to register FRAMEDONE isr\n");
  53. dispc_mgr_enable(channel, false);
  54. /* if we couldn't register for framedone, just sleep and exit */
  55. if (r) {
  56. msleep(100);
  57. return;
  58. }
  59. if (!wait_for_completion_timeout(&framedone_compl,
  60. msecs_to_jiffies(100)))
  61. DSSERR("timeout waiting for FRAME DONE\n");
  62. r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
  63. irq);
  64. if (r)
  65. DSSERR("failed to unregister FRAMEDONE isr\n");
  66. }
  67. static void dispc_digit_out_enable_isr(void *data, u32 mask)
  68. {
  69. struct completion *compl = data;
  70. /* ignore any sync lost interrupts */
  71. if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD))
  72. complete(compl);
  73. }
  74. static void dispc_mgr_enable_digit_out(void)
  75. {
  76. DECLARE_COMPLETION_ONSTACK(vsync_compl);
  77. int r;
  78. u32 irq_mask;
  79. if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true)
  80. return;
  81. /*
  82. * Digit output produces some sync lost interrupts during the first
  83. * frame when enabling. Those need to be ignored, so we register for the
  84. * sync lost irq to prevent the error handler from triggering.
  85. */
  86. irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) |
  87. dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT);
  88. r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl,
  89. irq_mask);
  90. if (r) {
  91. DSSERR("failed to register %x isr\n", irq_mask);
  92. return;
  93. }
  94. dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true);
  95. /* wait for the first evsync */
  96. if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100)))
  97. DSSERR("timeout waiting for digit out to start\n");
  98. r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl,
  99. irq_mask);
  100. if (r)
  101. DSSERR("failed to unregister %x isr\n", irq_mask);
  102. }
  103. static void dispc_mgr_disable_digit_out(void)
  104. {
  105. DECLARE_COMPLETION_ONSTACK(framedone_compl);
  106. int r, i;
  107. u32 irq_mask;
  108. int num_irqs;
  109. if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false)
  110. return;
  111. /*
  112. * When we disable the digit output, we need to wait for FRAMEDONE to
  113. * know that DISPC has finished with the output.
  114. */
  115. irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT);
  116. num_irqs = 1;
  117. if (!irq_mask) {
  118. /*
  119. * omap 2/3 don't have framedone irq for TV, so we need to use
  120. * vsyncs for this.
  121. */
  122. irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT);
  123. /*
  124. * We need to wait for both even and odd vsyncs. Note that this
  125. * is not totally reliable, as we could get a vsync interrupt
  126. * before we disable the output, which leads to timeout in the
  127. * wait_for_completion.
  128. */
  129. num_irqs = 2;
  130. }
  131. r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl,
  132. irq_mask);
  133. if (r)
  134. DSSERR("failed to register %x isr\n", irq_mask);
  135. dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false);
  136. /* if we couldn't register the irq, just sleep and exit */
  137. if (r) {
  138. msleep(100);
  139. return;
  140. }
  141. for (i = 0; i < num_irqs; ++i) {
  142. if (!wait_for_completion_timeout(&framedone_compl,
  143. msecs_to_jiffies(100)))
  144. DSSERR("timeout waiting for digit out to stop\n");
  145. }
  146. r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl,
  147. irq_mask);
  148. if (r)
  149. DSSERR("failed to unregister %x isr\n", irq_mask);
  150. }
  151. void dispc_mgr_enable_sync(enum omap_channel channel)
  152. {
  153. if (dss_mgr_is_lcd(channel))
  154. dispc_mgr_enable_lcd_out(channel);
  155. else if (channel == OMAP_DSS_CHANNEL_DIGIT)
  156. dispc_mgr_enable_digit_out();
  157. else
  158. WARN_ON(1);
  159. }
  160. void dispc_mgr_disable_sync(enum omap_channel channel)
  161. {
  162. if (dss_mgr_is_lcd(channel))
  163. dispc_mgr_disable_lcd_out(channel);
  164. else if (channel == OMAP_DSS_CHANNEL_DIGIT)
  165. dispc_mgr_disable_digit_out();
  166. else
  167. WARN_ON(1);
  168. }