malidp_mw.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
  4. * Author: Brian Starkey <brian.starkey@arm.com>
  5. *
  6. * ARM Mali DP Writeback connector implementation
  7. */
  8. #include <drm/drm_atomic.h>
  9. #include <drm/drm_atomic_helper.h>
  10. #include <drm/drm_crtc.h>
  11. #include <drm/drm_edid.h>
  12. #include <drm/drm_fb_dma_helper.h>
  13. #include <drm/drm_fourcc.h>
  14. #include <drm/drm_framebuffer.h>
  15. #include <drm/drm_gem_dma_helper.h>
  16. #include <drm/drm_print.h>
  17. #include <drm/drm_probe_helper.h>
  18. #include <drm/drm_writeback.h>
  19. #include "malidp_drv.h"
  20. #include "malidp_hw.h"
  21. #include "malidp_mw.h"
  22. #define to_mw_state(_state) (struct malidp_mw_connector_state *)(_state)
  23. struct malidp_mw_connector_state {
  24. struct drm_connector_state base;
  25. dma_addr_t addrs[2];
  26. s32 pitches[2];
  27. u8 format;
  28. u8 n_planes;
  29. bool rgb2yuv_initialized;
  30. const s16 *rgb2yuv_coeffs;
  31. };
  32. static int malidp_mw_connector_get_modes(struct drm_connector *connector)
  33. {
  34. struct drm_device *dev = connector->dev;
  35. return drm_add_modes_noedid(connector, dev->mode_config.max_width,
  36. dev->mode_config.max_height);
  37. }
  38. static enum drm_mode_status
  39. malidp_mw_connector_mode_valid(struct drm_connector *connector,
  40. const struct drm_display_mode *mode)
  41. {
  42. struct drm_device *dev = connector->dev;
  43. struct drm_mode_config *mode_config = &dev->mode_config;
  44. int w = mode->hdisplay, h = mode->vdisplay;
  45. if ((w < mode_config->min_width) || (w > mode_config->max_width))
  46. return MODE_BAD_HVALUE;
  47. if ((h < mode_config->min_height) || (h > mode_config->max_height))
  48. return MODE_BAD_VVALUE;
  49. return MODE_OK;
  50. }
  51. static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = {
  52. .get_modes = malidp_mw_connector_get_modes,
  53. .mode_valid = malidp_mw_connector_mode_valid,
  54. };
  55. static void malidp_mw_connector_reset(struct drm_connector *connector)
  56. {
  57. struct malidp_mw_connector_state *mw_state = kzalloc_obj(*mw_state);
  58. if (connector->state)
  59. __drm_atomic_helper_connector_destroy_state(connector->state);
  60. kfree(connector->state);
  61. connector->state = NULL;
  62. if (mw_state)
  63. __drm_atomic_helper_connector_reset(connector, &mw_state->base);
  64. }
  65. static enum drm_connector_status
  66. malidp_mw_connector_detect(struct drm_connector *connector, bool force)
  67. {
  68. return connector_status_connected;
  69. }
  70. static void malidp_mw_connector_destroy(struct drm_connector *connector)
  71. {
  72. drm_connector_cleanup(connector);
  73. }
  74. static struct drm_connector_state *
  75. malidp_mw_connector_duplicate_state(struct drm_connector *connector)
  76. {
  77. struct malidp_mw_connector_state *mw_state, *mw_current_state;
  78. if (WARN_ON(!connector->state))
  79. return NULL;
  80. mw_state = kzalloc_obj(*mw_state);
  81. if (!mw_state)
  82. return NULL;
  83. mw_current_state = to_mw_state(connector->state);
  84. mw_state->rgb2yuv_coeffs = mw_current_state->rgb2yuv_coeffs;
  85. mw_state->rgb2yuv_initialized = mw_current_state->rgb2yuv_initialized;
  86. __drm_atomic_helper_connector_duplicate_state(connector, &mw_state->base);
  87. return &mw_state->base;
  88. }
  89. static const struct drm_connector_funcs malidp_mw_connector_funcs = {
  90. .reset = malidp_mw_connector_reset,
  91. .detect = malidp_mw_connector_detect,
  92. .fill_modes = drm_helper_probe_single_connector_modes,
  93. .destroy = malidp_mw_connector_destroy,
  94. .atomic_duplicate_state = malidp_mw_connector_duplicate_state,
  95. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  96. };
  97. static const s16 rgb2yuv_coeffs_bt709_limited[MALIDP_COLORADJ_NUM_COEFFS] = {
  98. 47, 157, 16,
  99. -26, -87, 112,
  100. 112, -102, -10,
  101. 16, 128, 128
  102. };
  103. static int
  104. malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
  105. struct drm_crtc_state *crtc_state,
  106. struct drm_connector_state *conn_state)
  107. {
  108. struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state);
  109. struct malidp_drm *malidp = drm_to_malidp(encoder->dev);
  110. struct drm_framebuffer *fb;
  111. int i, n_planes;
  112. if (!conn_state->writeback_job)
  113. return 0;
  114. fb = conn_state->writeback_job->fb;
  115. if ((fb->width != crtc_state->mode.hdisplay) ||
  116. (fb->height != crtc_state->mode.vdisplay)) {
  117. DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n",
  118. fb->width, fb->height);
  119. return -EINVAL;
  120. }
  121. if (fb->modifier) {
  122. DRM_DEBUG_KMS("Writeback framebuffer does not support modifiers\n");
  123. return -EINVAL;
  124. }
  125. mw_state->format =
  126. malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
  127. fb->format->format, !!fb->modifier);
  128. if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
  129. DRM_DEBUG_KMS("Invalid pixel format %p4cc\n",
  130. &fb->format->format);
  131. return -EINVAL;
  132. }
  133. n_planes = fb->format->num_planes;
  134. for (i = 0; i < n_planes; i++) {
  135. struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, i);
  136. /* memory write buffers are never rotated */
  137. u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0);
  138. if (fb->pitches[i] & (alignment - 1)) {
  139. DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
  140. fb->pitches[i], i);
  141. return -EINVAL;
  142. }
  143. mw_state->pitches[i] = fb->pitches[i];
  144. mw_state->addrs[i] = obj->dma_addr + fb->offsets[i];
  145. }
  146. mw_state->n_planes = n_planes;
  147. if (fb->format->is_yuv)
  148. mw_state->rgb2yuv_coeffs = rgb2yuv_coeffs_bt709_limited;
  149. return 0;
  150. }
  151. static const struct drm_encoder_helper_funcs malidp_mw_encoder_helper_funcs = {
  152. .atomic_check = malidp_mw_encoder_atomic_check,
  153. };
  154. static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats)
  155. {
  156. const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
  157. u32 *formats;
  158. int n, i;
  159. formats = kcalloc(map->n_pixel_formats, sizeof(*formats),
  160. GFP_KERNEL);
  161. if (!formats)
  162. return NULL;
  163. for (n = 0, i = 0; i < map->n_pixel_formats; i++) {
  164. if (map->pixel_formats[i].layer & SE_MEMWRITE)
  165. formats[n++] = map->pixel_formats[i].format;
  166. }
  167. *n_formats = n;
  168. return formats;
  169. }
  170. int malidp_mw_connector_init(struct drm_device *drm)
  171. {
  172. struct malidp_drm *malidp = drm_to_malidp(drm);
  173. u32 *formats;
  174. int ret, n_formats;
  175. if (!malidp->dev->hw->enable_memwrite)
  176. return 0;
  177. drm_connector_helper_add(&malidp->mw_connector.base,
  178. &malidp_mw_connector_helper_funcs);
  179. formats = get_writeback_formats(malidp, &n_formats);
  180. if (!formats)
  181. return -ENOMEM;
  182. ret = drm_writeback_connector_init(drm, &malidp->mw_connector,
  183. &malidp_mw_connector_funcs,
  184. &malidp_mw_encoder_helper_funcs,
  185. formats, n_formats,
  186. 1 << drm_crtc_index(&malidp->crtc));
  187. kfree(formats);
  188. if (ret)
  189. return ret;
  190. return 0;
  191. }
  192. void malidp_mw_atomic_commit(struct drm_device *drm,
  193. struct drm_atomic_state *old_state)
  194. {
  195. struct malidp_drm *malidp = drm_to_malidp(drm);
  196. struct drm_writeback_connector *mw_conn = &malidp->mw_connector;
  197. struct drm_connector_state *conn_state = mw_conn->base.state;
  198. struct malidp_hw_device *hwdev = malidp->dev;
  199. struct malidp_mw_connector_state *mw_state;
  200. if (!conn_state)
  201. return;
  202. mw_state = to_mw_state(conn_state);
  203. if (conn_state->writeback_job) {
  204. struct drm_framebuffer *fb = conn_state->writeback_job->fb;
  205. DRM_DEV_DEBUG_DRIVER(drm->dev,
  206. "Enable memwrite %ux%u:%d %pad fmt: %u\n",
  207. fb->width, fb->height,
  208. mw_state->pitches[0],
  209. &mw_state->addrs[0],
  210. mw_state->format);
  211. drm_writeback_queue_job(mw_conn, conn_state);
  212. hwdev->hw->enable_memwrite(hwdev, mw_state->addrs,
  213. mw_state->pitches, mw_state->n_planes,
  214. fb->width, fb->height, mw_state->format,
  215. !mw_state->rgb2yuv_initialized ?
  216. mw_state->rgb2yuv_coeffs : NULL);
  217. mw_state->rgb2yuv_initialized = !!mw_state->rgb2yuv_coeffs;
  218. } else {
  219. DRM_DEV_DEBUG_DRIVER(drm->dev, "Disable memwrite\n");
  220. hwdev->hw->disable_memwrite(hwdev);
  221. }
  222. }