malidp_mw.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
  4. * Author: Brian Starkey <[email protected]>
  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_probe_helper.h>
  17. #include <drm/drm_writeback.h>
  18. #include "malidp_drv.h"
  19. #include "malidp_hw.h"
  20. #include "malidp_mw.h"
  21. #define to_mw_state(_state) (struct malidp_mw_connector_state *)(_state)
  22. struct malidp_mw_connector_state {
  23. struct drm_connector_state base;
  24. dma_addr_t addrs[2];
  25. s32 pitches[2];
  26. u8 format;
  27. u8 n_planes;
  28. bool rgb2yuv_initialized;
  29. const s16 *rgb2yuv_coeffs;
  30. };
  31. static int malidp_mw_connector_get_modes(struct drm_connector *connector)
  32. {
  33. struct drm_device *dev = connector->dev;
  34. return drm_add_modes_noedid(connector, dev->mode_config.max_width,
  35. dev->mode_config.max_height);
  36. }
  37. static enum drm_mode_status
  38. malidp_mw_connector_mode_valid(struct drm_connector *connector,
  39. struct drm_display_mode *mode)
  40. {
  41. struct drm_device *dev = connector->dev;
  42. struct drm_mode_config *mode_config = &dev->mode_config;
  43. int w = mode->hdisplay, h = mode->vdisplay;
  44. if ((w < mode_config->min_width) || (w > mode_config->max_width))
  45. return MODE_BAD_HVALUE;
  46. if ((h < mode_config->min_height) || (h > mode_config->max_height))
  47. return MODE_BAD_VVALUE;
  48. return MODE_OK;
  49. }
  50. static const struct drm_connector_helper_funcs malidp_mw_connector_helper_funcs = {
  51. .get_modes = malidp_mw_connector_get_modes,
  52. .mode_valid = malidp_mw_connector_mode_valid,
  53. };
  54. static void malidp_mw_connector_reset(struct drm_connector *connector)
  55. {
  56. struct malidp_mw_connector_state *mw_state =
  57. kzalloc(sizeof(*mw_state), GFP_KERNEL);
  58. if (connector->state)
  59. __drm_atomic_helper_connector_destroy_state(connector->state);
  60. kfree(connector->state);
  61. __drm_atomic_helper_connector_reset(connector, &mw_state->base);
  62. }
  63. static enum drm_connector_status
  64. malidp_mw_connector_detect(struct drm_connector *connector, bool force)
  65. {
  66. return connector_status_connected;
  67. }
  68. static void malidp_mw_connector_destroy(struct drm_connector *connector)
  69. {
  70. drm_connector_cleanup(connector);
  71. }
  72. static struct drm_connector_state *
  73. malidp_mw_connector_duplicate_state(struct drm_connector *connector)
  74. {
  75. struct malidp_mw_connector_state *mw_state, *mw_current_state;
  76. if (WARN_ON(!connector->state))
  77. return NULL;
  78. mw_state = kzalloc(sizeof(*mw_state), GFP_KERNEL);
  79. if (!mw_state)
  80. return NULL;
  81. mw_current_state = to_mw_state(connector->state);
  82. mw_state->rgb2yuv_coeffs = mw_current_state->rgb2yuv_coeffs;
  83. mw_state->rgb2yuv_initialized = mw_current_state->rgb2yuv_initialized;
  84. __drm_atomic_helper_connector_duplicate_state(connector, &mw_state->base);
  85. return &mw_state->base;
  86. }
  87. static const struct drm_connector_funcs malidp_mw_connector_funcs = {
  88. .reset = malidp_mw_connector_reset,
  89. .detect = malidp_mw_connector_detect,
  90. .fill_modes = drm_helper_probe_single_connector_modes,
  91. .destroy = malidp_mw_connector_destroy,
  92. .atomic_duplicate_state = malidp_mw_connector_duplicate_state,
  93. .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
  94. };
  95. static const s16 rgb2yuv_coeffs_bt709_limited[MALIDP_COLORADJ_NUM_COEFFS] = {
  96. 47, 157, 16,
  97. -26, -87, 112,
  98. 112, -102, -10,
  99. 16, 128, 128
  100. };
  101. static int
  102. malidp_mw_encoder_atomic_check(struct drm_encoder *encoder,
  103. struct drm_crtc_state *crtc_state,
  104. struct drm_connector_state *conn_state)
  105. {
  106. struct malidp_mw_connector_state *mw_state = to_mw_state(conn_state);
  107. struct malidp_drm *malidp = encoder->dev->dev_private;
  108. struct drm_framebuffer *fb;
  109. int i, n_planes;
  110. if (!conn_state->writeback_job)
  111. return 0;
  112. fb = conn_state->writeback_job->fb;
  113. if ((fb->width != crtc_state->mode.hdisplay) ||
  114. (fb->height != crtc_state->mode.vdisplay)) {
  115. DRM_DEBUG_KMS("Invalid framebuffer size %ux%u\n",
  116. fb->width, fb->height);
  117. return -EINVAL;
  118. }
  119. if (fb->modifier) {
  120. DRM_DEBUG_KMS("Writeback framebuffer does not support modifiers\n");
  121. return -EINVAL;
  122. }
  123. mw_state->format =
  124. malidp_hw_get_format_id(&malidp->dev->hw->map, SE_MEMWRITE,
  125. fb->format->format, !!fb->modifier);
  126. if (mw_state->format == MALIDP_INVALID_FORMAT_ID) {
  127. DRM_DEBUG_KMS("Invalid pixel format %p4cc\n",
  128. &fb->format->format);
  129. return -EINVAL;
  130. }
  131. n_planes = fb->format->num_planes;
  132. for (i = 0; i < n_planes; i++) {
  133. struct drm_gem_dma_object *obj = drm_fb_dma_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->dma_addr + 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. drm_connector_helper_add(&malidp->mw_connector.base,
  176. &malidp_mw_connector_helper_funcs);
  177. formats = get_writeback_formats(malidp, &n_formats);
  178. if (!formats)
  179. return -ENOMEM;
  180. ret = drm_writeback_connector_init(drm, &malidp->mw_connector,
  181. &malidp_mw_connector_funcs,
  182. &malidp_mw_encoder_helper_funcs,
  183. formats, n_formats,
  184. 1 << drm_crtc_index(&malidp->crtc));
  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. }