msm_fb.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * Copyright (C) 2013 Red Hat
  3. * Author: Rob Clark <robdclark@gmail.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License version 2 as published by
  7. * the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12. * more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along with
  15. * this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <drm/drm_crtc.h>
  18. #include <drm/drm_crtc_helper.h>
  19. #include "msm_drv.h"
  20. #include "msm_kms.h"
  21. #include "msm_gem.h"
  22. struct msm_framebuffer {
  23. struct drm_framebuffer base;
  24. const struct msm_format *format;
  25. struct drm_gem_object *planes[MAX_PLANE];
  26. };
  27. #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
  28. static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
  29. const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos);
  30. static int msm_framebuffer_create_handle(struct drm_framebuffer *fb,
  31. struct drm_file *file_priv,
  32. unsigned int *handle)
  33. {
  34. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  35. return drm_gem_handle_create(file_priv,
  36. msm_fb->planes[0], handle);
  37. }
  38. static void msm_framebuffer_destroy(struct drm_framebuffer *fb)
  39. {
  40. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  41. int i, n = fb->format->num_planes;
  42. DBG("destroy: FB ID: %d (%p)", fb->base.id, fb);
  43. drm_framebuffer_cleanup(fb);
  44. for (i = 0; i < n; i++) {
  45. struct drm_gem_object *bo = msm_fb->planes[i];
  46. drm_gem_object_put_unlocked(bo);
  47. }
  48. kfree(msm_fb);
  49. }
  50. static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
  51. .create_handle = msm_framebuffer_create_handle,
  52. .destroy = msm_framebuffer_destroy,
  53. };
  54. #ifdef CONFIG_DEBUG_FS
  55. void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
  56. {
  57. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  58. int i, n = fb->format->num_planes;
  59. seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n",
  60. fb->width, fb->height, (char *)&fb->format->format,
  61. drm_framebuffer_read_refcount(fb), fb->base.id);
  62. for (i = 0; i < n; i++) {
  63. seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
  64. i, fb->offsets[i], fb->pitches[i]);
  65. msm_gem_describe(msm_fb->planes[i], m);
  66. }
  67. }
  68. #endif
  69. /* prepare/pin all the fb's bo's for scanout. Note that it is not valid
  70. * to prepare an fb more multiple different initiator 'id's. But that
  71. * should be fine, since only the scanout (mdpN) side of things needs
  72. * this, the gpu doesn't care about fb's.
  73. */
  74. int msm_framebuffer_prepare(struct drm_framebuffer *fb,
  75. struct msm_gem_address_space *aspace)
  76. {
  77. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  78. int ret, i, n = fb->format->num_planes;
  79. uint64_t iova;
  80. for (i = 0; i < n; i++) {
  81. ret = msm_gem_get_iova(msm_fb->planes[i], aspace, &iova);
  82. DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret);
  83. if (ret)
  84. return ret;
  85. }
  86. return 0;
  87. }
  88. void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
  89. struct msm_gem_address_space *aspace)
  90. {
  91. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  92. int i, n = fb->format->num_planes;
  93. for (i = 0; i < n; i++)
  94. msm_gem_put_iova(msm_fb->planes[i], aspace);
  95. }
  96. uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
  97. struct msm_gem_address_space *aspace, int plane)
  98. {
  99. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  100. if (!msm_fb->planes[plane])
  101. return 0;
  102. return msm_gem_iova(msm_fb->planes[plane], aspace) + fb->offsets[plane];
  103. }
  104. struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
  105. {
  106. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  107. return msm_fb->planes[plane];
  108. }
  109. const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
  110. {
  111. struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
  112. return msm_fb->format;
  113. }
  114. struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
  115. struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
  116. {
  117. struct drm_gem_object *bos[4] = {0};
  118. struct drm_framebuffer *fb;
  119. int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format);
  120. for (i = 0; i < n; i++) {
  121. bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
  122. if (!bos[i]) {
  123. ret = -ENXIO;
  124. goto out_unref;
  125. }
  126. }
  127. fb = msm_framebuffer_init(dev, mode_cmd, bos);
  128. if (IS_ERR(fb)) {
  129. ret = PTR_ERR(fb);
  130. goto out_unref;
  131. }
  132. return fb;
  133. out_unref:
  134. for (i = 0; i < n; i++)
  135. drm_gem_object_put_unlocked(bos[i]);
  136. return ERR_PTR(ret);
  137. }
  138. static struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
  139. const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
  140. {
  141. struct msm_drm_private *priv = dev->dev_private;
  142. struct msm_kms *kms = priv->kms;
  143. struct msm_framebuffer *msm_fb = NULL;
  144. struct drm_framebuffer *fb;
  145. const struct msm_format *format;
  146. int ret, i, n;
  147. unsigned int hsub, vsub;
  148. DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
  149. dev, mode_cmd, mode_cmd->width, mode_cmd->height,
  150. (char *)&mode_cmd->pixel_format);
  151. n = drm_format_num_planes(mode_cmd->pixel_format);
  152. hsub = drm_format_horz_chroma_subsampling(mode_cmd->pixel_format);
  153. vsub = drm_format_vert_chroma_subsampling(mode_cmd->pixel_format);
  154. format = kms->funcs->get_format(kms, mode_cmd->pixel_format);
  155. if (!format) {
  156. dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
  157. (char *)&mode_cmd->pixel_format);
  158. ret = -EINVAL;
  159. goto fail;
  160. }
  161. msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL);
  162. if (!msm_fb) {
  163. ret = -ENOMEM;
  164. goto fail;
  165. }
  166. fb = &msm_fb->base;
  167. msm_fb->format = format;
  168. if (n > ARRAY_SIZE(msm_fb->planes)) {
  169. ret = -EINVAL;
  170. goto fail;
  171. }
  172. for (i = 0; i < n; i++) {
  173. unsigned int width = mode_cmd->width / (i ? hsub : 1);
  174. unsigned int height = mode_cmd->height / (i ? vsub : 1);
  175. unsigned int min_size;
  176. min_size = (height - 1) * mode_cmd->pitches[i]
  177. + width * drm_format_plane_cpp(mode_cmd->pixel_format, i)
  178. + mode_cmd->offsets[i];
  179. if (bos[i]->size < min_size) {
  180. ret = -EINVAL;
  181. goto fail;
  182. }
  183. msm_fb->planes[i] = bos[i];
  184. }
  185. drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
  186. ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs);
  187. if (ret) {
  188. dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
  189. goto fail;
  190. }
  191. DBG("create: FB ID: %d (%p)", fb->base.id, fb);
  192. return fb;
  193. fail:
  194. kfree(msm_fb);
  195. return ERR_PTR(ret);
  196. }
  197. struct drm_framebuffer *
  198. msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format)
  199. {
  200. struct drm_mode_fb_cmd2 mode_cmd = {
  201. .pixel_format = format,
  202. .width = w,
  203. .height = h,
  204. .pitches = { p },
  205. };
  206. struct drm_gem_object *bo;
  207. struct drm_framebuffer *fb;
  208. int size;
  209. /* allocate backing bo */
  210. size = mode_cmd.pitches[0] * mode_cmd.height;
  211. DBG("allocating %d bytes for fb %d", size, dev->primary->index);
  212. bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN);
  213. if (IS_ERR(bo)) {
  214. dev_warn(dev->dev, "could not allocate stolen bo\n");
  215. /* try regular bo: */
  216. bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
  217. }
  218. if (IS_ERR(bo)) {
  219. dev_err(dev->dev, "failed to allocate buffer object\n");
  220. return ERR_CAST(bo);
  221. }
  222. fb = msm_framebuffer_init(dev, &mode_cmd, &bo);
  223. if (IS_ERR(fb)) {
  224. dev_err(dev->dev, "failed to allocate fb\n");
  225. /* note: if fb creation failed, we can't rely on fb destroy
  226. * to unref the bo:
  227. */
  228. drm_gem_object_put_unlocked(bo);
  229. return ERR_CAST(fb);
  230. }
  231. return fb;
  232. }