mdp_kms.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2013 Red Hat
  4. * Author: Rob Clark <robdclark@gmail.com>
  5. */
  6. #include "msm_drv.h"
  7. #include "mdp_kms.h"
  8. struct mdp_irq_wait {
  9. struct mdp_irq irq;
  10. int count;
  11. };
  12. static DECLARE_WAIT_QUEUE_HEAD(wait_event);
  13. static DEFINE_SPINLOCK(list_lock);
  14. static void update_irq(struct mdp_kms *mdp_kms)
  15. {
  16. struct mdp_irq *irq;
  17. uint32_t irqmask = mdp_kms->vblank_mask;
  18. assert_spin_locked(&list_lock);
  19. list_for_each_entry(irq, &mdp_kms->irq_list, node)
  20. irqmask |= irq->irqmask;
  21. mdp_kms->funcs->set_irqmask(mdp_kms, irqmask, mdp_kms->cur_irq_mask);
  22. mdp_kms->cur_irq_mask = irqmask;
  23. }
  24. /* if an mdp_irq's irqmask has changed, such as when mdp5 crtc<->encoder
  25. * link changes, this must be called to figure out the new global irqmask
  26. */
  27. void mdp_irq_update(struct mdp_kms *mdp_kms)
  28. {
  29. unsigned long flags;
  30. spin_lock_irqsave(&list_lock, flags);
  31. update_irq(mdp_kms);
  32. spin_unlock_irqrestore(&list_lock, flags);
  33. }
  34. void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status)
  35. {
  36. struct mdp_irq *handler, *n;
  37. unsigned long flags;
  38. spin_lock_irqsave(&list_lock, flags);
  39. mdp_kms->in_irq = true;
  40. list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) {
  41. if (handler->irqmask & status) {
  42. spin_unlock_irqrestore(&list_lock, flags);
  43. handler->irq(handler, handler->irqmask & status);
  44. spin_lock_irqsave(&list_lock, flags);
  45. }
  46. }
  47. mdp_kms->in_irq = false;
  48. update_irq(mdp_kms);
  49. spin_unlock_irqrestore(&list_lock, flags);
  50. }
  51. void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
  52. {
  53. unsigned long flags;
  54. spin_lock_irqsave(&list_lock, flags);
  55. if (enable)
  56. mdp_kms->vblank_mask |= mask;
  57. else
  58. mdp_kms->vblank_mask &= ~mask;
  59. update_irq(mdp_kms);
  60. spin_unlock_irqrestore(&list_lock, flags);
  61. }
  62. static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus)
  63. {
  64. struct mdp_irq_wait *wait =
  65. container_of(irq, struct mdp_irq_wait, irq);
  66. wait->count--;
  67. wake_up_all(&wait_event);
  68. }
  69. void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)
  70. {
  71. struct mdp_irq_wait wait = {
  72. .irq = {
  73. .irq = wait_irq,
  74. .irqmask = irqmask,
  75. },
  76. .count = 1,
  77. };
  78. mdp_irq_register(mdp_kms, &wait.irq);
  79. wait_event_timeout(wait_event, (wait.count <= 0),
  80. msecs_to_jiffies(100));
  81. mdp_irq_unregister(mdp_kms, &wait.irq);
  82. }
  83. void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
  84. {
  85. unsigned long flags;
  86. bool needs_update = false;
  87. spin_lock_irqsave(&list_lock, flags);
  88. if (!irq->registered) {
  89. irq->registered = true;
  90. list_add(&irq->node, &mdp_kms->irq_list);
  91. needs_update = !mdp_kms->in_irq;
  92. }
  93. spin_unlock_irqrestore(&list_lock, flags);
  94. if (needs_update)
  95. mdp_irq_update(mdp_kms);
  96. }
  97. void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
  98. {
  99. unsigned long flags;
  100. bool needs_update = false;
  101. spin_lock_irqsave(&list_lock, flags);
  102. if (irq->registered) {
  103. irq->registered = false;
  104. list_del(&irq->node);
  105. needs_update = !mdp_kms->in_irq;
  106. }
  107. spin_unlock_irqrestore(&list_lock, flags);
  108. if (needs_update)
  109. mdp_irq_update(mdp_kms);
  110. }