rcar_du_writeback.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * R-Car Display Unit Writeback Support
  4. *
  5. * Copyright (C) 2019 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
  6. */
  7. #include <drm/drm_atomic_helper.h>
  8. #include <drm/drm_device.h>
  9. #include <drm/drm_edid.h>
  10. #include <drm/drm_fourcc.h>
  11. #include <drm/drm_framebuffer.h>
  12. #include <drm/drm_probe_helper.h>
  13. #include <drm/drm_writeback.h>
  14. #include "rcar_du_crtc.h"
  15. #include "rcar_du_drv.h"
  16. #include "rcar_du_kms.h"
  17. #include "rcar_du_writeback.h"
  18. /**
  19. * struct rcar_du_wb_conn_state - Driver-specific writeback connector state
  20. * @state: base DRM connector state
  21. * @format: format of the writeback framebuffer
  22. */
  23. struct rcar_du_wb_conn_state {
  24. struct drm_connector_state state;
  25. const struct rcar_du_format_info *format;
  26. };
  27. #define to_rcar_wb_conn_state(s) \
  28. container_of(s, struct rcar_du_wb_conn_state, state)
  29. /**
  30. * struct rcar_du_wb_job - Driver-private data for writeback jobs
  31. * @sg_tables: scatter-gather tables for the framebuffer memory
  32. */
  33. struct rcar_du_wb_job {
  34. struct sg_table sg_tables[3];
  35. };
  36. static int rcar_du_wb_conn_get_modes(struct drm_connector *connector)
  37. {
  38. struct drm_device *dev = connector->dev;
  39. return drm_add_modes_noedid(connector, dev->mode_config.max_width,
  40. dev->mode_config.max_height);
  41. }
  42. static int rcar_du_wb_prepare_job(struct drm_writeback_connector *connector,
  43. struct drm_writeback_job *job)
  44. {
  45. struct rcar_du_crtc *rcrtc = wb_to_rcar_crtc(connector);
  46. struct rcar_du_wb_job *rjob;
  47. int ret;
  48. if (!job->fb)
  49. return 0;
  50. rjob = kzalloc(sizeof(*rjob), GFP_KERNEL);
  51. if (!rjob)
  52. return -ENOMEM;
  53. /* Map the framebuffer to the VSP. */
  54. ret = rcar_du_vsp_map_fb(rcrtc->vsp, job->fb, rjob->sg_tables);
  55. if (ret < 0) {
  56. kfree(rjob);
  57. return ret;
  58. }
  59. job->priv = rjob;
  60. return 0;
  61. }
  62. static void rcar_du_wb_cleanup_job(struct drm_writeback_connector *connector,
  63. struct drm_writeback_job *job)
  64. {
  65. struct rcar_du_crtc *rcrtc = wb_to_rcar_crtc(connector);
  66. struct rcar_du_wb_job *rjob = job->priv;
  67. if (!job->fb)
  68. return;
  69. rcar_du_vsp_unmap_fb(rcrtc->vsp, job->fb, rjob->sg_tables);
  70. kfree(rjob);
  71. }
  72. static const struct drm_connector_helper_funcs rcar_du_wb_conn_helper_funcs = {
  73. .get_modes = rcar_du_wb_conn_get_modes,
  74. .prepare_writeback_job = rcar_du_wb_prepare_job,
  75. .cleanup_writeback_job = rcar_du_wb_cleanup_job,
  76. };
  77. static struct drm_connector_state *
  78. rcar_du_wb_conn_duplicate_state(struct drm_connector *connector)
  79. {
  80. struct rcar_du_wb_conn_state *copy;
  81. if (WARN_ON(!connector->state))
  82. return NULL;
  83. copy = kzalloc(sizeof(*copy), GFP_KERNEL);
  84. if (!copy)
  85. return NULL;
  86. __drm_atomic_helper_connector_duplicate_state(connector, &copy->state);
  87. return &copy->state;
  88. }
  89. static void rcar_du_wb_conn_destroy_state(struct drm_connector *connector,
  90. struct drm_connector_state *state)
  91. {
  92. __drm_atomic_helper_connector_destroy_state(state);
  93. kfree(to_rcar_wb_conn_state(state));
  94. }
  95. static void rcar_du_wb_conn_reset(struct drm_connector *connector)
  96. {
  97. struct rcar_du_wb_conn_state *state;
  98. if (connector->state) {
  99. rcar_du_wb_conn_destroy_state(connector, connector->state);
  100. connector->state = NULL;
  101. }
  102. state = kzalloc(sizeof(*state), GFP_KERNEL);
  103. if (state == NULL)
  104. return;
  105. __drm_atomic_helper_connector_reset(connector, &state->state);
  106. }
  107. static const struct drm_connector_funcs rcar_du_wb_conn_funcs = {
  108. .reset = rcar_du_wb_conn_reset,
  109. .fill_modes = drm_helper_probe_single_connector_modes,
  110. .destroy = drm_connector_cleanup,
  111. .atomic_duplicate_state = rcar_du_wb_conn_duplicate_state,
  112. .atomic_destroy_state = rcar_du_wb_conn_destroy_state,
  113. };
  114. static int rcar_du_wb_enc_atomic_check(struct drm_encoder *encoder,
  115. struct drm_crtc_state *crtc_state,
  116. struct drm_connector_state *conn_state)
  117. {
  118. struct rcar_du_wb_conn_state *wb_state =
  119. to_rcar_wb_conn_state(conn_state);
  120. const struct drm_display_mode *mode = &crtc_state->mode;
  121. struct drm_device *dev = encoder->dev;
  122. struct drm_framebuffer *fb;
  123. if (!conn_state->writeback_job)
  124. return 0;
  125. fb = conn_state->writeback_job->fb;
  126. /*
  127. * Verify that the framebuffer format is supported and that its size
  128. * matches the current mode.
  129. */
  130. if (fb->width != mode->hdisplay || fb->height != mode->vdisplay) {
  131. dev_dbg(dev->dev, "%s: invalid framebuffer size %ux%u\n",
  132. __func__, fb->width, fb->height);
  133. return -EINVAL;
  134. }
  135. wb_state->format = rcar_du_format_info(fb->format->format);
  136. if (wb_state->format == NULL) {
  137. dev_dbg(dev->dev, "%s: unsupported format %p4cc\n", __func__,
  138. &fb->format->format);
  139. return -EINVAL;
  140. }
  141. return 0;
  142. }
  143. static const struct drm_encoder_helper_funcs rcar_du_wb_enc_helper_funcs = {
  144. .atomic_check = rcar_du_wb_enc_atomic_check,
  145. };
  146. /*
  147. * Only RGB formats are currently supported as the VSP outputs RGB to the DU
  148. * and can't convert to YUV separately for writeback.
  149. */
  150. static const u32 writeback_formats[] = {
  151. DRM_FORMAT_RGB332,
  152. DRM_FORMAT_ARGB4444,
  153. DRM_FORMAT_XRGB4444,
  154. DRM_FORMAT_ARGB1555,
  155. DRM_FORMAT_XRGB1555,
  156. DRM_FORMAT_RGB565,
  157. DRM_FORMAT_BGR888,
  158. DRM_FORMAT_RGB888,
  159. DRM_FORMAT_BGRA8888,
  160. DRM_FORMAT_BGRX8888,
  161. DRM_FORMAT_ARGB8888,
  162. DRM_FORMAT_XRGB8888,
  163. };
  164. int rcar_du_writeback_init(struct rcar_du_device *rcdu,
  165. struct rcar_du_crtc *rcrtc)
  166. {
  167. struct drm_writeback_connector *wb_conn = &rcrtc->writeback;
  168. drm_connector_helper_add(&wb_conn->base,
  169. &rcar_du_wb_conn_helper_funcs);
  170. return drm_writeback_connector_init(&rcdu->ddev, wb_conn,
  171. &rcar_du_wb_conn_funcs,
  172. &rcar_du_wb_enc_helper_funcs,
  173. writeback_formats,
  174. ARRAY_SIZE(writeback_formats),
  175. 1 << drm_crtc_index(&rcrtc->crtc));
  176. }
  177. void rcar_du_writeback_setup(struct rcar_du_crtc *rcrtc,
  178. struct vsp1_du_writeback_config *cfg)
  179. {
  180. struct rcar_du_wb_conn_state *wb_state;
  181. struct drm_connector_state *state;
  182. struct rcar_du_wb_job *rjob;
  183. struct drm_framebuffer *fb;
  184. unsigned int i;
  185. state = rcrtc->writeback.base.state;
  186. if (!state || !state->writeback_job)
  187. return;
  188. fb = state->writeback_job->fb;
  189. rjob = state->writeback_job->priv;
  190. wb_state = to_rcar_wb_conn_state(state);
  191. cfg->pixelformat = wb_state->format->v4l2;
  192. cfg->pitch = fb->pitches[0];
  193. for (i = 0; i < wb_state->format->planes; ++i)
  194. cfg->mem[i] = sg_dma_address(rjob->sg_tables[i].sgl)
  195. + fb->offsets[i];
  196. drm_writeback_queue_job(&rcrtc->writeback, state);
  197. }
  198. void rcar_du_writeback_complete(struct rcar_du_crtc *rcrtc)
  199. {
  200. drm_writeback_signal_completion(&rcrtc->writeback, 0);
  201. }