msm_fb.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /*
  2. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
  3. * Copyright (C) 2013 Red Hat
  4. * Author: Rob Clark <[email protected]>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License version 2 as published by
  8. * the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it will be useful, but WITHOUT
  11. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. * more details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with
  16. * this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <drm/drm_crtc.h>
  19. #include <drm/drm_damage_helper.h>
  20. #include <drm/drm_gem_framebuffer_helper.h>
  21. #include <drm/drm_probe_helper.h>
  22. #include "msm_drv.h"
  23. #include "msm_kms.h"
  24. #include "msm_gem.h"
  25. struct msm_framebuffer {
  26. struct drm_framebuffer base;
  27. const struct msm_format *format;
  28. };
  29. #define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
  30. static const struct drm_framebuffer_funcs msm_framebuffer_funcs = {
  31. .create_handle = drm_gem_fb_create_handle,
  32. .destroy = drm_gem_fb_destroy,
  33. .dirty = drm_atomic_helper_dirtyfb,
  34. };
  35. #ifdef CONFIG_DEBUG_FS
  36. void msm_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
  37. {
  38. struct msm_framebuffer *msm_fb;
  39. int i, n;
  40. if (!fb) {
  41. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  42. return;
  43. }
  44. msm_fb = to_msm_framebuffer(fb);
  45. n = fb->format->num_planes;
  46. seq_printf(m, "fb: %dx%d@%4.4s (%2d, ID:%d)\n",
  47. fb->width, fb->height, (char *)&fb->format->format,
  48. drm_framebuffer_read_refcount(fb), fb->base.id);
  49. for (i = 0; i < n; i++) {
  50. seq_printf(m, " %d: offset=%d pitch=%d, obj: ",
  51. i, fb->offsets[i], fb->pitches[i]);
  52. msm_gem_describe(fb->obj[i], m);
  53. }
  54. }
  55. #endif
  56. void msm_framebuffer_set_keepattrs(struct drm_framebuffer *fb, bool enable)
  57. {
  58. struct msm_framebuffer *msm_fb;
  59. int i, n;
  60. struct drm_gem_object *bo;
  61. struct msm_gem_object *msm_obj;
  62. if (!fb) {
  63. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  64. return;
  65. }
  66. if (!fb->format) {
  67. DRM_ERROR("from:%pS null fb->format\n",
  68. __builtin_return_address(0));
  69. return;
  70. }
  71. msm_fb = to_msm_framebuffer(fb);
  72. n = fb->format->num_planes;
  73. for (i = 0; i < n; i++) {
  74. bo = msm_framebuffer_bo(fb, i);
  75. if (bo) {
  76. msm_obj = to_msm_bo(bo);
  77. if (enable)
  78. msm_obj->flags |= MSM_BO_KEEPATTRS;
  79. else
  80. msm_obj->flags &= ~MSM_BO_KEEPATTRS;
  81. }
  82. }
  83. }
  84. /* prepare/pin all the fb's bo's for scanout. Note that it is not valid
  85. * to prepare an fb more multiple different initiator 'id's. But that
  86. * should be fine, since only the scanout (mdpN) side of things needs
  87. * this, the gpu doesn't care about fb's.
  88. */
  89. int msm_framebuffer_prepare(struct drm_framebuffer *fb,
  90. struct msm_gem_address_space *aspace)
  91. {
  92. struct msm_framebuffer *msm_fb;
  93. int ret, i, n;
  94. uint64_t iova;
  95. if (!fb) {
  96. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  97. return -EINVAL;
  98. }
  99. msm_fb = to_msm_framebuffer(fb);
  100. n = fb->format->num_planes;
  101. for (i = 0; i < n; i++) {
  102. ret = msm_gem_get_iova(fb->obj[i], aspace, &iova);
  103. DBG("FB[%u]: iova[%d]: %08llx (%d)", fb->base.id, i, iova, ret);
  104. if (ret)
  105. return ret;
  106. }
  107. return 0;
  108. }
  109. void msm_framebuffer_cleanup(struct drm_framebuffer *fb,
  110. struct msm_gem_address_space *aspace)
  111. {
  112. struct msm_framebuffer *msm_fb;
  113. int i, n;
  114. if (fb == NULL) {
  115. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  116. return;
  117. }
  118. msm_fb = to_msm_framebuffer(fb);
  119. n = fb->format->num_planes;
  120. for (i = 0; i < n; i++)
  121. msm_gem_put_iova(fb->obj[i], aspace);
  122. }
  123. uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb,
  124. struct msm_gem_address_space *aspace, int plane)
  125. {
  126. if (!fb) {
  127. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  128. return -EINVAL;
  129. }
  130. if (!fb->obj[plane])
  131. return 0;
  132. return msm_gem_iova(fb->obj[plane], aspace) + fb->offsets[plane];
  133. }
  134. uint32_t msm_framebuffer_phys(struct drm_framebuffer *fb,
  135. int plane)
  136. {
  137. struct msm_framebuffer *msm_fb;
  138. dma_addr_t phys_addr;
  139. if (!fb) {
  140. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  141. return -EINVAL;
  142. }
  143. msm_fb = to_msm_framebuffer(fb);
  144. if (!msm_fb->base.obj[plane])
  145. return 0;
  146. phys_addr = msm_gem_get_dma_addr(msm_fb->base.obj[plane]);
  147. if (!phys_addr)
  148. return 0;
  149. return phys_addr + fb->offsets[plane];
  150. }
  151. struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
  152. {
  153. if (!fb) {
  154. DRM_ERROR("from:%pS null fb\n", __builtin_return_address(0));
  155. return ERR_PTR(-EINVAL);
  156. }
  157. return drm_gem_fb_get_obj(fb, plane);
  158. }
  159. const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb)
  160. {
  161. return fb ? (to_msm_framebuffer(fb))->format : NULL;
  162. }
  163. struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
  164. struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
  165. {
  166. const struct drm_format_info *info = drm_get_format_info(dev,
  167. mode_cmd);
  168. struct drm_gem_object *bos[4] = {0};
  169. struct drm_framebuffer *fb;
  170. int ret, i, n = info->num_planes;
  171. for (i = 0; i < n; i++) {
  172. bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
  173. if (!bos[i]) {
  174. ret = -ENXIO;
  175. goto out_unref;
  176. }
  177. }
  178. fb = msm_framebuffer_init(dev, mode_cmd, bos);
  179. if (IS_ERR(fb)) {
  180. ret = PTR_ERR(fb);
  181. goto out_unref;
  182. }
  183. return fb;
  184. out_unref:
  185. for (i = 0; i < n; i++)
  186. drm_gem_object_put_unlocked(bos[i]);
  187. return ERR_PTR(ret);
  188. }
  189. struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev,
  190. const struct drm_mode_fb_cmd2 *mode_cmd,
  191. struct drm_gem_object **bos)
  192. {
  193. const struct drm_format_info *info = drm_get_format_info(dev,
  194. mode_cmd);
  195. struct msm_drm_private *priv = dev->dev_private;
  196. struct msm_kms *kms = priv->kms;
  197. struct msm_framebuffer *msm_fb = NULL;
  198. struct drm_framebuffer *fb;
  199. const struct msm_format *format;
  200. int ret, i, num_planes;
  201. bool is_modified = false;
  202. DBG("create framebuffer: dev=%pK, mode_cmd=%pK (%dx%d@%4.4s)",
  203. dev, mode_cmd, mode_cmd->width, mode_cmd->height,
  204. (char *)&mode_cmd->pixel_format);
  205. num_planes = info->num_planes;
  206. format = kms->funcs->get_format(kms, mode_cmd->pixel_format,
  207. mode_cmd->modifier[0]);
  208. if (!format) {
  209. dev_err(dev->dev, "unsupported pixel format: %4.4s\n",
  210. (char *)&mode_cmd->pixel_format);
  211. ret = -EINVAL;
  212. goto fail;
  213. }
  214. msm_fb = kzalloc(sizeof(*msm_fb), GFP_KERNEL);
  215. if (!msm_fb) {
  216. ret = -ENOMEM;
  217. goto fail;
  218. }
  219. fb = &msm_fb->base;
  220. msm_fb->format = format;
  221. if (mode_cmd->flags & DRM_MODE_FB_MODIFIERS) {
  222. for (i = 0; i < ARRAY_SIZE(mode_cmd->modifier); i++) {
  223. if (mode_cmd->modifier[i]) {
  224. is_modified = true;
  225. break;
  226. }
  227. }
  228. }
  229. if (num_planes > ARRAY_SIZE(fb->obj)) {
  230. ret = -EINVAL;
  231. goto fail;
  232. }
  233. if (is_modified) {
  234. if (!kms->funcs->check_modified_format) {
  235. dev_err(dev->dev, "can't check modified fb format\n");
  236. ret = -EINVAL;
  237. goto fail;
  238. } else {
  239. ret = kms->funcs->check_modified_format(
  240. kms, msm_fb->format, mode_cmd, bos);
  241. if (ret)
  242. goto fail;
  243. }
  244. } else {
  245. const struct drm_format_info *info;
  246. info = drm_format_info(mode_cmd->pixel_format);
  247. if (!info || num_planes > ARRAY_SIZE(info->cpp)) {
  248. ret = -EINVAL;
  249. goto fail;
  250. }
  251. for (i = 0; i < num_planes; i++) {
  252. unsigned int width = mode_cmd->width / (i ?
  253. info->hsub : 1);
  254. unsigned int height = mode_cmd->height / (i ?
  255. info->vsub : 1);
  256. unsigned int min_size;
  257. min_size = (height - 1) * mode_cmd->pitches[i]
  258. + width * info->cpp[i]
  259. + mode_cmd->offsets[i];
  260. if (!bos[i] || bos[i]->size < min_size) {
  261. ret = -EINVAL;
  262. goto fail;
  263. }
  264. }
  265. }
  266. for (i = 0; i < num_planes; i++)
  267. msm_fb->base.obj[i] = bos[i];
  268. drm_helper_mode_fill_fb_struct(dev, fb, mode_cmd);
  269. ret = drm_framebuffer_init(dev, fb, &msm_framebuffer_funcs);
  270. if (ret) {
  271. dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
  272. goto fail;
  273. }
  274. DBG("create: FB ID: %d (%pK)", fb->base.id, fb);
  275. return fb;
  276. fail:
  277. kfree(msm_fb);
  278. return ERR_PTR(ret);
  279. }
  280. struct drm_framebuffer *
  281. msm_alloc_stolen_fb(struct drm_device *dev, int w, int h, int p, uint32_t format)
  282. {
  283. struct drm_mode_fb_cmd2 mode_cmd = {
  284. .pixel_format = format,
  285. .width = w,
  286. .height = h,
  287. .pitches = { p },
  288. };
  289. struct drm_gem_object *bo;
  290. struct drm_framebuffer *fb;
  291. int size;
  292. /* allocate backing bo */
  293. size = mode_cmd.pitches[0] * mode_cmd.height;
  294. DBG("allocating %d bytes for fb %d", size, dev->primary->index);
  295. bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC | MSM_BO_STOLEN);
  296. if (IS_ERR(bo)) {
  297. dev_warn(dev->dev, "could not allocate stolen bo\n");
  298. /* try regular bo: */
  299. bo = msm_gem_new(dev, size, MSM_BO_SCANOUT | MSM_BO_WC);
  300. }
  301. if (IS_ERR(bo)) {
  302. dev_err(dev->dev, "failed to allocate buffer object\n");
  303. return ERR_CAST(bo);
  304. }
  305. msm_gem_object_set_name(bo, "stolenfb");
  306. fb = msm_framebuffer_init(dev, &mode_cmd, &bo);
  307. if (IS_ERR(fb)) {
  308. dev_err(dev->dev, "failed to allocate fb\n");
  309. /* note: if fb creation failed, we can't rely on fb destroy
  310. * to unref the bo:
  311. */
  312. drm_gem_object_put_unlocked(bo);
  313. return ERR_CAST(fb);
  314. }
  315. return fb;
  316. }