drm_gem_framebuffer_helper.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * drm gem framebuffer helper functions
  4. *
  5. * Copyright (C) 2017 Noralf Trønnes
  6. */
  7. #include <linux/export.h>
  8. #include <linux/slab.h>
  9. #include <linux/module.h>
  10. #include <drm/drm_damage_helper.h>
  11. #include <drm/drm_drv.h>
  12. #include <drm/drm_fourcc.h>
  13. #include <drm/drm_framebuffer.h>
  14. #include <drm/drm_gem.h>
  15. #include <drm/drm_gem_framebuffer_helper.h>
  16. #include <drm/drm_modeset_helper.h>
  17. #include <drm/drm_print.h>
  18. #include "drm_internal.h"
  19. MODULE_IMPORT_NS("DMA_BUF");
  20. #define AFBC_HEADER_SIZE 16
  21. #define AFBC_TH_LAYOUT_ALIGNMENT 8
  22. #define AFBC_HDR_ALIGN 64
  23. #define AFBC_SUPERBLOCK_PIXELS 256
  24. #define AFBC_SUPERBLOCK_ALIGNMENT 128
  25. #define AFBC_TH_BODY_START_ALIGNMENT 4096
  26. /**
  27. * DOC: overview
  28. *
  29. * This library provides helpers for drivers that don't subclass
  30. * &drm_framebuffer and use &drm_gem_object for their backing storage.
  31. *
  32. * Drivers without additional needs to validate framebuffers can simply use
  33. * drm_gem_fb_create() and everything is wired up automatically. Other drivers
  34. * can use all parts independently.
  35. */
  36. /**
  37. * drm_gem_fb_get_obj() - Get GEM object backing the framebuffer
  38. * @fb: Framebuffer
  39. * @plane: Plane index
  40. *
  41. * No additional reference is taken beyond the one that the &drm_frambuffer
  42. * already holds.
  43. *
  44. * Returns:
  45. * Pointer to &drm_gem_object for the given framebuffer and plane index or NULL
  46. * if it does not exist.
  47. */
  48. struct drm_gem_object *drm_gem_fb_get_obj(struct drm_framebuffer *fb,
  49. unsigned int plane)
  50. {
  51. struct drm_device *dev = fb->dev;
  52. if (drm_WARN_ON_ONCE(dev, plane >= ARRAY_SIZE(fb->obj)))
  53. return NULL;
  54. else if (drm_WARN_ON_ONCE(dev, !fb->obj[plane]))
  55. return NULL;
  56. return fb->obj[plane];
  57. }
  58. EXPORT_SYMBOL_GPL(drm_gem_fb_get_obj);
  59. static int
  60. drm_gem_fb_init(struct drm_device *dev,
  61. struct drm_framebuffer *fb,
  62. const struct drm_format_info *info,
  63. const struct drm_mode_fb_cmd2 *mode_cmd,
  64. struct drm_gem_object **obj, unsigned int num_planes,
  65. const struct drm_framebuffer_funcs *funcs)
  66. {
  67. unsigned int i;
  68. int ret;
  69. drm_helper_mode_fill_fb_struct(dev, fb, info, mode_cmd);
  70. for (i = 0; i < num_planes; i++)
  71. fb->obj[i] = obj[i];
  72. ret = drm_framebuffer_init(dev, fb, funcs);
  73. if (ret)
  74. drm_err(dev, "Failed to init framebuffer: %d\n", ret);
  75. return ret;
  76. }
  77. /**
  78. * drm_gem_fb_destroy - Free GEM backed framebuffer
  79. * @fb: Framebuffer
  80. *
  81. * Frees a GEM backed framebuffer with its backing buffer(s) and the structure
  82. * itself. Drivers can use this as their &drm_framebuffer_funcs->destroy
  83. * callback.
  84. */
  85. void drm_gem_fb_destroy(struct drm_framebuffer *fb)
  86. {
  87. unsigned int i;
  88. for (i = 0; i < fb->format->num_planes; i++)
  89. drm_gem_object_put(fb->obj[i]);
  90. drm_framebuffer_cleanup(fb);
  91. kfree(fb);
  92. }
  93. EXPORT_SYMBOL(drm_gem_fb_destroy);
  94. /**
  95. * drm_gem_fb_create_handle - Create handle for GEM backed framebuffer
  96. * @fb: Framebuffer
  97. * @file: DRM file to register the handle for
  98. * @handle: Pointer to return the created handle
  99. *
  100. * This function creates a handle for the GEM object backing the framebuffer.
  101. * Drivers can use this as their &drm_framebuffer_funcs->create_handle
  102. * callback. The GETFB IOCTL calls into this callback.
  103. *
  104. * Returns:
  105. * 0 on success or a negative error code on failure.
  106. */
  107. int drm_gem_fb_create_handle(struct drm_framebuffer *fb, struct drm_file *file,
  108. unsigned int *handle)
  109. {
  110. return drm_gem_handle_create(file, fb->obj[0], handle);
  111. }
  112. EXPORT_SYMBOL(drm_gem_fb_create_handle);
  113. /**
  114. * drm_gem_fb_init_with_funcs() - Helper function for implementing
  115. * &drm_mode_config_funcs.fb_create
  116. * callback in cases when the driver
  117. * allocates a subclass of
  118. * struct drm_framebuffer
  119. * @dev: DRM device
  120. * @fb: framebuffer object
  121. * @file: DRM file that holds the GEM handle(s) backing the framebuffer
  122. * @info: pixel format information
  123. * @mode_cmd: Metadata from the userspace framebuffer creation request
  124. * @funcs: vtable to be used for the new framebuffer object
  125. *
  126. * This function can be used to set &drm_framebuffer_funcs for drivers that need
  127. * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
  128. * change &drm_framebuffer_funcs. The function does buffer size validation.
  129. * The buffer size validation is for a general case, though, so users should
  130. * pay attention to the checks being appropriate for them or, at least,
  131. * non-conflicting.
  132. *
  133. * Returns:
  134. * Zero or a negative error code.
  135. */
  136. int drm_gem_fb_init_with_funcs(struct drm_device *dev,
  137. struct drm_framebuffer *fb,
  138. struct drm_file *file,
  139. const struct drm_format_info *info,
  140. const struct drm_mode_fb_cmd2 *mode_cmd,
  141. const struct drm_framebuffer_funcs *funcs)
  142. {
  143. struct drm_gem_object *objs[DRM_FORMAT_MAX_PLANES];
  144. unsigned int i;
  145. int ret;
  146. if (drm_drv_uses_atomic_modeset(dev) &&
  147. !drm_any_plane_has_format(dev, mode_cmd->pixel_format,
  148. mode_cmd->modifier[0])) {
  149. drm_dbg_kms(dev, "Unsupported pixel format %p4cc / modifier 0x%llx\n",
  150. &mode_cmd->pixel_format, mode_cmd->modifier[0]);
  151. return -EINVAL;
  152. }
  153. for (i = 0; i < info->num_planes; i++) {
  154. unsigned int width = mode_cmd->width / (i ? info->hsub : 1);
  155. unsigned int height = mode_cmd->height / (i ? info->vsub : 1);
  156. unsigned int min_size;
  157. objs[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
  158. if (!objs[i]) {
  159. drm_dbg_kms(dev, "Failed to lookup GEM object\n");
  160. ret = -ENOENT;
  161. goto err_gem_object_put;
  162. }
  163. min_size = (height - 1) * mode_cmd->pitches[i]
  164. + drm_format_info_min_pitch(info, i, width)
  165. + mode_cmd->offsets[i];
  166. if (objs[i]->size < min_size) {
  167. drm_dbg_kms(dev,
  168. "GEM object size (%zu) smaller than minimum size (%u) for plane %d\n",
  169. objs[i]->size, min_size, i);
  170. drm_gem_object_put(objs[i]);
  171. ret = -EINVAL;
  172. goto err_gem_object_put;
  173. }
  174. }
  175. ret = drm_gem_fb_init(dev, fb, info, mode_cmd, objs, i, funcs);
  176. if (ret)
  177. goto err_gem_object_put;
  178. return 0;
  179. err_gem_object_put:
  180. while (i > 0) {
  181. --i;
  182. drm_gem_object_put(objs[i]);
  183. }
  184. return ret;
  185. }
  186. EXPORT_SYMBOL_GPL(drm_gem_fb_init_with_funcs);
  187. /**
  188. * drm_gem_fb_create_with_funcs() - Helper function for the
  189. * &drm_mode_config_funcs.fb_create
  190. * callback
  191. * @dev: DRM device
  192. * @file: DRM file that holds the GEM handle(s) backing the framebuffer
  193. * @info: pixel format information
  194. * @mode_cmd: Metadata from the userspace framebuffer creation request
  195. * @funcs: vtable to be used for the new framebuffer object
  196. *
  197. * This function can be used to set &drm_framebuffer_funcs for drivers that need
  198. * custom framebuffer callbacks. Use drm_gem_fb_create() if you don't need to
  199. * change &drm_framebuffer_funcs. The function does buffer size validation.
  200. *
  201. * Returns:
  202. * Pointer to a &drm_framebuffer on success or an error pointer on failure.
  203. */
  204. struct drm_framebuffer *
  205. drm_gem_fb_create_with_funcs(struct drm_device *dev, struct drm_file *file,
  206. const struct drm_format_info *info,
  207. const struct drm_mode_fb_cmd2 *mode_cmd,
  208. const struct drm_framebuffer_funcs *funcs)
  209. {
  210. struct drm_framebuffer *fb;
  211. int ret;
  212. fb = kzalloc_obj(*fb);
  213. if (!fb)
  214. return ERR_PTR(-ENOMEM);
  215. ret = drm_gem_fb_init_with_funcs(dev, fb, file, info, mode_cmd, funcs);
  216. if (ret) {
  217. kfree(fb);
  218. return ERR_PTR(ret);
  219. }
  220. return fb;
  221. }
  222. EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_funcs);
  223. static const struct drm_framebuffer_funcs drm_gem_fb_funcs = {
  224. .destroy = drm_gem_fb_destroy,
  225. .create_handle = drm_gem_fb_create_handle,
  226. };
  227. /**
  228. * drm_gem_fb_create() - Helper function for the
  229. * &drm_mode_config_funcs.fb_create callback
  230. * @dev: DRM device
  231. * @file: DRM file that holds the GEM handle(s) backing the framebuffer
  232. * @info: pixel format information
  233. * @mode_cmd: Metadata from the userspace framebuffer creation request
  234. *
  235. * This function creates a new framebuffer object described by
  236. * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
  237. * backing the framebuffer.
  238. *
  239. * If your hardware has special alignment or pitch requirements these should be
  240. * checked before calling this function. The function does buffer size
  241. * validation. Use drm_gem_fb_create_with_dirty() if you need framebuffer
  242. * flushing.
  243. *
  244. * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
  245. * The ADDFB2 IOCTL calls into this callback.
  246. *
  247. * Returns:
  248. * Pointer to a &drm_framebuffer on success or an error pointer on failure.
  249. */
  250. struct drm_framebuffer *
  251. drm_gem_fb_create(struct drm_device *dev, struct drm_file *file,
  252. const struct drm_format_info *info,
  253. const struct drm_mode_fb_cmd2 *mode_cmd)
  254. {
  255. return drm_gem_fb_create_with_funcs(dev, file, info, mode_cmd,
  256. &drm_gem_fb_funcs);
  257. }
  258. EXPORT_SYMBOL_GPL(drm_gem_fb_create);
  259. static const struct drm_framebuffer_funcs drm_gem_fb_funcs_dirtyfb = {
  260. .destroy = drm_gem_fb_destroy,
  261. .create_handle = drm_gem_fb_create_handle,
  262. .dirty = drm_atomic_helper_dirtyfb,
  263. };
  264. /**
  265. * drm_gem_fb_create_with_dirty() - Helper function for the
  266. * &drm_mode_config_funcs.fb_create callback
  267. * @dev: DRM device
  268. * @file: DRM file that holds the GEM handle(s) backing the framebuffer
  269. * @info: pixel format information
  270. * @mode_cmd: Metadata from the userspace framebuffer creation request
  271. *
  272. * This function creates a new framebuffer object described by
  273. * &drm_mode_fb_cmd2. This description includes handles for the buffer(s)
  274. * backing the framebuffer. drm_atomic_helper_dirtyfb() is used for the dirty
  275. * callback giving framebuffer flushing through the atomic machinery. Use
  276. * drm_gem_fb_create() if you don't need the dirty callback.
  277. * The function does buffer size validation.
  278. *
  279. * Drivers should also call drm_plane_enable_fb_damage_clips() on all planes
  280. * to enable userspace to use damage clips also with the ATOMIC IOCTL.
  281. *
  282. * Drivers can use this as their &drm_mode_config_funcs.fb_create callback.
  283. * The ADDFB2 IOCTL calls into this callback.
  284. *
  285. * Returns:
  286. * Pointer to a &drm_framebuffer on success or an error pointer on failure.
  287. */
  288. struct drm_framebuffer *
  289. drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file,
  290. const struct drm_format_info *info,
  291. const struct drm_mode_fb_cmd2 *mode_cmd)
  292. {
  293. return drm_gem_fb_create_with_funcs(dev, file, info, mode_cmd,
  294. &drm_gem_fb_funcs_dirtyfb);
  295. }
  296. EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty);
  297. /**
  298. * drm_gem_fb_vmap - maps all framebuffer BOs into kernel address space
  299. * @fb: the framebuffer
  300. * @map: returns the mapping's address for each BO
  301. * @data: returns the data address for each BO, can be NULL
  302. *
  303. * This function maps all buffer objects of the given framebuffer into
  304. * kernel address space and stores them in struct iosys_map. If the
  305. * mapping operation fails for one of the BOs, the function unmaps the
  306. * already established mappings automatically.
  307. *
  308. * Callers that want to access a BO's stored data should pass @data.
  309. * The argument returns the addresses of the data stored in each BO. This
  310. * is different from @map if the framebuffer's offsets field is non-zero.
  311. *
  312. * Both, @map and @data, must each refer to arrays with at least
  313. * fb->format->num_planes elements.
  314. *
  315. * See drm_gem_fb_vunmap() for unmapping.
  316. *
  317. * Returns:
  318. * 0 on success, or a negative errno code otherwise.
  319. */
  320. int drm_gem_fb_vmap(struct drm_framebuffer *fb, struct iosys_map *map,
  321. struct iosys_map *data)
  322. {
  323. struct drm_gem_object *obj;
  324. unsigned int i;
  325. int ret;
  326. for (i = 0; i < fb->format->num_planes; ++i) {
  327. obj = drm_gem_fb_get_obj(fb, i);
  328. if (!obj) {
  329. ret = -EINVAL;
  330. goto err_drm_gem_vunmap;
  331. }
  332. ret = drm_gem_vmap(obj, &map[i]);
  333. if (ret)
  334. goto err_drm_gem_vunmap;
  335. }
  336. if (data) {
  337. for (i = 0; i < fb->format->num_planes; ++i) {
  338. memcpy(&data[i], &map[i], sizeof(data[i]));
  339. if (iosys_map_is_null(&data[i]))
  340. continue;
  341. iosys_map_incr(&data[i], fb->offsets[i]);
  342. }
  343. }
  344. return 0;
  345. err_drm_gem_vunmap:
  346. while (i) {
  347. --i;
  348. obj = drm_gem_fb_get_obj(fb, i);
  349. if (!obj)
  350. continue;
  351. drm_gem_vunmap(obj, &map[i]);
  352. }
  353. return ret;
  354. }
  355. EXPORT_SYMBOL(drm_gem_fb_vmap);
  356. /**
  357. * drm_gem_fb_vunmap - unmaps framebuffer BOs from kernel address space
  358. * @fb: the framebuffer
  359. * @map: mapping addresses as returned by drm_gem_fb_vmap()
  360. *
  361. * This function unmaps all buffer objects of the given framebuffer.
  362. *
  363. * See drm_gem_fb_vmap() for more information.
  364. */
  365. void drm_gem_fb_vunmap(struct drm_framebuffer *fb, struct iosys_map *map)
  366. {
  367. unsigned int i = fb->format->num_planes;
  368. struct drm_gem_object *obj;
  369. while (i) {
  370. --i;
  371. obj = drm_gem_fb_get_obj(fb, i);
  372. if (!obj)
  373. continue;
  374. if (iosys_map_is_null(&map[i]))
  375. continue;
  376. drm_gem_vunmap(obj, &map[i]);
  377. }
  378. }
  379. EXPORT_SYMBOL(drm_gem_fb_vunmap);
  380. static void __drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir,
  381. unsigned int num_planes)
  382. {
  383. struct dma_buf_attachment *import_attach;
  384. struct drm_gem_object *obj;
  385. int ret;
  386. while (num_planes) {
  387. --num_planes;
  388. obj = drm_gem_fb_get_obj(fb, num_planes);
  389. if (!obj)
  390. continue;
  391. import_attach = obj->import_attach;
  392. if (!drm_gem_is_imported(obj))
  393. continue;
  394. ret = dma_buf_end_cpu_access(import_attach->dmabuf, dir);
  395. if (ret)
  396. drm_err(fb->dev, "dma_buf_end_cpu_access(%u, %d) failed: %d\n",
  397. ret, num_planes, dir);
  398. }
  399. }
  400. /**
  401. * drm_gem_fb_begin_cpu_access - prepares GEM buffer objects for CPU access
  402. * @fb: the framebuffer
  403. * @dir: access mode
  404. *
  405. * Prepares a framebuffer's GEM buffer objects for CPU access. This function
  406. * must be called before accessing the BO data within the kernel. For imported
  407. * BOs, the function calls dma_buf_begin_cpu_access().
  408. *
  409. * See drm_gem_fb_end_cpu_access() for signalling the end of CPU access.
  410. *
  411. * Returns:
  412. * 0 on success, or a negative errno code otherwise.
  413. */
  414. int drm_gem_fb_begin_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
  415. {
  416. struct dma_buf_attachment *import_attach;
  417. struct drm_gem_object *obj;
  418. unsigned int i;
  419. int ret;
  420. for (i = 0; i < fb->format->num_planes; ++i) {
  421. obj = drm_gem_fb_get_obj(fb, i);
  422. if (!obj) {
  423. ret = -EINVAL;
  424. goto err___drm_gem_fb_end_cpu_access;
  425. }
  426. import_attach = obj->import_attach;
  427. if (!drm_gem_is_imported(obj))
  428. continue;
  429. ret = dma_buf_begin_cpu_access(import_attach->dmabuf, dir);
  430. if (ret)
  431. goto err___drm_gem_fb_end_cpu_access;
  432. }
  433. return 0;
  434. err___drm_gem_fb_end_cpu_access:
  435. __drm_gem_fb_end_cpu_access(fb, dir, i);
  436. return ret;
  437. }
  438. EXPORT_SYMBOL(drm_gem_fb_begin_cpu_access);
  439. /**
  440. * drm_gem_fb_end_cpu_access - signals end of CPU access to GEM buffer objects
  441. * @fb: the framebuffer
  442. * @dir: access mode
  443. *
  444. * Signals the end of CPU access to the given framebuffer's GEM buffer objects. This
  445. * function must be paired with a corresponding call to drm_gem_fb_begin_cpu_access().
  446. * For imported BOs, the function calls dma_buf_end_cpu_access().
  447. *
  448. * See also drm_gem_fb_begin_cpu_access().
  449. */
  450. void drm_gem_fb_end_cpu_access(struct drm_framebuffer *fb, enum dma_data_direction dir)
  451. {
  452. __drm_gem_fb_end_cpu_access(fb, dir, fb->format->num_planes);
  453. }
  454. EXPORT_SYMBOL(drm_gem_fb_end_cpu_access);
  455. // TODO Drop this function and replace by drm_format_info_bpp() once all
  456. // DRM_FORMAT_* provide proper block info in drivers/gpu/drm/drm_fourcc.c
  457. static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev,
  458. const struct drm_format_info *info,
  459. const struct drm_mode_fb_cmd2 *mode_cmd)
  460. {
  461. switch (info->format) {
  462. case DRM_FORMAT_YUV420_8BIT:
  463. return 12;
  464. case DRM_FORMAT_YUV420_10BIT:
  465. return 15;
  466. case DRM_FORMAT_VUY101010:
  467. return 30;
  468. default:
  469. return drm_format_info_bpp(info, 0);
  470. }
  471. }
  472. static int drm_gem_afbc_min_size(struct drm_device *dev,
  473. const struct drm_format_info *info,
  474. const struct drm_mode_fb_cmd2 *mode_cmd,
  475. struct drm_afbc_framebuffer *afbc_fb)
  476. {
  477. __u32 n_blocks, w_alignment, h_alignment, hdr_alignment;
  478. /* remove bpp when all users properly encode cpp in drm_format_info */
  479. __u32 bpp;
  480. switch (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK) {
  481. case AFBC_FORMAT_MOD_BLOCK_SIZE_16x16:
  482. afbc_fb->block_width = 16;
  483. afbc_fb->block_height = 16;
  484. break;
  485. case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8:
  486. afbc_fb->block_width = 32;
  487. afbc_fb->block_height = 8;
  488. break;
  489. /* no user exists yet - fall through */
  490. case AFBC_FORMAT_MOD_BLOCK_SIZE_64x4:
  491. case AFBC_FORMAT_MOD_BLOCK_SIZE_32x8_64x4:
  492. default:
  493. drm_dbg_kms(dev, "Invalid AFBC_FORMAT_MOD_BLOCK_SIZE: %lld.\n",
  494. mode_cmd->modifier[0]
  495. & AFBC_FORMAT_MOD_BLOCK_SIZE_MASK);
  496. return -EINVAL;
  497. }
  498. /* tiled header afbc */
  499. w_alignment = afbc_fb->block_width;
  500. h_alignment = afbc_fb->block_height;
  501. hdr_alignment = AFBC_HDR_ALIGN;
  502. if (mode_cmd->modifier[0] & AFBC_FORMAT_MOD_TILED) {
  503. w_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
  504. h_alignment *= AFBC_TH_LAYOUT_ALIGNMENT;
  505. hdr_alignment = AFBC_TH_BODY_START_ALIGNMENT;
  506. }
  507. afbc_fb->aligned_width = ALIGN(mode_cmd->width, w_alignment);
  508. afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment);
  509. afbc_fb->offset = mode_cmd->offsets[0];
  510. bpp = drm_gem_afbc_get_bpp(dev, info, mode_cmd);
  511. if (!bpp) {
  512. drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp);
  513. return -EINVAL;
  514. }
  515. n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height)
  516. / AFBC_SUPERBLOCK_PIXELS;
  517. afbc_fb->afbc_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, hdr_alignment);
  518. afbc_fb->afbc_size += n_blocks * ALIGN(bpp * AFBC_SUPERBLOCK_PIXELS / 8,
  519. AFBC_SUPERBLOCK_ALIGNMENT);
  520. return 0;
  521. }
  522. /**
  523. * drm_gem_fb_afbc_init() - Helper function for drivers using afbc to
  524. * fill and validate all the afbc-specific
  525. * struct drm_afbc_framebuffer members
  526. *
  527. * @dev: DRM device
  528. * @afbc_fb: afbc-specific framebuffer
  529. * @info: pixel format information
  530. * @mode_cmd: Metadata from the userspace framebuffer creation request
  531. * @afbc_fb: afbc framebuffer
  532. *
  533. * This function can be used by drivers which support afbc to complete
  534. * the preparation of struct drm_afbc_framebuffer. It must be called after
  535. * allocating the said struct and calling drm_gem_fb_init_with_funcs().
  536. * It is caller's responsibility to put afbc_fb->base.obj objects in case
  537. * the call is unsuccessful.
  538. *
  539. * Returns:
  540. * Zero on success or a negative error value on failure.
  541. */
  542. int drm_gem_fb_afbc_init(struct drm_device *dev,
  543. const struct drm_format_info *info,
  544. const struct drm_mode_fb_cmd2 *mode_cmd,
  545. struct drm_afbc_framebuffer *afbc_fb)
  546. {
  547. struct drm_gem_object **objs;
  548. int ret;
  549. objs = afbc_fb->base.obj;
  550. ret = drm_gem_afbc_min_size(dev, info, mode_cmd, afbc_fb);
  551. if (ret < 0)
  552. return ret;
  553. if (objs[0]->size < afbc_fb->afbc_size) {
  554. drm_dbg_kms(dev, "GEM object size (%zu) smaller than minimum afbc size (%u)\n",
  555. objs[0]->size, afbc_fb->afbc_size);
  556. return -EINVAL;
  557. }
  558. return 0;
  559. }
  560. EXPORT_SYMBOL_GPL(drm_gem_fb_afbc_init);