malidp_mw.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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_crtc_helper.h>
  12. #include <drm/drm_fb_cma_helper.h>
  13. #include <drm/drm_gem_cma_helper.h>
  14. #include <drm/drmP.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. 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 || !conn_state->writeback_job->fb)
  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. mw_state->format =
  118. malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
  119. fb->format->format);
  120. if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
  121. struct drm_format_name_buf format_name;
  122. DRM_DEBUG_KMS("Invalid pixel format %s\n",
  123. drm_get_format_name(fb->format->format,
  124. &format_name));
  125. return -EINVAL;
  126. }
  127. n_planes = drm_format_num_planes(fb->format->format);
  128. for (i = 0; i < n_planes; i++) {
  129. struct drm_gem_cma_object *obj = drm_fb_cma_get_gem_obj(fb, i);
  130. /* memory write buffers are never rotated */
  131. u8 alignment = malidp_hw_get_pitch_align(malidp->dev, 0);
  132. if (fb->pitches[i] & (alignment - 1)) {
  133. DRM_DEBUG_KMS("Invalid pitch %u for plane %d\n",
  134. fb->pitches[i], i);
  135. return -EINVAL;
  136. }
  137. mw_state->pitches[i] = fb->pitches[i];
  138. mw_state->addrs[i] = obj->paddr + fb->offsets[i];
  139. }
  140. mw_state->n_planes = n_planes;
  141. if (fb->format->is_yuv)
  142. mw_state->rgb2yuv_coeffs = rgb2yuv_coeffs_bt709_limited;
  143. return 0;
  144. }
  145. static const struct drm_encoder_helper_funcs malidp_mw_encoder_helper_funcs = {
  146. .atomic_check = malidp_mw_encoder_atomic_check,
  147. };
  148. static u32 *get_writeback_formats(struct malidp_drm *malidp, int *n_formats)
  149. {
  150. const struct malidp_hw_regmap *map = &malidp->dev->hw->map;
  151. u32 *formats;
  152. int n, i;
  153. formats = kcalloc(map->n_pixel_formats, sizeof(*formats),
  154. GFP_KERNEL);
  155. if (!formats)
  156. return NULL;
  157. for (n = 0, i = 0; i < map->n_pixel_formats; i++) {
  158. if (map->pixel_formats[i].layer & SE_MEMWRITE)
  159. formats[n++] = map->pixel_formats[i].format;
  160. }
  161. *n_formats = n;
  162. return formats;
  163. }
  164. int malidp_mw_connector_init(struct drm_device *drm)
  165. {
  166. struct malidp_drm *malidp = drm->dev_private;
  167. u32 *formats;
  168. int ret, n_formats;
  169. if (!malidp->dev->hw->enable_memwrite)
  170. return 0;
  171. malidp->mw_connector.encoder.possible_crtcs = 1 << drm_crtc_index(&malidp->crtc);
  172. drm_connector_helper_add(&malidp->mw_connector.base,
  173. &malidp_mw_connector_helper_funcs);
  174. formats = get_writeback_formats(malidp, &n_formats);
  175. if (!formats)
  176. return -ENOMEM;
  177. ret = drm_writeback_connector_init(drm, &malidp->mw_connector,
  178. &malidp_mw_connector_funcs,
  179. &malidp_mw_encoder_helper_funcs,
  180. formats, n_formats);
  181. kfree(formats);
  182. if (ret)
  183. return ret;
  184. return 0;
  185. }
  186. void malidp_mw_atomic_commit(struct drm_device *drm,
  187. struct drm_atomic_state *old_state)
  188. {
  189. struct malidp_drm *malidp = drm->dev_private;
  190. struct drm_writeback_connector *mw_conn = &malidp->mw_connector;
  191. struct drm_connector_state *conn_state = mw_conn->base.state;
  192. struct malidp_hw_device *hwdev = malidp->dev;
  193. struct malidp_mw_connector_state *mw_state;
  194. if (!conn_state)
  195. return;
  196. mw_state = to_mw_state(conn_state);
  197. if (conn_state->writeback_job && conn_state->writeback_job->fb) {
  198. struct drm_framebuffer *fb = conn_state->writeback_job->fb;
  199. DRM_DEV_DEBUG_DRIVER(drm->dev,
  200. "Enable memwrite %ux%u:%d %pad fmt: %u\n",
  201. fb->width, fb->height,
  202. mw_state->pitches[0],
  203. &mw_state->addrs[0],
  204. mw_state->format);
  205. drm_writeback_queue_job(mw_conn, conn_state->writeback_job);
  206. conn_state->writeback_job = NULL;
  207. hwdev->hw->enable_memwrite(hwdev, mw_state->addrs,
  208. mw_state->pitches, mw_state->n_planes,
  209. fb->width, fb->height, mw_state->format,
  210. !mw_state->rgb2yuv_initialized ?
  211. mw_state->rgb2yuv_coeffs : NULL);
  212. mw_state->rgb2yuv_initialized = !!mw_state->rgb2yuv_coeffs;
  213. } else {
  214. DRM_DEV_DEBUG_DRIVER(drm->dev, "Disable memwrite\n");
  215. hwdev->hw->disable_memwrite(hwdev);
  216. }
  217. }