logicvc_crtc.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright (C) 2019-2022 Bootlin
  4. * Author: Paul Kocialkowski <paul.kocialkowski@bootlin.com>
  5. */
  6. #include <linux/of.h>
  7. #include <linux/of_graph.h>
  8. #include <linux/types.h>
  9. #include <linux/workqueue.h>
  10. #include <drm/drm_atomic_helper.h>
  11. #include <drm/drm_crtc.h>
  12. #include <drm/drm_drv.h>
  13. #include <drm/drm_gem_dma_helper.h>
  14. #include <drm/drm_print.h>
  15. #include <drm/drm_vblank.h>
  16. #include "logicvc_crtc.h"
  17. #include "logicvc_drm.h"
  18. #include "logicvc_interface.h"
  19. #include "logicvc_layer.h"
  20. #include "logicvc_regs.h"
  21. #define logicvc_crtc(c) \
  22. container_of(c, struct logicvc_crtc, drm_crtc)
  23. static enum drm_mode_status
  24. logicvc_crtc_mode_valid(struct drm_crtc *drm_crtc,
  25. const struct drm_display_mode *mode)
  26. {
  27. if (mode->flags & DRM_MODE_FLAG_INTERLACE)
  28. return -EINVAL;
  29. return 0;
  30. }
  31. static void logicvc_crtc_atomic_begin(struct drm_crtc *drm_crtc,
  32. struct drm_atomic_state *state)
  33. {
  34. struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);
  35. struct drm_crtc_state *old_state =
  36. drm_atomic_get_old_crtc_state(state, drm_crtc);
  37. struct drm_device *drm_dev = drm_crtc->dev;
  38. unsigned long flags;
  39. /*
  40. * We need to grab the pending event here if vblank was already enabled
  41. * since we won't get a call to atomic_enable to grab it.
  42. */
  43. if (drm_crtc->state->event && old_state->active) {
  44. spin_lock_irqsave(&drm_dev->event_lock, flags);
  45. WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);
  46. crtc->event = drm_crtc->state->event;
  47. drm_crtc->state->event = NULL;
  48. spin_unlock_irqrestore(&drm_dev->event_lock, flags);
  49. }
  50. }
  51. static void logicvc_crtc_atomic_enable(struct drm_crtc *drm_crtc,
  52. struct drm_atomic_state *state)
  53. {
  54. struct logicvc_crtc *crtc = logicvc_crtc(drm_crtc);
  55. struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
  56. struct drm_crtc_state *old_state =
  57. drm_atomic_get_old_crtc_state(state, drm_crtc);
  58. struct drm_crtc_state *new_state =
  59. drm_atomic_get_new_crtc_state(state, drm_crtc);
  60. struct drm_display_mode *mode = &new_state->adjusted_mode;
  61. struct drm_device *drm_dev = drm_crtc->dev;
  62. unsigned int hact, hfp, hsl, hbp;
  63. unsigned int vact, vfp, vsl, vbp;
  64. unsigned long flags;
  65. u32 ctrl;
  66. /* Timings */
  67. hact = mode->hdisplay;
  68. hfp = mode->hsync_start - mode->hdisplay;
  69. hsl = mode->hsync_end - mode->hsync_start;
  70. hbp = mode->htotal - mode->hsync_end;
  71. vact = mode->vdisplay;
  72. vfp = mode->vsync_start - mode->vdisplay;
  73. vsl = mode->vsync_end - mode->vsync_start;
  74. vbp = mode->vtotal - mode->vsync_end;
  75. regmap_write(logicvc->regmap, LOGICVC_HSYNC_FRONT_PORCH_REG, hfp - 1);
  76. regmap_write(logicvc->regmap, LOGICVC_HSYNC_REG, hsl - 1);
  77. regmap_write(logicvc->regmap, LOGICVC_HSYNC_BACK_PORCH_REG, hbp - 1);
  78. regmap_write(logicvc->regmap, LOGICVC_HRES_REG, hact - 1);
  79. regmap_write(logicvc->regmap, LOGICVC_VSYNC_FRONT_PORCH_REG, vfp - 1);
  80. regmap_write(logicvc->regmap, LOGICVC_VSYNC_REG, vsl - 1);
  81. regmap_write(logicvc->regmap, LOGICVC_VSYNC_BACK_PORCH_REG, vbp - 1);
  82. regmap_write(logicvc->regmap, LOGICVC_VRES_REG, vact - 1);
  83. /* Signals */
  84. ctrl = LOGICVC_CTRL_HSYNC_ENABLE | LOGICVC_CTRL_VSYNC_ENABLE |
  85. LOGICVC_CTRL_DE_ENABLE;
  86. if (mode->flags & DRM_MODE_FLAG_NHSYNC)
  87. ctrl |= LOGICVC_CTRL_HSYNC_INVERT;
  88. if (mode->flags & DRM_MODE_FLAG_NVSYNC)
  89. ctrl |= LOGICVC_CTRL_VSYNC_INVERT;
  90. if (logicvc->interface) {
  91. struct drm_connector *connector =
  92. &logicvc->interface->drm_connector;
  93. struct drm_display_info *display_info =
  94. &connector->display_info;
  95. if (display_info->bus_flags & DRM_BUS_FLAG_DE_LOW)
  96. ctrl |= LOGICVC_CTRL_DE_INVERT;
  97. if (display_info->bus_flags &
  98. DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE)
  99. ctrl |= LOGICVC_CTRL_CLOCK_INVERT;
  100. }
  101. regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,
  102. LOGICVC_CTRL_HSYNC_ENABLE |
  103. LOGICVC_CTRL_HSYNC_INVERT |
  104. LOGICVC_CTRL_VSYNC_ENABLE |
  105. LOGICVC_CTRL_VSYNC_INVERT |
  106. LOGICVC_CTRL_DE_ENABLE |
  107. LOGICVC_CTRL_DE_INVERT |
  108. LOGICVC_CTRL_PIXEL_INVERT |
  109. LOGICVC_CTRL_CLOCK_INVERT, ctrl);
  110. /* Generate internal state reset. */
  111. regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);
  112. drm_crtc_vblank_on(drm_crtc);
  113. /* Register our event after vblank is enabled. */
  114. if (drm_crtc->state->event && !old_state->active) {
  115. spin_lock_irqsave(&drm_dev->event_lock, flags);
  116. WARN_ON(drm_crtc_vblank_get(drm_crtc) != 0);
  117. crtc->event = drm_crtc->state->event;
  118. drm_crtc->state->event = NULL;
  119. spin_unlock_irqrestore(&drm_dev->event_lock, flags);
  120. }
  121. }
  122. static void logicvc_crtc_atomic_disable(struct drm_crtc *drm_crtc,
  123. struct drm_atomic_state *state)
  124. {
  125. struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
  126. struct drm_device *drm_dev = drm_crtc->dev;
  127. drm_crtc_vblank_off(drm_crtc);
  128. /* Disable and clear CRTC bits. */
  129. regmap_update_bits(logicvc->regmap, LOGICVC_CTRL_REG,
  130. LOGICVC_CTRL_HSYNC_ENABLE |
  131. LOGICVC_CTRL_HSYNC_INVERT |
  132. LOGICVC_CTRL_VSYNC_ENABLE |
  133. LOGICVC_CTRL_VSYNC_INVERT |
  134. LOGICVC_CTRL_DE_ENABLE |
  135. LOGICVC_CTRL_DE_INVERT |
  136. LOGICVC_CTRL_PIXEL_INVERT |
  137. LOGICVC_CTRL_CLOCK_INVERT, 0);
  138. /* Generate internal state reset. */
  139. regmap_write(logicvc->regmap, LOGICVC_DTYPE_REG, 0);
  140. /* Consume any leftover event since vblank is now disabled. */
  141. if (drm_crtc->state->event && !drm_crtc->state->active) {
  142. spin_lock_irq(&drm_dev->event_lock);
  143. drm_crtc_send_vblank_event(drm_crtc, drm_crtc->state->event);
  144. drm_crtc->state->event = NULL;
  145. spin_unlock_irq(&drm_dev->event_lock);
  146. }
  147. }
  148. static const struct drm_crtc_helper_funcs logicvc_crtc_helper_funcs = {
  149. .mode_valid = logicvc_crtc_mode_valid,
  150. .atomic_begin = logicvc_crtc_atomic_begin,
  151. .atomic_enable = logicvc_crtc_atomic_enable,
  152. .atomic_disable = logicvc_crtc_atomic_disable,
  153. };
  154. static int logicvc_crtc_enable_vblank(struct drm_crtc *drm_crtc)
  155. {
  156. struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
  157. /* Clear any pending V_SYNC interrupt. */
  158. regmap_write_bits(logicvc->regmap, LOGICVC_INT_STAT_REG,
  159. LOGICVC_INT_STAT_V_SYNC, LOGICVC_INT_STAT_V_SYNC);
  160. /* Unmask V_SYNC interrupt. */
  161. regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,
  162. LOGICVC_INT_MASK_V_SYNC, 0);
  163. return 0;
  164. }
  165. static void logicvc_crtc_disable_vblank(struct drm_crtc *drm_crtc)
  166. {
  167. struct logicvc_drm *logicvc = logicvc_drm(drm_crtc->dev);
  168. /* Mask V_SYNC interrupt. */
  169. regmap_write_bits(logicvc->regmap, LOGICVC_INT_MASK_REG,
  170. LOGICVC_INT_MASK_V_SYNC, LOGICVC_INT_MASK_V_SYNC);
  171. }
  172. static const struct drm_crtc_funcs logicvc_crtc_funcs = {
  173. .reset = drm_atomic_helper_crtc_reset,
  174. .destroy = drm_crtc_cleanup,
  175. .set_config = drm_atomic_helper_set_config,
  176. .page_flip = drm_atomic_helper_page_flip,
  177. .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
  178. .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
  179. .enable_vblank = logicvc_crtc_enable_vblank,
  180. .disable_vblank = logicvc_crtc_disable_vblank,
  181. };
  182. void logicvc_crtc_vblank_handler(struct logicvc_drm *logicvc)
  183. {
  184. struct drm_device *drm_dev = &logicvc->drm_dev;
  185. struct logicvc_crtc *crtc = logicvc->crtc;
  186. unsigned long flags;
  187. if (!crtc)
  188. return;
  189. drm_crtc_handle_vblank(&crtc->drm_crtc);
  190. if (crtc->event) {
  191. spin_lock_irqsave(&drm_dev->event_lock, flags);
  192. drm_crtc_send_vblank_event(&crtc->drm_crtc, crtc->event);
  193. drm_crtc_vblank_put(&crtc->drm_crtc);
  194. crtc->event = NULL;
  195. spin_unlock_irqrestore(&drm_dev->event_lock, flags);
  196. }
  197. }
  198. int logicvc_crtc_init(struct logicvc_drm *logicvc)
  199. {
  200. struct drm_device *drm_dev = &logicvc->drm_dev;
  201. struct device *dev = drm_dev->dev;
  202. struct device_node *of_node = dev->of_node;
  203. struct logicvc_crtc *crtc;
  204. struct logicvc_layer *layer_primary;
  205. int ret;
  206. crtc = devm_kzalloc(dev, sizeof(*crtc), GFP_KERNEL);
  207. if (!crtc)
  208. return -ENOMEM;
  209. layer_primary = logicvc_layer_get_primary(logicvc);
  210. if (!layer_primary) {
  211. drm_err(drm_dev, "Failed to get primary layer\n");
  212. return -EINVAL;
  213. }
  214. ret = drm_crtc_init_with_planes(drm_dev, &crtc->drm_crtc,
  215. &layer_primary->drm_plane, NULL,
  216. &logicvc_crtc_funcs, NULL);
  217. if (ret) {
  218. drm_err(drm_dev, "Failed to initialize CRTC\n");
  219. return ret;
  220. }
  221. drm_crtc_helper_add(&crtc->drm_crtc, &logicvc_crtc_helper_funcs);
  222. crtc->drm_crtc.port = of_graph_get_port_by_id(of_node, 1);
  223. logicvc->crtc = crtc;
  224. return 0;
  225. }