drm_gem_framebuffer_helper.c 18 KB

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