rockchip_drm_fb.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*
  2. * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
  3. * Author:Mark Yao <mark.yao@rock-chips.com>
  4. *
  5. * This software is licensed under the terms of the GNU General Public
  6. * License version 2, as published by the Free Software Foundation, and
  7. * may be copied, distributed, and modified under those terms.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/kernel.h>
  15. #include <drm/drm.h>
  16. #include <drm/drmP.h>
  17. #include <drm/drm_atomic.h>
  18. #include <drm/drm_fb_helper.h>
  19. #include <drm/drm_crtc_helper.h>
  20. #include <drm/drm_gem_framebuffer_helper.h>
  21. #include "rockchip_drm_drv.h"
  22. #include "rockchip_drm_fb.h"
  23. #include "rockchip_drm_gem.h"
  24. #include "rockchip_drm_psr.h"
  25. static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb,
  26. struct drm_file *file,
  27. unsigned int flags, unsigned int color,
  28. struct drm_clip_rect *clips,
  29. unsigned int num_clips)
  30. {
  31. rockchip_drm_psr_flush_all(fb->dev);
  32. return 0;
  33. }
  34. static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
  35. .destroy = drm_gem_fb_destroy,
  36. .create_handle = drm_gem_fb_create_handle,
  37. .dirty = rockchip_drm_fb_dirty,
  38. };
  39. static struct drm_framebuffer *
  40. rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd,
  41. struct drm_gem_object **obj, unsigned int num_planes)
  42. {
  43. struct drm_framebuffer *fb;
  44. int ret;
  45. int i;
  46. fb = kzalloc(sizeof(*fb), GFP_KERNEL);
  47. if (!fb)
  48. return ERR_PTR(-ENOMEM);
  49. drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
  50. for (i = 0; i < num_planes; i++)
  51. fb->obj[i] = obj[i];
  52. ret = drm_framebuffer_init(dev, fb, &rockchip_drm_fb_funcs);
  53. if (ret) {
  54. DRM_DEV_ERROR(dev->dev,
  55. "Failed to initialize framebuffer: %d\n",
  56. ret);
  57. kfree(fb);
  58. return ERR_PTR(ret);
  59. }
  60. return fb;
  61. }
  62. static struct drm_framebuffer *
  63. rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv,
  64. const struct drm_mode_fb_cmd2 *mode_cmd)
  65. {
  66. struct drm_framebuffer *fb;
  67. struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER];
  68. struct drm_gem_object *obj;
  69. unsigned int hsub;
  70. unsigned int vsub;
  71. int num_planes;
  72. int ret;
  73. int i;
  74. hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
  75. vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
  76. num_planes = min(drm_format_num_planes(mode_cmd->pixel_format),
  77. ROCKCHIP_MAX_FB_BUFFER);
  78. for (i = 0; i < num_planes; i++) {
  79. unsigned int width = mode_cmd->width / (i ? hsub : 1);
  80. unsigned int height = mode_cmd->height / (i ? vsub : 1);
  81. unsigned int min_size;
  82. obj = drm_gem_object_lookup(file_priv, mode_cmd->handles[i]);
  83. if (!obj) {
  84. DRM_DEV_ERROR(dev->dev,
  85. "Failed to lookup GEM object\n");
  86. ret = -ENXIO;
  87. goto err_gem_object_unreference;
  88. }
  89. min_size = (height - 1) * mode_cmd->pitches[i] +
  90. mode_cmd->offsets[i] +
  91. width * drm_format_plane_cpp(mode_cmd->pixel_format, i);
  92. if (obj->size < min_size) {
  93. drm_gem_object_put_unlocked(obj);
  94. ret = -EINVAL;
  95. goto err_gem_object_unreference;
  96. }
  97. objs[i] = obj;
  98. }
  99. fb = rockchip_fb_alloc(dev, mode_cmd, objs, i);
  100. if (IS_ERR(fb)) {
  101. ret = PTR_ERR(fb);
  102. goto err_gem_object_unreference;
  103. }
  104. return fb;
  105. err_gem_object_unreference:
  106. for (i--; i >= 0; i--)
  107. drm_gem_object_put_unlocked(objs[i]);
  108. return ERR_PTR(ret);
  109. }
  110. static void
  111. rockchip_drm_psr_inhibit_get_state(struct drm_atomic_state *state)
  112. {
  113. struct drm_crtc *crtc;
  114. struct drm_crtc_state *crtc_state;
  115. struct drm_encoder *encoder;
  116. u32 encoder_mask = 0;
  117. int i;
  118. for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
  119. encoder_mask |= crtc_state->encoder_mask;
  120. encoder_mask |= crtc->state->encoder_mask;
  121. }
  122. drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
  123. rockchip_drm_psr_inhibit_get(encoder);
  124. }
  125. static void
  126. rockchip_drm_psr_inhibit_put_state(struct drm_atomic_state *state)
  127. {
  128. struct drm_crtc *crtc;
  129. struct drm_crtc_state *crtc_state;
  130. struct drm_encoder *encoder;
  131. u32 encoder_mask = 0;
  132. int i;
  133. for_each_old_crtc_in_state(state, crtc, crtc_state, i) {
  134. encoder_mask |= crtc_state->encoder_mask;
  135. encoder_mask |= crtc->state->encoder_mask;
  136. }
  137. drm_for_each_encoder_mask(encoder, state->dev, encoder_mask)
  138. rockchip_drm_psr_inhibit_put(encoder);
  139. }
  140. static void
  141. rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state)
  142. {
  143. struct drm_device *dev = old_state->dev;
  144. rockchip_drm_psr_inhibit_get_state(old_state);
  145. drm_atomic_helper_commit_modeset_disables(dev, old_state);
  146. drm_atomic_helper_commit_modeset_enables(dev, old_state);
  147. drm_atomic_helper_commit_planes(dev, old_state,
  148. DRM_PLANE_COMMIT_ACTIVE_ONLY);
  149. rockchip_drm_psr_inhibit_put_state(old_state);
  150. drm_atomic_helper_commit_hw_done(old_state);
  151. drm_atomic_helper_wait_for_vblanks(dev, old_state);
  152. drm_atomic_helper_cleanup_planes(dev, old_state);
  153. }
  154. static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
  155. .atomic_commit_tail = rockchip_atomic_helper_commit_tail_rpm,
  156. };
  157. static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
  158. .fb_create = rockchip_user_fb_create,
  159. .output_poll_changed = drm_fb_helper_output_poll_changed,
  160. .atomic_check = drm_atomic_helper_check,
  161. .atomic_commit = drm_atomic_helper_commit,
  162. };
  163. struct drm_framebuffer *
  164. rockchip_drm_framebuffer_init(struct drm_device *dev,
  165. const struct drm_mode_fb_cmd2 *mode_cmd,
  166. struct drm_gem_object *obj)
  167. {
  168. struct drm_framebuffer *fb;
  169. fb = rockchip_fb_alloc(dev, mode_cmd, &obj, 1);
  170. if (IS_ERR(fb))
  171. return ERR_CAST(fb);
  172. return fb;
  173. }
  174. void rockchip_drm_mode_config_init(struct drm_device *dev)
  175. {
  176. dev->mode_config.min_width = 0;
  177. dev->mode_config.min_height = 0;
  178. /*
  179. * set max width and height as default value(4096x4096).
  180. * this value would be used to check framebuffer size limitation
  181. * at drm_mode_addfb().
  182. */
  183. dev->mode_config.max_width = 4096;
  184. dev->mode_config.max_height = 4096;
  185. dev->mode_config.funcs = &rockchip_drm_mode_config_funcs;
  186. dev->mode_config.helper_private = &rockchip_mode_config_helpers;
  187. }