sun4i_crtc.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /*
  2. * Copyright (C) 2015 Free Electrons
  3. * Copyright (C) 2015 NextThing Co
  4. *
  5. * Maxime Ripard <maxime.ripard@free-electrons.com>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. */
  12. #include <drm/drmP.h>
  13. #include <drm/drm_atomic_helper.h>
  14. #include <drm/drm_crtc.h>
  15. #include <drm/drm_crtc_helper.h>
  16. #include <drm/drm_modes.h>
  17. #include <linux/clk-provider.h>
  18. #include <linux/ioport.h>
  19. #include <linux/of_address.h>
  20. #include <linux/of_irq.h>
  21. #include <linux/regmap.h>
  22. #include <video/videomode.h>
  23. #include "sun4i_backend.h"
  24. #include "sun4i_crtc.h"
  25. #include "sun4i_drv.h"
  26. #include "sun4i_tcon.h"
  27. static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
  28. struct drm_crtc_state *old_state)
  29. {
  30. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  31. struct drm_device *dev = crtc->dev;
  32. unsigned long flags;
  33. if (crtc->state->event) {
  34. WARN_ON(drm_crtc_vblank_get(crtc) != 0);
  35. spin_lock_irqsave(&dev->event_lock, flags);
  36. scrtc->event = crtc->state->event;
  37. spin_unlock_irqrestore(&dev->event_lock, flags);
  38. crtc->state->event = NULL;
  39. }
  40. }
  41. static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
  42. struct drm_crtc_state *old_state)
  43. {
  44. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  45. struct sun4i_drv *drv = scrtc->drv;
  46. struct drm_pending_vblank_event *event = crtc->state->event;
  47. DRM_DEBUG_DRIVER("Committing plane changes\n");
  48. sun4i_backend_commit(drv->backend);
  49. if (event) {
  50. crtc->state->event = NULL;
  51. spin_lock_irq(&crtc->dev->event_lock);
  52. if (drm_crtc_vblank_get(crtc) == 0)
  53. drm_crtc_arm_vblank_event(crtc, event);
  54. else
  55. drm_crtc_send_vblank_event(crtc, event);
  56. spin_unlock_irq(&crtc->dev->event_lock);
  57. }
  58. }
  59. static void sun4i_crtc_disable(struct drm_crtc *crtc)
  60. {
  61. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  62. struct sun4i_drv *drv = scrtc->drv;
  63. DRM_DEBUG_DRIVER("Disabling the CRTC\n");
  64. sun4i_tcon_disable(drv->tcon);
  65. if (crtc->state->event && !crtc->state->active) {
  66. spin_lock_irq(&crtc->dev->event_lock);
  67. drm_crtc_send_vblank_event(crtc, crtc->state->event);
  68. spin_unlock_irq(&crtc->dev->event_lock);
  69. crtc->state->event = NULL;
  70. }
  71. }
  72. static void sun4i_crtc_enable(struct drm_crtc *crtc)
  73. {
  74. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  75. struct sun4i_drv *drv = scrtc->drv;
  76. DRM_DEBUG_DRIVER("Enabling the CRTC\n");
  77. sun4i_tcon_enable(drv->tcon);
  78. }
  79. static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
  80. .atomic_begin = sun4i_crtc_atomic_begin,
  81. .atomic_flush = sun4i_crtc_atomic_flush,
  82. .disable = sun4i_crtc_disable,
  83. .enable = sun4i_crtc_enable,
  84. };
  85. static const struct drm_crtc_funcs sun4i_crtc_funcs = {
  86. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  87. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  88. .destroy = drm_crtc_cleanup,
  89. .page_flip = drm_atomic_helper_page_flip,
  90. .reset = drm_atomic_helper_crtc_reset,
  91. .set_config = drm_atomic_helper_set_config,
  92. };
  93. struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
  94. {
  95. struct sun4i_drv *drv = drm->dev_private;
  96. struct sun4i_crtc *scrtc;
  97. int ret;
  98. scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
  99. if (!scrtc)
  100. return NULL;
  101. scrtc->drv = drv;
  102. ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
  103. drv->primary,
  104. NULL,
  105. &sun4i_crtc_funcs,
  106. NULL);
  107. if (ret) {
  108. dev_err(drm->dev, "Couldn't init DRM CRTC\n");
  109. return NULL;
  110. }
  111. drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
  112. return scrtc;
  113. }