tidss_irq.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com/
  4. * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
  5. */
  6. #include <linux/platform_device.h>
  7. #include <drm/drm_drv.h>
  8. #include <drm/drm_print.h>
  9. #include "tidss_crtc.h"
  10. #include "tidss_dispc.h"
  11. #include "tidss_drv.h"
  12. #include "tidss_irq.h"
  13. #include "tidss_plane.h"
  14. static void tidss_irq_update(struct tidss_device *tidss)
  15. {
  16. assert_spin_locked(&tidss->irq_lock);
  17. dispc_set_irqenable(tidss->dispc, tidss->irq_mask);
  18. }
  19. void tidss_irq_enable_vblank(struct drm_crtc *crtc)
  20. {
  21. struct drm_device *ddev = crtc->dev;
  22. struct tidss_device *tidss = to_tidss(ddev);
  23. struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  24. u32 hw_videoport = tcrtc->hw_videoport;
  25. unsigned long flags;
  26. spin_lock_irqsave(&tidss->irq_lock, flags);
  27. tidss->irq_mask |= DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
  28. DSS_IRQ_VP_VSYNC_ODD(hw_videoport);
  29. tidss_irq_update(tidss);
  30. spin_unlock_irqrestore(&tidss->irq_lock, flags);
  31. }
  32. void tidss_irq_disable_vblank(struct drm_crtc *crtc)
  33. {
  34. struct drm_device *ddev = crtc->dev;
  35. struct tidss_device *tidss = to_tidss(ddev);
  36. struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  37. u32 hw_videoport = tcrtc->hw_videoport;
  38. unsigned long flags;
  39. spin_lock_irqsave(&tidss->irq_lock, flags);
  40. tidss->irq_mask &= ~(DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
  41. DSS_IRQ_VP_VSYNC_ODD(hw_videoport));
  42. tidss_irq_update(tidss);
  43. spin_unlock_irqrestore(&tidss->irq_lock, flags);
  44. }
  45. static irqreturn_t tidss_irq_handler(int irq, void *arg)
  46. {
  47. struct drm_device *ddev = (struct drm_device *)arg;
  48. struct tidss_device *tidss = to_tidss(ddev);
  49. unsigned int id;
  50. dispc_irq_t irqstatus;
  51. spin_lock(&tidss->irq_lock);
  52. irqstatus = dispc_read_and_clear_irqstatus(tidss->dispc);
  53. spin_unlock(&tidss->irq_lock);
  54. for (id = 0; id < tidss->num_crtcs; id++) {
  55. struct drm_crtc *crtc = tidss->crtcs[id];
  56. struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
  57. u32 hw_videoport = tcrtc->hw_videoport;
  58. if (irqstatus & (DSS_IRQ_VP_VSYNC_EVEN(hw_videoport) |
  59. DSS_IRQ_VP_VSYNC_ODD(hw_videoport)))
  60. tidss_crtc_vblank_irq(crtc);
  61. if (irqstatus & (DSS_IRQ_VP_FRAME_DONE(hw_videoport)))
  62. tidss_crtc_framedone_irq(crtc);
  63. if (irqstatus & DSS_IRQ_VP_SYNC_LOST(hw_videoport))
  64. tidss_crtc_error_irq(crtc, irqstatus);
  65. }
  66. for (unsigned int i = 0; i < tidss->num_planes; ++i) {
  67. struct drm_plane *plane = tidss->planes[i];
  68. struct tidss_plane *tplane = to_tidss_plane(plane);
  69. if (irqstatus & DSS_IRQ_PLANE_FIFO_UNDERFLOW(tplane->hw_plane_id))
  70. tidss_plane_error_irq(plane, irqstatus);
  71. }
  72. return IRQ_HANDLED;
  73. }
  74. void tidss_irq_resume(struct tidss_device *tidss)
  75. {
  76. unsigned long flags;
  77. spin_lock_irqsave(&tidss->irq_lock, flags);
  78. tidss_irq_update(tidss);
  79. spin_unlock_irqrestore(&tidss->irq_lock, flags);
  80. }
  81. int tidss_irq_install(struct drm_device *ddev, unsigned int irq)
  82. {
  83. struct tidss_device *tidss = to_tidss(ddev);
  84. int ret;
  85. if (irq == IRQ_NOTCONNECTED)
  86. return -ENOTCONN;
  87. ret = request_irq(irq, tidss_irq_handler, 0, ddev->driver->name, ddev);
  88. if (ret)
  89. return ret;
  90. tidss->irq_mask = 0;
  91. for (unsigned int i = 0; i < tidss->num_crtcs; ++i) {
  92. struct tidss_crtc *tcrtc = to_tidss_crtc(tidss->crtcs[i]);
  93. tidss->irq_mask |= DSS_IRQ_VP_SYNC_LOST(tcrtc->hw_videoport);
  94. tidss->irq_mask |= DSS_IRQ_VP_FRAME_DONE(tcrtc->hw_videoport);
  95. }
  96. for (unsigned int i = 0; i < tidss->num_planes; ++i) {
  97. struct tidss_plane *tplane = to_tidss_plane(tidss->planes[i]);
  98. tidss->irq_mask |= DSS_IRQ_PLANE_FIFO_UNDERFLOW(tplane->hw_plane_id);
  99. }
  100. return 0;
  101. }
  102. void tidss_irq_uninstall(struct drm_device *ddev)
  103. {
  104. struct tidss_device *tidss = to_tidss(ddev);
  105. free_irq(tidss->irq, ddev);
  106. }