vmwgfx_stdu.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669
  1. /******************************************************************************
  2. *
  3. * COPYRIGHT © 2014-2015 VMware, Inc., Palo Alto, CA., USA
  4. * All Rights Reserved.
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sub license, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial portions
  16. * of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. ******************************************************************************/
  27. #include "vmwgfx_kms.h"
  28. #include "device_include/svga3d_surfacedefs.h"
  29. #include <drm/drm_plane_helper.h>
  30. #include <drm/drm_atomic.h>
  31. #include <drm/drm_atomic_helper.h>
  32. #define vmw_crtc_to_stdu(x) \
  33. container_of(x, struct vmw_screen_target_display_unit, base.crtc)
  34. #define vmw_encoder_to_stdu(x) \
  35. container_of(x, struct vmw_screen_target_display_unit, base.encoder)
  36. #define vmw_connector_to_stdu(x) \
  37. container_of(x, struct vmw_screen_target_display_unit, base.connector)
  38. enum stdu_content_type {
  39. SAME_AS_DISPLAY = 0,
  40. SEPARATE_SURFACE,
  41. SEPARATE_DMA
  42. };
  43. /**
  44. * struct vmw_stdu_dirty - closure structure for the update functions
  45. *
  46. * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
  47. * @transfer: Transfer direction for DMA command.
  48. * @left: Left side of bounding box.
  49. * @right: Right side of bounding box.
  50. * @top: Top side of bounding box.
  51. * @bottom: Bottom side of bounding box.
  52. * @buf: DMA buffer when DMA-ing between buffer and screen targets.
  53. * @sid: Surface ID when copying between surface and screen targets.
  54. */
  55. struct vmw_stdu_dirty {
  56. struct vmw_kms_dirty base;
  57. SVGA3dTransferType transfer;
  58. s32 left, right, top, bottom;
  59. u32 pitch;
  60. union {
  61. struct vmw_dma_buffer *buf;
  62. u32 sid;
  63. };
  64. };
  65. /*
  66. * SVGA commands that are used by this code. Please see the device headers
  67. * for explanation.
  68. */
  69. struct vmw_stdu_update {
  70. SVGA3dCmdHeader header;
  71. SVGA3dCmdUpdateGBScreenTarget body;
  72. };
  73. struct vmw_stdu_dma {
  74. SVGA3dCmdHeader header;
  75. SVGA3dCmdSurfaceDMA body;
  76. };
  77. struct vmw_stdu_surface_copy {
  78. SVGA3dCmdHeader header;
  79. SVGA3dCmdSurfaceCopy body;
  80. };
  81. /**
  82. * struct vmw_screen_target_display_unit
  83. *
  84. * @base: VMW specific DU structure
  85. * @display_srf: surface to be displayed. The dimension of this will always
  86. * match the display mode. If the display mode matches
  87. * content_vfbs dimensions, then this is a pointer into the
  88. * corresponding field in content_vfbs. If not, then this
  89. * is a separate buffer to which content_vfbs will blit to.
  90. * @content_type: content_fb type
  91. * @defined: true if the current display unit has been initialized
  92. */
  93. struct vmw_screen_target_display_unit {
  94. struct vmw_display_unit base;
  95. const struct vmw_surface *display_srf;
  96. enum stdu_content_type content_fb_type;
  97. s32 display_width, display_height;
  98. bool defined;
  99. /* For CPU Blit */
  100. struct ttm_bo_kmap_obj host_map, guest_map;
  101. unsigned int cpp;
  102. };
  103. static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);
  104. /******************************************************************************
  105. * Screen Target Display Unit CRTC Functions
  106. *****************************************************************************/
  107. /**
  108. * vmw_stdu_crtc_destroy - cleans up the STDU
  109. *
  110. * @crtc: used to get a reference to the containing STDU
  111. */
  112. static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc)
  113. {
  114. vmw_stdu_destroy(vmw_crtc_to_stdu(crtc));
  115. }
  116. /**
  117. * vmw_stdu_define_st - Defines a Screen Target
  118. *
  119. * @dev_priv: VMW DRM device
  120. * @stdu: display unit to create a Screen Target for
  121. * @mode: The mode to set.
  122. * @crtc_x: X coordinate of screen target relative to framebuffer origin.
  123. * @crtc_y: Y coordinate of screen target relative to framebuffer origin.
  124. *
  125. * Creates a STDU that we can used later. This function is called whenever the
  126. * framebuffer size changes.
  127. *
  128. * RETURNs:
  129. * 0 on success, error code on failure
  130. */
  131. static int vmw_stdu_define_st(struct vmw_private *dev_priv,
  132. struct vmw_screen_target_display_unit *stdu,
  133. struct drm_display_mode *mode,
  134. int crtc_x, int crtc_y)
  135. {
  136. struct {
  137. SVGA3dCmdHeader header;
  138. SVGA3dCmdDefineGBScreenTarget body;
  139. } *cmd;
  140. cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  141. if (unlikely(cmd == NULL)) {
  142. DRM_ERROR("Out of FIFO space defining Screen Target\n");
  143. return -ENOMEM;
  144. }
  145. cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET;
  146. cmd->header.size = sizeof(cmd->body);
  147. cmd->body.stid = stdu->base.unit;
  148. cmd->body.width = mode->hdisplay;
  149. cmd->body.height = mode->vdisplay;
  150. cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0;
  151. cmd->body.dpi = 0;
  152. if (stdu->base.is_implicit) {
  153. cmd->body.xRoot = crtc_x;
  154. cmd->body.yRoot = crtc_y;
  155. } else {
  156. cmd->body.xRoot = stdu->base.gui_x;
  157. cmd->body.yRoot = stdu->base.gui_y;
  158. }
  159. stdu->base.set_gui_x = cmd->body.xRoot;
  160. stdu->base.set_gui_y = cmd->body.yRoot;
  161. vmw_fifo_commit(dev_priv, sizeof(*cmd));
  162. stdu->defined = true;
  163. stdu->display_width = mode->hdisplay;
  164. stdu->display_height = mode->vdisplay;
  165. return 0;
  166. }
  167. /**
  168. * vmw_stdu_bind_st - Binds a surface to a Screen Target
  169. *
  170. * @dev_priv: VMW DRM device
  171. * @stdu: display unit affected
  172. * @res: Buffer to bind to the screen target. Set to NULL to blank screen.
  173. *
  174. * Binding a surface to a Screen Target the same as flipping
  175. */
  176. static int vmw_stdu_bind_st(struct vmw_private *dev_priv,
  177. struct vmw_screen_target_display_unit *stdu,
  178. const struct vmw_resource *res)
  179. {
  180. SVGA3dSurfaceImageId image;
  181. struct {
  182. SVGA3dCmdHeader header;
  183. SVGA3dCmdBindGBScreenTarget body;
  184. } *cmd;
  185. if (!stdu->defined) {
  186. DRM_ERROR("No screen target defined\n");
  187. return -EINVAL;
  188. }
  189. /* Set up image using information in vfb */
  190. memset(&image, 0, sizeof(image));
  191. image.sid = res ? res->id : SVGA3D_INVALID_ID;
  192. cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  193. if (unlikely(cmd == NULL)) {
  194. DRM_ERROR("Out of FIFO space binding a screen target\n");
  195. return -ENOMEM;
  196. }
  197. cmd->header.id = SVGA_3D_CMD_BIND_GB_SCREENTARGET;
  198. cmd->header.size = sizeof(cmd->body);
  199. cmd->body.stid = stdu->base.unit;
  200. cmd->body.image = image;
  201. vmw_fifo_commit(dev_priv, sizeof(*cmd));
  202. return 0;
  203. }
  204. /**
  205. * vmw_stdu_populate_update - populate an UPDATE_GB_SCREENTARGET command with a
  206. * bounding box.
  207. *
  208. * @cmd: Pointer to command stream.
  209. * @unit: Screen target unit.
  210. * @left: Left side of bounding box.
  211. * @right: Right side of bounding box.
  212. * @top: Top side of bounding box.
  213. * @bottom: Bottom side of bounding box.
  214. */
  215. static void vmw_stdu_populate_update(void *cmd, int unit,
  216. s32 left, s32 right, s32 top, s32 bottom)
  217. {
  218. struct vmw_stdu_update *update = cmd;
  219. update->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET;
  220. update->header.size = sizeof(update->body);
  221. update->body.stid = unit;
  222. update->body.rect.x = left;
  223. update->body.rect.y = top;
  224. update->body.rect.w = right - left;
  225. update->body.rect.h = bottom - top;
  226. }
  227. /**
  228. * vmw_stdu_update_st - Full update of a Screen Target
  229. *
  230. * @dev_priv: VMW DRM device
  231. * @stdu: display unit affected
  232. *
  233. * This function needs to be called whenever the content of a screen
  234. * target has changed completely. Typically as a result of a backing
  235. * surface change.
  236. *
  237. * RETURNS:
  238. * 0 on success, error code on failure
  239. */
  240. static int vmw_stdu_update_st(struct vmw_private *dev_priv,
  241. struct vmw_screen_target_display_unit *stdu)
  242. {
  243. struct vmw_stdu_update *cmd;
  244. if (!stdu->defined) {
  245. DRM_ERROR("No screen target defined");
  246. return -EINVAL;
  247. }
  248. cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  249. if (unlikely(cmd == NULL)) {
  250. DRM_ERROR("Out of FIFO space updating a Screen Target\n");
  251. return -ENOMEM;
  252. }
  253. vmw_stdu_populate_update(cmd, stdu->base.unit,
  254. 0, stdu->display_width,
  255. 0, stdu->display_height);
  256. vmw_fifo_commit(dev_priv, sizeof(*cmd));
  257. return 0;
  258. }
  259. /**
  260. * vmw_stdu_destroy_st - Destroy a Screen Target
  261. *
  262. * @dev_priv: VMW DRM device
  263. * @stdu: display unit to destroy
  264. */
  265. static int vmw_stdu_destroy_st(struct vmw_private *dev_priv,
  266. struct vmw_screen_target_display_unit *stdu)
  267. {
  268. int ret;
  269. struct {
  270. SVGA3dCmdHeader header;
  271. SVGA3dCmdDestroyGBScreenTarget body;
  272. } *cmd;
  273. /* Nothing to do if not successfully defined */
  274. if (unlikely(!stdu->defined))
  275. return 0;
  276. cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  277. if (unlikely(cmd == NULL)) {
  278. DRM_ERROR("Out of FIFO space, screen target not destroyed\n");
  279. return -ENOMEM;
  280. }
  281. cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET;
  282. cmd->header.size = sizeof(cmd->body);
  283. cmd->body.stid = stdu->base.unit;
  284. vmw_fifo_commit(dev_priv, sizeof(*cmd));
  285. /* Force sync */
  286. ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
  287. if (unlikely(ret != 0))
  288. DRM_ERROR("Failed to sync with HW");
  289. stdu->defined = false;
  290. stdu->display_width = 0;
  291. stdu->display_height = 0;
  292. return ret;
  293. }
  294. /**
  295. * vmw_stdu_crtc_mode_set_nofb - Updates screen target size
  296. *
  297. * @crtc: CRTC associated with the screen target
  298. *
  299. * This function defines/destroys a screen target
  300. *
  301. */
  302. static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
  303. {
  304. struct vmw_private *dev_priv;
  305. struct vmw_screen_target_display_unit *stdu;
  306. int ret;
  307. stdu = vmw_crtc_to_stdu(crtc);
  308. dev_priv = vmw_priv(crtc->dev);
  309. if (stdu->defined) {
  310. ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
  311. if (ret)
  312. DRM_ERROR("Failed to blank CRTC\n");
  313. (void) vmw_stdu_update_st(dev_priv, stdu);
  314. ret = vmw_stdu_destroy_st(dev_priv, stdu);
  315. if (ret)
  316. DRM_ERROR("Failed to destroy Screen Target\n");
  317. stdu->content_fb_type = SAME_AS_DISPLAY;
  318. }
  319. if (!crtc->state->enable)
  320. return;
  321. vmw_svga_enable(dev_priv);
  322. ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, crtc->x, crtc->y);
  323. if (ret)
  324. DRM_ERROR("Failed to define Screen Target of size %dx%d\n",
  325. crtc->x, crtc->y);
  326. }
  327. static void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc)
  328. {
  329. }
  330. static void vmw_stdu_crtc_helper_commit(struct drm_crtc *crtc)
  331. {
  332. struct vmw_private *dev_priv;
  333. struct vmw_screen_target_display_unit *stdu;
  334. struct vmw_framebuffer *vfb;
  335. struct drm_framebuffer *fb;
  336. stdu = vmw_crtc_to_stdu(crtc);
  337. dev_priv = vmw_priv(crtc->dev);
  338. fb = crtc->primary->fb;
  339. vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL;
  340. if (vfb)
  341. vmw_kms_add_active(dev_priv, &stdu->base, vfb);
  342. else
  343. vmw_kms_del_active(dev_priv, &stdu->base);
  344. }
  345. static void vmw_stdu_crtc_helper_disable(struct drm_crtc *crtc)
  346. {
  347. struct vmw_private *dev_priv;
  348. struct vmw_screen_target_display_unit *stdu;
  349. int ret;
  350. if (!crtc) {
  351. DRM_ERROR("CRTC is NULL\n");
  352. return;
  353. }
  354. stdu = vmw_crtc_to_stdu(crtc);
  355. dev_priv = vmw_priv(crtc->dev);
  356. if (stdu->defined) {
  357. ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
  358. if (ret)
  359. DRM_ERROR("Failed to blank CRTC\n");
  360. (void) vmw_stdu_update_st(dev_priv, stdu);
  361. ret = vmw_stdu_destroy_st(dev_priv, stdu);
  362. if (ret)
  363. DRM_ERROR("Failed to destroy Screen Target\n");
  364. stdu->content_fb_type = SAME_AS_DISPLAY;
  365. }
  366. }
  367. /**
  368. * vmw_stdu_crtc_page_flip - Binds a buffer to a screen target
  369. *
  370. * @crtc: CRTC to attach FB to
  371. * @fb: FB to attach
  372. * @event: Event to be posted. This event should've been alloced
  373. * using k[mz]alloc, and should've been completely initialized.
  374. * @page_flip_flags: Input flags.
  375. *
  376. * If the STDU uses the same display and content buffers, i.e. a true flip,
  377. * this function will replace the existing display buffer with the new content
  378. * buffer.
  379. *
  380. * If the STDU uses different display and content buffers, i.e. a blit, then
  381. * only the content buffer will be updated.
  382. *
  383. * RETURNS:
  384. * 0 on success, error code on failure
  385. */
  386. static int vmw_stdu_crtc_page_flip(struct drm_crtc *crtc,
  387. struct drm_framebuffer *new_fb,
  388. struct drm_pending_vblank_event *event,
  389. uint32_t flags,
  390. struct drm_modeset_acquire_ctx *ctx)
  391. {
  392. struct vmw_private *dev_priv = vmw_priv(crtc->dev);
  393. struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
  394. struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(new_fb);
  395. struct drm_vmw_rect vclips;
  396. int ret;
  397. dev_priv = vmw_priv(crtc->dev);
  398. stdu = vmw_crtc_to_stdu(crtc);
  399. if (!stdu->defined || !vmw_kms_crtc_flippable(dev_priv, crtc))
  400. return -EINVAL;
  401. /*
  402. * We're always async, but the helper doesn't know how to set async
  403. * so lie to the helper. Also, the helper expects someone
  404. * to pick the event up from the crtc state, and if nobody does,
  405. * it will free it. Since we handle the event in this function,
  406. * don't hand it to the helper.
  407. */
  408. flags &= ~DRM_MODE_PAGE_FLIP_ASYNC;
  409. ret = drm_atomic_helper_page_flip(crtc, new_fb, NULL, flags, ctx);
  410. if (ret) {
  411. DRM_ERROR("Page flip error %d.\n", ret);
  412. return ret;
  413. }
  414. if (stdu->base.is_implicit)
  415. vmw_kms_update_implicit_fb(dev_priv, crtc);
  416. /*
  417. * Now that we've bound a new surface to the screen target,
  418. * update the contents.
  419. */
  420. vclips.x = crtc->x;
  421. vclips.y = crtc->y;
  422. vclips.w = crtc->mode.hdisplay;
  423. vclips.h = crtc->mode.vdisplay;
  424. if (vfb->dmabuf)
  425. ret = vmw_kms_stdu_dma(dev_priv, NULL, vfb, NULL, NULL, &vclips,
  426. 1, 1, true, false);
  427. else
  428. ret = vmw_kms_stdu_surface_dirty(dev_priv, vfb, NULL, &vclips,
  429. NULL, 0, 0, 1, 1, NULL);
  430. if (ret) {
  431. DRM_ERROR("Page flip update error %d.\n", ret);
  432. return ret;
  433. }
  434. if (event) {
  435. struct vmw_fence_obj *fence = NULL;
  436. struct drm_file *file_priv = event->base.file_priv;
  437. vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
  438. if (!fence)
  439. return -ENOMEM;
  440. ret = vmw_event_fence_action_queue(file_priv, fence,
  441. &event->base,
  442. &event->event.tv_sec,
  443. &event->event.tv_usec,
  444. true);
  445. vmw_fence_obj_unreference(&fence);
  446. } else {
  447. (void) vmw_fifo_flush(dev_priv, false);
  448. }
  449. return 0;
  450. }
  451. /**
  452. * vmw_stdu_dmabuf_clip - Callback to encode a suface DMA command cliprect
  453. *
  454. * @dirty: The closure structure.
  455. *
  456. * Encodes a surface DMA command cliprect and updates the bounding box
  457. * for the DMA.
  458. */
  459. static void vmw_stdu_dmabuf_clip(struct vmw_kms_dirty *dirty)
  460. {
  461. struct vmw_stdu_dirty *ddirty =
  462. container_of(dirty, struct vmw_stdu_dirty, base);
  463. struct vmw_stdu_dma *cmd = dirty->cmd;
  464. struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
  465. blit += dirty->num_hits;
  466. blit->srcx = dirty->fb_x;
  467. blit->srcy = dirty->fb_y;
  468. blit->x = dirty->unit_x1;
  469. blit->y = dirty->unit_y1;
  470. blit->d = 1;
  471. blit->w = dirty->unit_x2 - dirty->unit_x1;
  472. blit->h = dirty->unit_y2 - dirty->unit_y1;
  473. dirty->num_hits++;
  474. if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM)
  475. return;
  476. /* Destination bounding box */
  477. ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1);
  478. ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1);
  479. ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2);
  480. ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2);
  481. }
  482. /**
  483. * vmw_stdu_dmabuf_fifo_commit - Callback to fill in and submit a DMA command.
  484. *
  485. * @dirty: The closure structure.
  486. *
  487. * Fills in the missing fields in a DMA command, and optionally encodes
  488. * a screen target update command, depending on transfer direction.
  489. */
  490. static void vmw_stdu_dmabuf_fifo_commit(struct vmw_kms_dirty *dirty)
  491. {
  492. struct vmw_stdu_dirty *ddirty =
  493. container_of(dirty, struct vmw_stdu_dirty, base);
  494. struct vmw_screen_target_display_unit *stdu =
  495. container_of(dirty->unit, typeof(*stdu), base);
  496. struct vmw_stdu_dma *cmd = dirty->cmd;
  497. struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
  498. SVGA3dCmdSurfaceDMASuffix *suffix =
  499. (SVGA3dCmdSurfaceDMASuffix *) &blit[dirty->num_hits];
  500. size_t blit_size = sizeof(*blit) * dirty->num_hits + sizeof(*suffix);
  501. if (!dirty->num_hits) {
  502. vmw_fifo_commit(dirty->dev_priv, 0);
  503. return;
  504. }
  505. cmd->header.id = SVGA_3D_CMD_SURFACE_DMA;
  506. cmd->header.size = sizeof(cmd->body) + blit_size;
  507. vmw_bo_get_guest_ptr(&ddirty->buf->base, &cmd->body.guest.ptr);
  508. cmd->body.guest.pitch = ddirty->pitch;
  509. cmd->body.host.sid = stdu->display_srf->res.id;
  510. cmd->body.host.face = 0;
  511. cmd->body.host.mipmap = 0;
  512. cmd->body.transfer = ddirty->transfer;
  513. suffix->suffixSize = sizeof(*suffix);
  514. suffix->maximumOffset = ddirty->buf->base.num_pages * PAGE_SIZE;
  515. if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
  516. blit_size += sizeof(struct vmw_stdu_update);
  517. vmw_stdu_populate_update(&suffix[1], stdu->base.unit,
  518. ddirty->left, ddirty->right,
  519. ddirty->top, ddirty->bottom);
  520. }
  521. vmw_fifo_commit(dirty->dev_priv, sizeof(*cmd) + blit_size);
  522. ddirty->left = ddirty->top = S32_MAX;
  523. ddirty->right = ddirty->bottom = S32_MIN;
  524. }
  525. /**
  526. * vmw_stdu_dmabuf_cpu_clip - Callback to encode a CPU blit
  527. *
  528. * @dirty: The closure structure.
  529. *
  530. * This function calculates the bounding box for all the incoming clips
  531. */
  532. static void vmw_stdu_dmabuf_cpu_clip(struct vmw_kms_dirty *dirty)
  533. {
  534. struct vmw_stdu_dirty *ddirty =
  535. container_of(dirty, struct vmw_stdu_dirty, base);
  536. dirty->num_hits = 1;
  537. /* Calculate bounding box */
  538. ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1);
  539. ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1);
  540. ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2);
  541. ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2);
  542. }
  543. /**
  544. * vmw_stdu_dmabuf_cpu_commit - Callback to do a CPU blit from DMAbuf
  545. *
  546. * @dirty: The closure structure.
  547. *
  548. * For the special case when we cannot create a proxy surface in a
  549. * 2D VM, we have to do a CPU blit ourselves.
  550. */
  551. static void vmw_stdu_dmabuf_cpu_commit(struct vmw_kms_dirty *dirty)
  552. {
  553. struct vmw_stdu_dirty *ddirty =
  554. container_of(dirty, struct vmw_stdu_dirty, base);
  555. struct vmw_screen_target_display_unit *stdu =
  556. container_of(dirty->unit, typeof(*stdu), base);
  557. s32 width, height;
  558. s32 src_pitch, dst_pitch;
  559. u8 *src, *dst;
  560. bool not_used;
  561. if (!dirty->num_hits)
  562. return;
  563. width = ddirty->right - ddirty->left;
  564. height = ddirty->bottom - ddirty->top;
  565. if (width == 0 || height == 0)
  566. return;
  567. /* Assume we are blitting from Host (display_srf) to Guest (dmabuf) */
  568. src_pitch = stdu->display_srf->base_size.width * stdu->cpp;
  569. src = ttm_kmap_obj_virtual(&stdu->host_map, &not_used);
  570. src += dirty->unit_y1 * src_pitch + dirty->unit_x1 * stdu->cpp;
  571. dst_pitch = ddirty->pitch;
  572. dst = ttm_kmap_obj_virtual(&stdu->guest_map, &not_used);
  573. dst += dirty->fb_y * dst_pitch + dirty->fb_x * stdu->cpp;
  574. /* Figure out the real direction */
  575. if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
  576. u8 *tmp;
  577. s32 tmp_pitch;
  578. tmp = src;
  579. tmp_pitch = src_pitch;
  580. src = dst;
  581. src_pitch = dst_pitch;
  582. dst = tmp;
  583. dst_pitch = tmp_pitch;
  584. }
  585. /* CPU Blit */
  586. while (height-- > 0) {
  587. memcpy(dst, src, width * stdu->cpp);
  588. dst += dst_pitch;
  589. src += src_pitch;
  590. }
  591. if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) {
  592. struct vmw_private *dev_priv;
  593. struct vmw_stdu_update *cmd;
  594. struct drm_clip_rect region;
  595. int ret;
  596. /* We are updating the actual surface, not a proxy */
  597. region.x1 = ddirty->left;
  598. region.x2 = ddirty->right;
  599. region.y1 = ddirty->top;
  600. region.y2 = ddirty->bottom;
  601. ret = vmw_kms_update_proxy(
  602. (struct vmw_resource *) &stdu->display_srf->res,
  603. (const struct drm_clip_rect *) &region, 1, 1);
  604. if (ret)
  605. goto out_cleanup;
  606. dev_priv = vmw_priv(stdu->base.crtc.dev);
  607. cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
  608. if (!cmd) {
  609. DRM_ERROR("Cannot reserve FIFO space to update STDU");
  610. goto out_cleanup;
  611. }
  612. vmw_stdu_populate_update(cmd, stdu->base.unit,
  613. ddirty->left, ddirty->right,
  614. ddirty->top, ddirty->bottom);
  615. vmw_fifo_commit(dev_priv, sizeof(*cmd));
  616. }
  617. out_cleanup:
  618. ddirty->left = ddirty->top = S32_MAX;
  619. ddirty->right = ddirty->bottom = S32_MIN;
  620. }
  621. /**
  622. * vmw_kms_stdu_dma - Perform a DMA transfer between a dma-buffer backed
  623. * framebuffer and the screen target system.
  624. *
  625. * @dev_priv: Pointer to the device private structure.
  626. * @file_priv: Pointer to a struct drm-file identifying the caller. May be
  627. * set to NULL, but then @user_fence_rep must also be set to NULL.
  628. * @vfb: Pointer to the dma-buffer backed framebuffer.
  629. * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
  630. * @vclips: Alternate array of clip rects. Either @clips or @vclips must
  631. * be NULL.
  632. * @num_clips: Number of clip rects in @clips or @vclips.
  633. * @increment: Increment to use when looping over @clips or @vclips.
  634. * @to_surface: Whether to DMA to the screen target system as opposed to
  635. * from the screen target system.
  636. * @interruptible: Whether to perform waits interruptible if possible.
  637. *
  638. * If DMA-ing till the screen target system, the function will also notify
  639. * the screen target system that a bounding box of the cliprects has been
  640. * updated.
  641. * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
  642. * interrupted.
  643. */
  644. int vmw_kms_stdu_dma(struct vmw_private *dev_priv,
  645. struct drm_file *file_priv,
  646. struct vmw_framebuffer *vfb,
  647. struct drm_vmw_fence_rep __user *user_fence_rep,
  648. struct drm_clip_rect *clips,
  649. struct drm_vmw_rect *vclips,
  650. uint32_t num_clips,
  651. int increment,
  652. bool to_surface,
  653. bool interruptible)
  654. {
  655. struct vmw_dma_buffer *buf =
  656. container_of(vfb, struct vmw_framebuffer_dmabuf, base)->buffer;
  657. struct vmw_stdu_dirty ddirty;
  658. int ret;
  659. ret = vmw_kms_helper_buffer_prepare(dev_priv, buf, interruptible,
  660. false);
  661. if (ret)
  662. return ret;
  663. ddirty.transfer = (to_surface) ? SVGA3D_WRITE_HOST_VRAM :
  664. SVGA3D_READ_HOST_VRAM;
  665. ddirty.left = ddirty.top = S32_MAX;
  666. ddirty.right = ddirty.bottom = S32_MIN;
  667. ddirty.pitch = vfb->base.pitches[0];
  668. ddirty.buf = buf;
  669. ddirty.base.fifo_commit = vmw_stdu_dmabuf_fifo_commit;
  670. ddirty.base.clip = vmw_stdu_dmabuf_clip;
  671. ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) +
  672. num_clips * sizeof(SVGA3dCopyBox) +
  673. sizeof(SVGA3dCmdSurfaceDMASuffix);
  674. if (to_surface)
  675. ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update);
  676. /* 2D VMs cannot use SVGA_3D_CMD_SURFACE_DMA so do CPU blit instead */
  677. if (!(dev_priv->capabilities & SVGA_CAP_3D)) {
  678. ddirty.base.fifo_commit = vmw_stdu_dmabuf_cpu_commit;
  679. ddirty.base.clip = vmw_stdu_dmabuf_cpu_clip;
  680. ddirty.base.fifo_reserve_size = 0;
  681. }
  682. ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips,
  683. 0, 0, num_clips, increment, &ddirty.base);
  684. vmw_kms_helper_buffer_finish(dev_priv, file_priv, buf, NULL,
  685. user_fence_rep);
  686. return ret;
  687. }
  688. /**
  689. * vmw_stdu_surface_clip - Callback to encode a surface copy command cliprect
  690. *
  691. * @dirty: The closure structure.
  692. *
  693. * Encodes a surface copy command cliprect and updates the bounding box
  694. * for the copy.
  695. */
  696. static void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty)
  697. {
  698. struct vmw_stdu_dirty *sdirty =
  699. container_of(dirty, struct vmw_stdu_dirty, base);
  700. struct vmw_stdu_surface_copy *cmd = dirty->cmd;
  701. struct vmw_screen_target_display_unit *stdu =
  702. container_of(dirty->unit, typeof(*stdu), base);
  703. if (sdirty->sid != stdu->display_srf->res.id) {
  704. struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
  705. blit += dirty->num_hits;
  706. blit->srcx = dirty->fb_x;
  707. blit->srcy = dirty->fb_y;
  708. blit->x = dirty->unit_x1;
  709. blit->y = dirty->unit_y1;
  710. blit->d = 1;
  711. blit->w = dirty->unit_x2 - dirty->unit_x1;
  712. blit->h = dirty->unit_y2 - dirty->unit_y1;
  713. }
  714. dirty->num_hits++;
  715. /* Destination bounding box */
  716. sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
  717. sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
  718. sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
  719. sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
  720. }
  721. /**
  722. * vmw_stdu_surface_fifo_commit - Callback to fill in and submit a surface
  723. * copy command.
  724. *
  725. * @dirty: The closure structure.
  726. *
  727. * Fills in the missing fields in a surface copy command, and encodes a screen
  728. * target update command.
  729. */
  730. static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty)
  731. {
  732. struct vmw_stdu_dirty *sdirty =
  733. container_of(dirty, struct vmw_stdu_dirty, base);
  734. struct vmw_screen_target_display_unit *stdu =
  735. container_of(dirty->unit, typeof(*stdu), base);
  736. struct vmw_stdu_surface_copy *cmd = dirty->cmd;
  737. struct vmw_stdu_update *update;
  738. size_t blit_size = sizeof(SVGA3dCopyBox) * dirty->num_hits;
  739. size_t commit_size;
  740. if (!dirty->num_hits) {
  741. vmw_fifo_commit(dirty->dev_priv, 0);
  742. return;
  743. }
  744. if (sdirty->sid != stdu->display_srf->res.id) {
  745. struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
  746. cmd->header.id = SVGA_3D_CMD_SURFACE_COPY;
  747. cmd->header.size = sizeof(cmd->body) + blit_size;
  748. cmd->body.src.sid = sdirty->sid;
  749. cmd->body.dest.sid = stdu->display_srf->res.id;
  750. update = (struct vmw_stdu_update *) &blit[dirty->num_hits];
  751. commit_size = sizeof(*cmd) + blit_size + sizeof(*update);
  752. } else {
  753. update = dirty->cmd;
  754. commit_size = sizeof(*update);
  755. }
  756. vmw_stdu_populate_update(update, stdu->base.unit, sdirty->left,
  757. sdirty->right, sdirty->top, sdirty->bottom);
  758. vmw_fifo_commit(dirty->dev_priv, commit_size);
  759. sdirty->left = sdirty->top = S32_MAX;
  760. sdirty->right = sdirty->bottom = S32_MIN;
  761. }
  762. /**
  763. * vmw_kms_stdu_surface_dirty - Dirty part of a surface backed framebuffer
  764. *
  765. * @dev_priv: Pointer to the device private structure.
  766. * @framebuffer: Pointer to the surface-buffer backed framebuffer.
  767. * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
  768. * @vclips: Alternate array of clip rects. Either @clips or @vclips must
  769. * be NULL.
  770. * @srf: Pointer to surface to blit from. If NULL, the surface attached
  771. * to @framebuffer will be used.
  772. * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
  773. * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
  774. * @num_clips: Number of clip rects in @clips.
  775. * @inc: Increment to use when looping over @clips.
  776. * @out_fence: If non-NULL, will return a ref-counted pointer to a
  777. * struct vmw_fence_obj. The returned fence pointer may be NULL in which
  778. * case the device has already synchronized.
  779. *
  780. * Returns 0 on success, negative error code on failure. -ERESTARTSYS if
  781. * interrupted.
  782. */
  783. int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
  784. struct vmw_framebuffer *framebuffer,
  785. struct drm_clip_rect *clips,
  786. struct drm_vmw_rect *vclips,
  787. struct vmw_resource *srf,
  788. s32 dest_x,
  789. s32 dest_y,
  790. unsigned num_clips, int inc,
  791. struct vmw_fence_obj **out_fence)
  792. {
  793. struct vmw_framebuffer_surface *vfbs =
  794. container_of(framebuffer, typeof(*vfbs), base);
  795. struct vmw_stdu_dirty sdirty;
  796. int ret;
  797. if (!srf)
  798. srf = &vfbs->surface->res;
  799. ret = vmw_kms_helper_resource_prepare(srf, true);
  800. if (ret)
  801. return ret;
  802. if (vfbs->is_dmabuf_proxy) {
  803. ret = vmw_kms_update_proxy(srf, clips, num_clips, inc);
  804. if (ret)
  805. goto out_finish;
  806. }
  807. sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit;
  808. sdirty.base.clip = vmw_kms_stdu_surface_clip;
  809. sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) +
  810. sizeof(SVGA3dCopyBox) * num_clips +
  811. sizeof(struct vmw_stdu_update);
  812. sdirty.sid = srf->id;
  813. sdirty.left = sdirty.top = S32_MAX;
  814. sdirty.right = sdirty.bottom = S32_MIN;
  815. ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
  816. dest_x, dest_y, num_clips, inc,
  817. &sdirty.base);
  818. out_finish:
  819. vmw_kms_helper_resource_finish(srf, out_fence);
  820. return ret;
  821. }
  822. /*
  823. * Screen Target CRTC dispatch table
  824. */
  825. static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
  826. .gamma_set = vmw_du_crtc_gamma_set,
  827. .destroy = vmw_stdu_crtc_destroy,
  828. .reset = vmw_du_crtc_reset,
  829. .atomic_duplicate_state = vmw_du_crtc_duplicate_state,
  830. .atomic_destroy_state = vmw_du_crtc_destroy_state,
  831. .set_config = vmw_kms_set_config,
  832. .page_flip = vmw_stdu_crtc_page_flip,
  833. };
  834. /******************************************************************************
  835. * Screen Target Display Unit Encoder Functions
  836. *****************************************************************************/
  837. /**
  838. * vmw_stdu_encoder_destroy - cleans up the STDU
  839. *
  840. * @encoder: used the get the containing STDU
  841. *
  842. * vmwgfx cleans up crtc/encoder/connector all at the same time so technically
  843. * this can be a no-op. Nevertheless, it doesn't hurt of have this in case
  844. * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't
  845. * get called.
  846. */
  847. static void vmw_stdu_encoder_destroy(struct drm_encoder *encoder)
  848. {
  849. vmw_stdu_destroy(vmw_encoder_to_stdu(encoder));
  850. }
  851. static const struct drm_encoder_funcs vmw_stdu_encoder_funcs = {
  852. .destroy = vmw_stdu_encoder_destroy,
  853. };
  854. /******************************************************************************
  855. * Screen Target Display Unit Connector Functions
  856. *****************************************************************************/
  857. /**
  858. * vmw_stdu_connector_destroy - cleans up the STDU
  859. *
  860. * @connector: used to get the containing STDU
  861. *
  862. * vmwgfx cleans up crtc/encoder/connector all at the same time so technically
  863. * this can be a no-op. Nevertheless, it doesn't hurt of have this in case
  864. * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't
  865. * get called.
  866. */
  867. static void vmw_stdu_connector_destroy(struct drm_connector *connector)
  868. {
  869. vmw_stdu_destroy(vmw_connector_to_stdu(connector));
  870. }
  871. static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
  872. .dpms = vmw_du_connector_dpms,
  873. .detect = vmw_du_connector_detect,
  874. .fill_modes = vmw_du_connector_fill_modes,
  875. .set_property = vmw_du_connector_set_property,
  876. .destroy = vmw_stdu_connector_destroy,
  877. .reset = vmw_du_connector_reset,
  878. .atomic_duplicate_state = vmw_du_connector_duplicate_state,
  879. .atomic_destroy_state = vmw_du_connector_destroy_state,
  880. .atomic_set_property = vmw_du_connector_atomic_set_property,
  881. .atomic_get_property = vmw_du_connector_atomic_get_property,
  882. };
  883. static const struct
  884. drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
  885. .best_encoder = drm_atomic_helper_best_encoder,
  886. };
  887. /******************************************************************************
  888. * Screen Target Display Plane Functions
  889. *****************************************************************************/
  890. /**
  891. * vmw_stdu_primary_plane_cleanup_fb - Unpins the display surface
  892. *
  893. * @plane: display plane
  894. * @old_state: Contains the FB to clean up
  895. *
  896. * Unpins the display surface
  897. *
  898. * Returns 0 on success
  899. */
  900. static void
  901. vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
  902. struct drm_plane_state *old_state)
  903. {
  904. struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
  905. if (vps->guest_map.virtual)
  906. ttm_bo_kunmap(&vps->guest_map);
  907. if (vps->host_map.virtual)
  908. ttm_bo_kunmap(&vps->host_map);
  909. if (vps->surf)
  910. WARN_ON(!vps->pinned);
  911. vmw_du_plane_cleanup_fb(plane, old_state);
  912. vps->content_fb_type = SAME_AS_DISPLAY;
  913. vps->cpp = 0;
  914. }
  915. /**
  916. * vmw_stdu_primary_plane_prepare_fb - Readies the display surface
  917. *
  918. * @plane: display plane
  919. * @new_state: info on the new plane state, including the FB
  920. *
  921. * This function allocates a new display surface if the content is
  922. * backed by a DMA. The display surface is pinned here, and it'll
  923. * be unpinned in .cleanup_fb()
  924. *
  925. * Returns 0 on success
  926. */
  927. static int
  928. vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
  929. struct drm_plane_state *new_state)
  930. {
  931. struct vmw_private *dev_priv = vmw_priv(plane->dev);
  932. struct drm_framebuffer *new_fb = new_state->fb;
  933. struct vmw_framebuffer *vfb;
  934. struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
  935. enum stdu_content_type new_content_type;
  936. struct vmw_framebuffer_surface *new_vfbs;
  937. struct drm_crtc *crtc = new_state->crtc;
  938. uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
  939. int ret;
  940. /* No FB to prepare */
  941. if (!new_fb) {
  942. if (vps->surf) {
  943. WARN_ON(vps->pinned != 0);
  944. vmw_surface_unreference(&vps->surf);
  945. }
  946. return 0;
  947. }
  948. vfb = vmw_framebuffer_to_vfb(new_fb);
  949. new_vfbs = (vfb->dmabuf) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
  950. if (new_vfbs && new_vfbs->surface->base_size.width == hdisplay &&
  951. new_vfbs->surface->base_size.height == vdisplay)
  952. new_content_type = SAME_AS_DISPLAY;
  953. else if (vfb->dmabuf)
  954. new_content_type = SEPARATE_DMA;
  955. else
  956. new_content_type = SEPARATE_SURFACE;
  957. if (new_content_type != SAME_AS_DISPLAY) {
  958. struct vmw_surface content_srf;
  959. struct drm_vmw_size display_base_size = {0};
  960. display_base_size.width = hdisplay;
  961. display_base_size.height = vdisplay;
  962. display_base_size.depth = 1;
  963. /*
  964. * If content buffer is a DMA buf, then we have to construct
  965. * surface info
  966. */
  967. if (new_content_type == SEPARATE_DMA) {
  968. switch (new_fb->format->cpp[0]*8) {
  969. case 32:
  970. content_srf.format = SVGA3D_X8R8G8B8;
  971. break;
  972. case 16:
  973. content_srf.format = SVGA3D_R5G6B5;
  974. break;
  975. case 8:
  976. content_srf.format = SVGA3D_P8;
  977. break;
  978. default:
  979. DRM_ERROR("Invalid format\n");
  980. return -EINVAL;
  981. }
  982. content_srf.flags = 0;
  983. content_srf.mip_levels[0] = 1;
  984. content_srf.multisample_count = 0;
  985. } else {
  986. content_srf = *new_vfbs->surface;
  987. }
  988. if (vps->surf) {
  989. struct drm_vmw_size cur_base_size = vps->surf->base_size;
  990. if (cur_base_size.width != display_base_size.width ||
  991. cur_base_size.height != display_base_size.height ||
  992. vps->surf->format != content_srf.format) {
  993. WARN_ON(vps->pinned != 0);
  994. vmw_surface_unreference(&vps->surf);
  995. }
  996. }
  997. if (!vps->surf) {
  998. ret = vmw_surface_gb_priv_define
  999. (crtc->dev,
  1000. /* Kernel visible only */
  1001. 0,
  1002. content_srf.flags,
  1003. content_srf.format,
  1004. true, /* a scanout buffer */
  1005. content_srf.mip_levels[0],
  1006. content_srf.multisample_count,
  1007. 0,
  1008. display_base_size,
  1009. &vps->surf);
  1010. if (ret != 0) {
  1011. DRM_ERROR("Couldn't allocate STDU surface.\n");
  1012. return ret;
  1013. }
  1014. }
  1015. } else {
  1016. /*
  1017. * prepare_fb and clean_fb should only take care of pinning
  1018. * and unpinning. References are tracked by state objects.
  1019. * The only time we add a reference in prepare_fb is if the
  1020. * state object doesn't have a reference to begin with
  1021. */
  1022. if (vps->surf) {
  1023. WARN_ON(vps->pinned != 0);
  1024. vmw_surface_unreference(&vps->surf);
  1025. }
  1026. vps->surf = vmw_surface_reference(new_vfbs->surface);
  1027. }
  1028. if (vps->surf) {
  1029. /* Pin new surface before flipping */
  1030. ret = vmw_resource_pin(&vps->surf->res, false);
  1031. if (ret)
  1032. goto out_srf_unref;
  1033. vps->pinned++;
  1034. }
  1035. vps->content_fb_type = new_content_type;
  1036. /*
  1037. * This should only happen if the DMA buf is too large to create a
  1038. * proxy surface for.
  1039. * If we are a 2D VM with a DMA buffer then we have to use CPU blit
  1040. * so cache these mappings
  1041. */
  1042. if (vps->content_fb_type == SEPARATE_DMA &&
  1043. !(dev_priv->capabilities & SVGA_CAP_3D)) {
  1044. struct vmw_framebuffer_dmabuf *new_vfbd;
  1045. new_vfbd = vmw_framebuffer_to_vfbd(new_fb);
  1046. ret = ttm_bo_reserve(&new_vfbd->buffer->base, false, false,
  1047. NULL);
  1048. if (ret)
  1049. goto out_srf_unpin;
  1050. ret = ttm_bo_kmap(&new_vfbd->buffer->base, 0,
  1051. new_vfbd->buffer->base.num_pages,
  1052. &vps->guest_map);
  1053. ttm_bo_unreserve(&new_vfbd->buffer->base);
  1054. if (ret) {
  1055. DRM_ERROR("Failed to map content buffer to CPU\n");
  1056. goto out_srf_unpin;
  1057. }
  1058. ret = ttm_bo_kmap(&vps->surf->res.backup->base, 0,
  1059. vps->surf->res.backup->base.num_pages,
  1060. &vps->host_map);
  1061. if (ret) {
  1062. DRM_ERROR("Failed to map display buffer to CPU\n");
  1063. ttm_bo_kunmap(&vps->guest_map);
  1064. goto out_srf_unpin;
  1065. }
  1066. vps->cpp = new_fb->pitches[0] / new_fb->width;
  1067. }
  1068. return 0;
  1069. out_srf_unpin:
  1070. vmw_resource_unpin(&vps->surf->res);
  1071. vps->pinned--;
  1072. out_srf_unref:
  1073. vmw_surface_unreference(&vps->surf);
  1074. return ret;
  1075. }
  1076. /**
  1077. * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
  1078. *
  1079. * @plane: display plane
  1080. * @old_state: Only used to get crtc info
  1081. *
  1082. * Formally update stdu->display_srf to the new plane, and bind the new
  1083. * plane STDU. This function is called during the commit phase when
  1084. * all the preparation have been done and all the configurations have
  1085. * been checked.
  1086. */
  1087. static void
  1088. vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
  1089. struct drm_plane_state *old_state)
  1090. {
  1091. struct vmw_private *dev_priv;
  1092. struct vmw_screen_target_display_unit *stdu;
  1093. struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state);
  1094. struct drm_crtc *crtc = plane->state->crtc ?: old_state->crtc;
  1095. int ret;
  1096. stdu = vmw_crtc_to_stdu(crtc);
  1097. dev_priv = vmw_priv(crtc->dev);
  1098. stdu->display_srf = vps->surf;
  1099. stdu->content_fb_type = vps->content_fb_type;
  1100. stdu->cpp = vps->cpp;
  1101. memcpy(&stdu->guest_map, &vps->guest_map, sizeof(vps->guest_map));
  1102. memcpy(&stdu->host_map, &vps->host_map, sizeof(vps->host_map));
  1103. if (!stdu->defined)
  1104. return;
  1105. if (plane->state->fb)
  1106. ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
  1107. else
  1108. ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
  1109. /*
  1110. * We cannot really fail this function, so if we do, then output an
  1111. * error and quit
  1112. */
  1113. if (ret)
  1114. DRM_ERROR("Failed to bind surface to STDU.\n");
  1115. else
  1116. crtc->primary->fb = plane->state->fb;
  1117. }
  1118. static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
  1119. .update_plane = drm_atomic_helper_update_plane,
  1120. .disable_plane = drm_atomic_helper_disable_plane,
  1121. .destroy = vmw_du_primary_plane_destroy,
  1122. .reset = vmw_du_plane_reset,
  1123. .atomic_duplicate_state = vmw_du_plane_duplicate_state,
  1124. .atomic_destroy_state = vmw_du_plane_destroy_state,
  1125. };
  1126. static const struct drm_plane_funcs vmw_stdu_cursor_funcs = {
  1127. .update_plane = drm_atomic_helper_update_plane,
  1128. .disable_plane = drm_atomic_helper_disable_plane,
  1129. .destroy = vmw_du_cursor_plane_destroy,
  1130. .reset = vmw_du_plane_reset,
  1131. .atomic_duplicate_state = vmw_du_plane_duplicate_state,
  1132. .atomic_destroy_state = vmw_du_plane_destroy_state,
  1133. };
  1134. /*
  1135. * Atomic Helpers
  1136. */
  1137. static const struct
  1138. drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
  1139. .atomic_check = vmw_du_cursor_plane_atomic_check,
  1140. .atomic_update = vmw_du_cursor_plane_atomic_update,
  1141. .prepare_fb = vmw_du_cursor_plane_prepare_fb,
  1142. .cleanup_fb = vmw_du_plane_cleanup_fb,
  1143. };
  1144. static const struct
  1145. drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = {
  1146. .atomic_check = vmw_du_primary_plane_atomic_check,
  1147. .atomic_update = vmw_stdu_primary_plane_atomic_update,
  1148. .prepare_fb = vmw_stdu_primary_plane_prepare_fb,
  1149. .cleanup_fb = vmw_stdu_primary_plane_cleanup_fb,
  1150. };
  1151. static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
  1152. .prepare = vmw_stdu_crtc_helper_prepare,
  1153. .commit = vmw_stdu_crtc_helper_commit,
  1154. .disable = vmw_stdu_crtc_helper_disable,
  1155. .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb,
  1156. .atomic_check = vmw_du_crtc_atomic_check,
  1157. .atomic_begin = vmw_du_crtc_atomic_begin,
  1158. .atomic_flush = vmw_du_crtc_atomic_flush,
  1159. };
  1160. /**
  1161. * vmw_stdu_init - Sets up a Screen Target Display Unit
  1162. *
  1163. * @dev_priv: VMW DRM device
  1164. * @unit: unit number range from 0 to VMWGFX_NUM_DISPLAY_UNITS
  1165. *
  1166. * This function is called once per CRTC, and allocates one Screen Target
  1167. * display unit to represent that CRTC. Since the SVGA device does not separate
  1168. * out encoder and connector, they are represented as part of the STDU as well.
  1169. */
  1170. static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
  1171. {
  1172. struct vmw_screen_target_display_unit *stdu;
  1173. struct drm_device *dev = dev_priv->dev;
  1174. struct drm_connector *connector;
  1175. struct drm_encoder *encoder;
  1176. struct drm_plane *primary, *cursor;
  1177. struct drm_crtc *crtc;
  1178. int ret;
  1179. stdu = kzalloc(sizeof(*stdu), GFP_KERNEL);
  1180. if (!stdu)
  1181. return -ENOMEM;
  1182. stdu->base.unit = unit;
  1183. crtc = &stdu->base.crtc;
  1184. encoder = &stdu->base.encoder;
  1185. connector = &stdu->base.connector;
  1186. primary = &stdu->base.primary;
  1187. cursor = &stdu->base.cursor;
  1188. stdu->base.pref_active = (unit == 0);
  1189. stdu->base.pref_width = dev_priv->initial_width;
  1190. stdu->base.pref_height = dev_priv->initial_height;
  1191. /*
  1192. * Remove this after enabling atomic because property values can
  1193. * only exist in a state object
  1194. */
  1195. stdu->base.is_implicit = false;
  1196. /* Initialize primary plane */
  1197. vmw_du_plane_reset(primary);
  1198. ret = drm_universal_plane_init(dev, primary,
  1199. 0, &vmw_stdu_plane_funcs,
  1200. vmw_primary_plane_formats,
  1201. ARRAY_SIZE(vmw_primary_plane_formats),
  1202. DRM_PLANE_TYPE_PRIMARY, NULL);
  1203. if (ret) {
  1204. DRM_ERROR("Failed to initialize primary plane");
  1205. goto err_free;
  1206. }
  1207. drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
  1208. /* Initialize cursor plane */
  1209. vmw_du_plane_reset(cursor);
  1210. ret = drm_universal_plane_init(dev, cursor,
  1211. 0, &vmw_stdu_cursor_funcs,
  1212. vmw_cursor_plane_formats,
  1213. ARRAY_SIZE(vmw_cursor_plane_formats),
  1214. DRM_PLANE_TYPE_CURSOR, NULL);
  1215. if (ret) {
  1216. DRM_ERROR("Failed to initialize cursor plane");
  1217. drm_plane_cleanup(&stdu->base.primary);
  1218. goto err_free;
  1219. }
  1220. drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs);
  1221. vmw_du_connector_reset(connector);
  1222. ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
  1223. DRM_MODE_CONNECTOR_VIRTUAL);
  1224. if (ret) {
  1225. DRM_ERROR("Failed to initialize connector\n");
  1226. goto err_free;
  1227. }
  1228. drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs);
  1229. connector->status = vmw_du_connector_detect(connector, false);
  1230. vmw_connector_state_to_vcs(connector->state)->is_implicit = false;
  1231. ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
  1232. DRM_MODE_ENCODER_VIRTUAL, NULL);
  1233. if (ret) {
  1234. DRM_ERROR("Failed to initialize encoder\n");
  1235. goto err_free_connector;
  1236. }
  1237. (void) drm_mode_connector_attach_encoder(connector, encoder);
  1238. encoder->possible_crtcs = (1 << unit);
  1239. encoder->possible_clones = 0;
  1240. ret = drm_connector_register(connector);
  1241. if (ret) {
  1242. DRM_ERROR("Failed to register connector\n");
  1243. goto err_free_encoder;
  1244. }
  1245. vmw_du_crtc_reset(crtc);
  1246. ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary,
  1247. &stdu->base.cursor,
  1248. &vmw_stdu_crtc_funcs, NULL);
  1249. if (ret) {
  1250. DRM_ERROR("Failed to initialize CRTC\n");
  1251. goto err_free_unregister;
  1252. }
  1253. drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs);
  1254. drm_mode_crtc_set_gamma_size(crtc, 256);
  1255. drm_object_attach_property(&connector->base,
  1256. dev_priv->hotplug_mode_update_property, 1);
  1257. drm_object_attach_property(&connector->base,
  1258. dev->mode_config.suggested_x_property, 0);
  1259. drm_object_attach_property(&connector->base,
  1260. dev->mode_config.suggested_y_property, 0);
  1261. if (dev_priv->implicit_placement_property)
  1262. drm_object_attach_property
  1263. (&connector->base,
  1264. dev_priv->implicit_placement_property,
  1265. stdu->base.is_implicit);
  1266. return 0;
  1267. err_free_unregister:
  1268. drm_connector_unregister(connector);
  1269. err_free_encoder:
  1270. drm_encoder_cleanup(encoder);
  1271. err_free_connector:
  1272. drm_connector_cleanup(connector);
  1273. err_free:
  1274. kfree(stdu);
  1275. return ret;
  1276. }
  1277. /**
  1278. * vmw_stdu_destroy - Cleans up a vmw_screen_target_display_unit
  1279. *
  1280. * @stdu: Screen Target Display Unit to be destroyed
  1281. *
  1282. * Clean up after vmw_stdu_init
  1283. */
  1284. static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu)
  1285. {
  1286. vmw_du_cleanup(&stdu->base);
  1287. kfree(stdu);
  1288. }
  1289. /******************************************************************************
  1290. * Screen Target Display KMS Functions
  1291. *
  1292. * These functions are called by the common KMS code in vmwgfx_kms.c
  1293. *****************************************************************************/
  1294. /**
  1295. * vmw_kms_stdu_init_display - Initializes a Screen Target based display
  1296. *
  1297. * @dev_priv: VMW DRM device
  1298. *
  1299. * This function initialize a Screen Target based display device. It checks
  1300. * the capability bits to make sure the underlying hardware can support
  1301. * screen targets, and then creates the maximum number of CRTCs, a.k.a Display
  1302. * Units, as supported by the display hardware.
  1303. *
  1304. * RETURNS:
  1305. * 0 on success, error code otherwise
  1306. */
  1307. int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
  1308. {
  1309. struct drm_device *dev = dev_priv->dev;
  1310. int i, ret;
  1311. /* Do nothing if Screen Target support is turned off */
  1312. if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE)
  1313. return -ENOSYS;
  1314. if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
  1315. return -ENOSYS;
  1316. ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS);
  1317. if (unlikely(ret != 0))
  1318. return ret;
  1319. dev_priv->active_display_unit = vmw_du_screen_target;
  1320. if (dev_priv->capabilities & SVGA_CAP_3D) {
  1321. /*
  1322. * For 3D VMs, display (scanout) buffer size is the smaller of
  1323. * max texture and max STDU
  1324. */
  1325. uint32_t max_width, max_height;
  1326. max_width = min(dev_priv->texture_max_width,
  1327. dev_priv->stdu_max_width);
  1328. max_height = min(dev_priv->texture_max_height,
  1329. dev_priv->stdu_max_height);
  1330. dev->mode_config.max_width = max_width;
  1331. dev->mode_config.max_height = max_height;
  1332. } else {
  1333. /*
  1334. * Given various display aspect ratios, there's no way to
  1335. * estimate these using prim_bb_mem. So just set these to
  1336. * something arbitrarily large and we will reject any layout
  1337. * that doesn't fit prim_bb_mem later
  1338. */
  1339. dev->mode_config.max_width = 16384;
  1340. dev->mode_config.max_height = 16384;
  1341. }
  1342. vmw_kms_create_implicit_placement_property(dev_priv, false);
  1343. for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
  1344. ret = vmw_stdu_init(dev_priv, i);
  1345. if (unlikely(ret != 0)) {
  1346. DRM_ERROR("Failed to initialize STDU %d", i);
  1347. goto err_vblank_cleanup;
  1348. }
  1349. }
  1350. DRM_INFO("Screen Target Display device initialized\n");
  1351. return 0;
  1352. err_vblank_cleanup:
  1353. drm_vblank_cleanup(dev);
  1354. return ret;
  1355. }
  1356. /**
  1357. * vmw_kms_stdu_close_display - Cleans up after vmw_kms_stdu_init_display
  1358. *
  1359. * @dev_priv: VMW DRM device
  1360. *
  1361. * Frees up any resources allocated by vmw_kms_stdu_init_display
  1362. *
  1363. * RETURNS:
  1364. * 0 on success
  1365. */
  1366. int vmw_kms_stdu_close_display(struct vmw_private *dev_priv)
  1367. {
  1368. struct drm_device *dev = dev_priv->dev;
  1369. drm_vblank_cleanup(dev);
  1370. return 0;
  1371. }