malidp_mw.c 7.4 KB

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