sun4i_crtc.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  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_graph.h>
  21. #include <linux/of_irq.h>
  22. #include <linux/regmap.h>
  23. #include <video/videomode.h>
  24. #include "sun4i_backend.h"
  25. #include "sun4i_crtc.h"
  26. #include "sun4i_drv.h"
  27. #include "sun4i_tcon.h"
  28. static void sun4i_crtc_atomic_begin(struct drm_crtc *crtc,
  29. struct drm_crtc_state *old_state)
  30. {
  31. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  32. struct drm_device *dev = crtc->dev;
  33. unsigned long flags;
  34. if (crtc->state->event) {
  35. WARN_ON(drm_crtc_vblank_get(crtc) != 0);
  36. spin_lock_irqsave(&dev->event_lock, flags);
  37. scrtc->event = crtc->state->event;
  38. spin_unlock_irqrestore(&dev->event_lock, flags);
  39. crtc->state->event = NULL;
  40. }
  41. }
  42. static void sun4i_crtc_atomic_flush(struct drm_crtc *crtc,
  43. struct drm_crtc_state *old_state)
  44. {
  45. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  46. struct sun4i_drv *drv = scrtc->drv;
  47. struct drm_pending_vblank_event *event = crtc->state->event;
  48. DRM_DEBUG_DRIVER("Committing plane changes\n");
  49. sun4i_backend_commit(drv->backend);
  50. if (event) {
  51. crtc->state->event = NULL;
  52. spin_lock_irq(&crtc->dev->event_lock);
  53. if (drm_crtc_vblank_get(crtc) == 0)
  54. drm_crtc_arm_vblank_event(crtc, event);
  55. else
  56. drm_crtc_send_vblank_event(crtc, event);
  57. spin_unlock_irq(&crtc->dev->event_lock);
  58. }
  59. }
  60. static void sun4i_crtc_disable(struct drm_crtc *crtc)
  61. {
  62. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  63. struct sun4i_drv *drv = scrtc->drv;
  64. DRM_DEBUG_DRIVER("Disabling the CRTC\n");
  65. sun4i_tcon_disable(drv->tcon);
  66. if (crtc->state->event && !crtc->state->active) {
  67. spin_lock_irq(&crtc->dev->event_lock);
  68. drm_crtc_send_vblank_event(crtc, crtc->state->event);
  69. spin_unlock_irq(&crtc->dev->event_lock);
  70. crtc->state->event = NULL;
  71. }
  72. }
  73. static void sun4i_crtc_enable(struct drm_crtc *crtc)
  74. {
  75. struct sun4i_crtc *scrtc = drm_crtc_to_sun4i_crtc(crtc);
  76. struct sun4i_drv *drv = scrtc->drv;
  77. DRM_DEBUG_DRIVER("Enabling the CRTC\n");
  78. sun4i_tcon_enable(drv->tcon);
  79. }
  80. static const struct drm_crtc_helper_funcs sun4i_crtc_helper_funcs = {
  81. .atomic_begin = sun4i_crtc_atomic_begin,
  82. .atomic_flush = sun4i_crtc_atomic_flush,
  83. .disable = sun4i_crtc_disable,
  84. .enable = sun4i_crtc_enable,
  85. };
  86. static const struct drm_crtc_funcs sun4i_crtc_funcs = {
  87. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  88. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  89. .destroy = drm_crtc_cleanup,
  90. .page_flip = drm_atomic_helper_page_flip,
  91. .reset = drm_atomic_helper_crtc_reset,
  92. .set_config = drm_atomic_helper_set_config,
  93. };
  94. struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm)
  95. {
  96. struct sun4i_drv *drv = drm->dev_private;
  97. struct sun4i_crtc *scrtc;
  98. int ret;
  99. scrtc = devm_kzalloc(drm->dev, sizeof(*scrtc), GFP_KERNEL);
  100. if (!scrtc)
  101. return NULL;
  102. scrtc->drv = drv;
  103. ret = drm_crtc_init_with_planes(drm, &scrtc->crtc,
  104. drv->primary,
  105. NULL,
  106. &sun4i_crtc_funcs,
  107. NULL);
  108. if (ret) {
  109. dev_err(drm->dev, "Couldn't init DRM CRTC\n");
  110. return NULL;
  111. }
  112. drm_crtc_helper_add(&scrtc->crtc, &sun4i_crtc_helper_funcs);
  113. /* Set crtc.port to output port node of the tcon */
  114. scrtc->crtc.port = of_graph_get_port_by_id(drv->tcon->dev->of_node,
  115. 1);
  116. return scrtc;
  117. }