18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/****************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * COPYRIGHT (C) 2014-2015 VMware, Inc., Palo Alto, CA., USA 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 78c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the 88c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 98c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 108c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 118c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 128c2ecf20Sopenharmony_ci * the following conditions: 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the 158c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 168c2ecf20Sopenharmony_ci * of the Software. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 198c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 208c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 218c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 228c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 238c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 248c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci ******************************************************************************/ 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#include <drm/drm_atomic.h> 298c2ecf20Sopenharmony_ci#include <drm/drm_atomic_helper.h> 308c2ecf20Sopenharmony_ci#include <drm/drm_damage_helper.h> 318c2ecf20Sopenharmony_ci#include <drm/drm_fourcc.h> 328c2ecf20Sopenharmony_ci#include <drm/drm_plane_helper.h> 338c2ecf20Sopenharmony_ci#include <drm/drm_vblank.h> 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#include "vmwgfx_kms.h" 368c2ecf20Sopenharmony_ci#include "device_include/svga3d_surfacedefs.h" 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define vmw_crtc_to_stdu(x) \ 398c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_target_display_unit, base.crtc) 408c2ecf20Sopenharmony_ci#define vmw_encoder_to_stdu(x) \ 418c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_target_display_unit, base.encoder) 428c2ecf20Sopenharmony_ci#define vmw_connector_to_stdu(x) \ 438c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_target_display_unit, base.connector) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cienum stdu_content_type { 488c2ecf20Sopenharmony_ci SAME_AS_DISPLAY = 0, 498c2ecf20Sopenharmony_ci SEPARATE_SURFACE, 508c2ecf20Sopenharmony_ci SEPARATE_BO 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * struct vmw_stdu_dirty - closure structure for the update functions 558c2ecf20Sopenharmony_ci * 568c2ecf20Sopenharmony_ci * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). 578c2ecf20Sopenharmony_ci * @transfer: Transfer direction for DMA command. 588c2ecf20Sopenharmony_ci * @left: Left side of bounding box. 598c2ecf20Sopenharmony_ci * @right: Right side of bounding box. 608c2ecf20Sopenharmony_ci * @top: Top side of bounding box. 618c2ecf20Sopenharmony_ci * @bottom: Bottom side of bounding box. 628c2ecf20Sopenharmony_ci * @fb_left: Left side of the framebuffer/content bounding box 638c2ecf20Sopenharmony_ci * @fb_top: Top of the framebuffer/content bounding box 648c2ecf20Sopenharmony_ci * @buf: buffer object when DMA-ing between buffer and screen targets. 658c2ecf20Sopenharmony_ci * @sid: Surface ID when copying between surface and screen targets. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistruct vmw_stdu_dirty { 688c2ecf20Sopenharmony_ci struct vmw_kms_dirty base; 698c2ecf20Sopenharmony_ci SVGA3dTransferType transfer; 708c2ecf20Sopenharmony_ci s32 left, right, top, bottom; 718c2ecf20Sopenharmony_ci s32 fb_left, fb_top; 728c2ecf20Sopenharmony_ci u32 pitch; 738c2ecf20Sopenharmony_ci union { 748c2ecf20Sopenharmony_ci struct vmw_buffer_object *buf; 758c2ecf20Sopenharmony_ci u32 sid; 768c2ecf20Sopenharmony_ci }; 778c2ecf20Sopenharmony_ci}; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* 808c2ecf20Sopenharmony_ci * SVGA commands that are used by this code. Please see the device headers 818c2ecf20Sopenharmony_ci * for explanation. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_cistruct vmw_stdu_update { 848c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 858c2ecf20Sopenharmony_ci SVGA3dCmdUpdateGBScreenTarget body; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistruct vmw_stdu_dma { 898c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 908c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMA body; 918c2ecf20Sopenharmony_ci}; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistruct vmw_stdu_surface_copy { 948c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 958c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceCopy body; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistruct vmw_stdu_update_gb_image { 998c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 1008c2ecf20Sopenharmony_ci SVGA3dCmdUpdateGBImage body; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * struct vmw_screen_target_display_unit 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * @base: VMW specific DU structure 1078c2ecf20Sopenharmony_ci * @display_srf: surface to be displayed. The dimension of this will always 1088c2ecf20Sopenharmony_ci * match the display mode. If the display mode matches 1098c2ecf20Sopenharmony_ci * content_vfbs dimensions, then this is a pointer into the 1108c2ecf20Sopenharmony_ci * corresponding field in content_vfbs. If not, then this 1118c2ecf20Sopenharmony_ci * is a separate buffer to which content_vfbs will blit to. 1128c2ecf20Sopenharmony_ci * @content_type: content_fb type 1138c2ecf20Sopenharmony_ci * @defined: true if the current display unit has been initialized 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_cistruct vmw_screen_target_display_unit { 1168c2ecf20Sopenharmony_ci struct vmw_display_unit base; 1178c2ecf20Sopenharmony_ci struct vmw_surface *display_srf; 1188c2ecf20Sopenharmony_ci enum stdu_content_type content_fb_type; 1198c2ecf20Sopenharmony_ci s32 display_width, display_height; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci bool defined; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* For CPU Blit */ 1248c2ecf20Sopenharmony_ci unsigned int cpp; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/****************************************************************************** 1348c2ecf20Sopenharmony_ci * Screen Target Display Unit CRTC Functions 1358c2ecf20Sopenharmony_ci *****************************************************************************/ 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/** 1398c2ecf20Sopenharmony_ci * vmw_stdu_crtc_destroy - cleans up the STDU 1408c2ecf20Sopenharmony_ci * 1418c2ecf20Sopenharmony_ci * @crtc: used to get a reference to the containing STDU 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_cistatic void vmw_stdu_crtc_destroy(struct drm_crtc *crtc) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci vmw_stdu_destroy(vmw_crtc_to_stdu(crtc)); 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci/** 1498c2ecf20Sopenharmony_ci * vmw_stdu_define_st - Defines a Screen Target 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 1528c2ecf20Sopenharmony_ci * @stdu: display unit to create a Screen Target for 1538c2ecf20Sopenharmony_ci * @mode: The mode to set. 1548c2ecf20Sopenharmony_ci * @crtc_x: X coordinate of screen target relative to framebuffer origin. 1558c2ecf20Sopenharmony_ci * @crtc_y: Y coordinate of screen target relative to framebuffer origin. 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * Creates a STDU that we can used later. This function is called whenever the 1588c2ecf20Sopenharmony_ci * framebuffer size changes. 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * RETURNs: 1618c2ecf20Sopenharmony_ci * 0 on success, error code on failure 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic int vmw_stdu_define_st(struct vmw_private *dev_priv, 1648c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu, 1658c2ecf20Sopenharmony_ci struct drm_display_mode *mode, 1668c2ecf20Sopenharmony_ci int crtc_x, int crtc_y) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct { 1698c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 1708c2ecf20Sopenharmony_ci SVGA3dCmdDefineGBScreenTarget body; 1718c2ecf20Sopenharmony_ci } *cmd; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 1748c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 1758c2ecf20Sopenharmony_ci return -ENOMEM; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET; 1788c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci cmd->body.stid = stdu->base.unit; 1818c2ecf20Sopenharmony_ci cmd->body.width = mode->hdisplay; 1828c2ecf20Sopenharmony_ci cmd->body.height = mode->vdisplay; 1838c2ecf20Sopenharmony_ci cmd->body.flags = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0; 1848c2ecf20Sopenharmony_ci cmd->body.dpi = 0; 1858c2ecf20Sopenharmony_ci cmd->body.xRoot = crtc_x; 1868c2ecf20Sopenharmony_ci cmd->body.yRoot = crtc_y; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci stdu->base.set_gui_x = cmd->body.xRoot; 1898c2ecf20Sopenharmony_ci stdu->base.set_gui_y = cmd->body.yRoot; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci stdu->defined = true; 1948c2ecf20Sopenharmony_ci stdu->display_width = mode->hdisplay; 1958c2ecf20Sopenharmony_ci stdu->display_height = mode->vdisplay; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/** 2038c2ecf20Sopenharmony_ci * vmw_stdu_bind_st - Binds a surface to a Screen Target 2048c2ecf20Sopenharmony_ci * 2058c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 2068c2ecf20Sopenharmony_ci * @stdu: display unit affected 2078c2ecf20Sopenharmony_ci * @res: Buffer to bind to the screen target. Set to NULL to blank screen. 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * Binding a surface to a Screen Target the same as flipping 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_cistatic int vmw_stdu_bind_st(struct vmw_private *dev_priv, 2128c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu, 2138c2ecf20Sopenharmony_ci const struct vmw_resource *res) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci SVGA3dSurfaceImageId image; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci struct { 2188c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 2198c2ecf20Sopenharmony_ci SVGA3dCmdBindGBScreenTarget body; 2208c2ecf20Sopenharmony_ci } *cmd; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!stdu->defined) { 2248c2ecf20Sopenharmony_ci DRM_ERROR("No screen target defined\n"); 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Set up image using information in vfb */ 2298c2ecf20Sopenharmony_ci memset(&image, 0, sizeof(image)); 2308c2ecf20Sopenharmony_ci image.sid = res ? res->id : SVGA3D_INVALID_ID; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 2338c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 2348c2ecf20Sopenharmony_ci return -ENOMEM; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_BIND_GB_SCREENTARGET; 2378c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci cmd->body.stid = stdu->base.unit; 2408c2ecf20Sopenharmony_ci cmd->body.image = image; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/** 2488c2ecf20Sopenharmony_ci * vmw_stdu_populate_update - populate an UPDATE_GB_SCREENTARGET command with a 2498c2ecf20Sopenharmony_ci * bounding box. 2508c2ecf20Sopenharmony_ci * 2518c2ecf20Sopenharmony_ci * @cmd: Pointer to command stream. 2528c2ecf20Sopenharmony_ci * @unit: Screen target unit. 2538c2ecf20Sopenharmony_ci * @left: Left side of bounding box. 2548c2ecf20Sopenharmony_ci * @right: Right side of bounding box. 2558c2ecf20Sopenharmony_ci * @top: Top side of bounding box. 2568c2ecf20Sopenharmony_ci * @bottom: Bottom side of bounding box. 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_cistatic void vmw_stdu_populate_update(void *cmd, int unit, 2598c2ecf20Sopenharmony_ci s32 left, s32 right, s32 top, s32 bottom) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct vmw_stdu_update *update = cmd; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci update->header.id = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET; 2648c2ecf20Sopenharmony_ci update->header.size = sizeof(update->body); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci update->body.stid = unit; 2678c2ecf20Sopenharmony_ci update->body.rect.x = left; 2688c2ecf20Sopenharmony_ci update->body.rect.y = top; 2698c2ecf20Sopenharmony_ci update->body.rect.w = right - left; 2708c2ecf20Sopenharmony_ci update->body.rect.h = bottom - top; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/** 2748c2ecf20Sopenharmony_ci * vmw_stdu_update_st - Full update of a Screen Target 2758c2ecf20Sopenharmony_ci * 2768c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 2778c2ecf20Sopenharmony_ci * @stdu: display unit affected 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * This function needs to be called whenever the content of a screen 2808c2ecf20Sopenharmony_ci * target has changed completely. Typically as a result of a backing 2818c2ecf20Sopenharmony_ci * surface change. 2828c2ecf20Sopenharmony_ci * 2838c2ecf20Sopenharmony_ci * RETURNS: 2848c2ecf20Sopenharmony_ci * 0 on success, error code on failure 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cistatic int vmw_stdu_update_st(struct vmw_private *dev_priv, 2878c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci struct vmw_stdu_update *cmd; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!stdu->defined) { 2928c2ecf20Sopenharmony_ci DRM_ERROR("No screen target defined"); 2938c2ecf20Sopenharmony_ci return -EINVAL; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 2978c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 2988c2ecf20Sopenharmony_ci return -ENOMEM; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci vmw_stdu_populate_update(cmd, stdu->base.unit, 3018c2ecf20Sopenharmony_ci 0, stdu->display_width, 3028c2ecf20Sopenharmony_ci 0, stdu->display_height); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * vmw_stdu_destroy_st - Destroy a Screen Target 3138c2ecf20Sopenharmony_ci * 3148c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 3158c2ecf20Sopenharmony_ci * @stdu: display unit to destroy 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_cistatic int vmw_stdu_destroy_st(struct vmw_private *dev_priv, 3188c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci int ret; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci struct { 3238c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 3248c2ecf20Sopenharmony_ci SVGA3dCmdDestroyGBScreenTarget body; 3258c2ecf20Sopenharmony_ci } *cmd; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* Nothing to do if not successfully defined */ 3298c2ecf20Sopenharmony_ci if (unlikely(!stdu->defined)) 3308c2ecf20Sopenharmony_ci return 0; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 3338c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 3348c2ecf20Sopenharmony_ci return -ENOMEM; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET; 3378c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci cmd->body.stid = stdu->base.unit; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* Force sync */ 3448c2ecf20Sopenharmony_ci ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); 3458c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 3468c2ecf20Sopenharmony_ci DRM_ERROR("Failed to sync with HW"); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci stdu->defined = false; 3498c2ecf20Sopenharmony_ci stdu->display_width = 0; 3508c2ecf20Sopenharmony_ci stdu->display_height = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return ret; 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/** 3578c2ecf20Sopenharmony_ci * vmw_stdu_crtc_mode_set_nofb - Updates screen target size 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * @crtc: CRTC associated with the screen target 3608c2ecf20Sopenharmony_ci * 3618c2ecf20Sopenharmony_ci * This function defines/destroys a screen target 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_cistatic void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 3678c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 3688c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 3698c2ecf20Sopenharmony_ci struct vmw_connector_state *vmw_conn_state; 3708c2ecf20Sopenharmony_ci int x, y, ret; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci stdu = vmw_crtc_to_stdu(crtc); 3738c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 3748c2ecf20Sopenharmony_ci conn_state = stdu->base.connector.state; 3758c2ecf20Sopenharmony_ci vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (stdu->defined) { 3788c2ecf20Sopenharmony_ci ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); 3798c2ecf20Sopenharmony_ci if (ret) 3808c2ecf20Sopenharmony_ci DRM_ERROR("Failed to blank CRTC\n"); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci (void) vmw_stdu_update_st(dev_priv, stdu); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci ret = vmw_stdu_destroy_st(dev_priv, stdu); 3858c2ecf20Sopenharmony_ci if (ret) 3868c2ecf20Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Target\n"); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci stdu->content_fb_type = SAME_AS_DISPLAY; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci if (!crtc->state->enable) 3928c2ecf20Sopenharmony_ci return; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci x = vmw_conn_state->gui_x; 3958c2ecf20Sopenharmony_ci y = vmw_conn_state->gui_y; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci vmw_svga_enable(dev_priv); 3988c2ecf20Sopenharmony_ci ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (ret) 4018c2ecf20Sopenharmony_ci DRM_ERROR("Failed to define Screen Target of size %dx%d\n", 4028c2ecf20Sopenharmony_ci crtc->x, crtc->y); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void vmw_stdu_crtc_helper_prepare(struct drm_crtc *crtc) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci} 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic void vmw_stdu_crtc_atomic_enable(struct drm_crtc *crtc, 4118c2ecf20Sopenharmony_ci struct drm_crtc_state *old_state) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc, 4168c2ecf20Sopenharmony_ci struct drm_crtc_state *old_state) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 4198c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 4208c2ecf20Sopenharmony_ci int ret; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (!crtc) { 4248c2ecf20Sopenharmony_ci DRM_ERROR("CRTC is NULL\n"); 4258c2ecf20Sopenharmony_ci return; 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci stdu = vmw_crtc_to_stdu(crtc); 4298c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (stdu->defined) { 4328c2ecf20Sopenharmony_ci ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); 4338c2ecf20Sopenharmony_ci if (ret) 4348c2ecf20Sopenharmony_ci DRM_ERROR("Failed to blank CRTC\n"); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci (void) vmw_stdu_update_st(dev_priv, stdu); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci ret = vmw_stdu_destroy_st(dev_priv, stdu); 4398c2ecf20Sopenharmony_ci if (ret) 4408c2ecf20Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Target\n"); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci stdu->content_fb_type = SAME_AS_DISPLAY; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/** 4478c2ecf20Sopenharmony_ci * vmw_stdu_bo_clip - Callback to encode a suface DMA command cliprect 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * @dirty: The closure structure. 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * Encodes a surface DMA command cliprect and updates the bounding box 4528c2ecf20Sopenharmony_ci * for the DMA. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_cistatic void vmw_stdu_bo_clip(struct vmw_kms_dirty *dirty) 4558c2ecf20Sopenharmony_ci{ 4568c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *ddirty = 4578c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 4588c2ecf20Sopenharmony_ci struct vmw_stdu_dma *cmd = dirty->cmd; 4598c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci blit += dirty->num_hits; 4628c2ecf20Sopenharmony_ci blit->srcx = dirty->fb_x; 4638c2ecf20Sopenharmony_ci blit->srcy = dirty->fb_y; 4648c2ecf20Sopenharmony_ci blit->x = dirty->unit_x1; 4658c2ecf20Sopenharmony_ci blit->y = dirty->unit_y1; 4668c2ecf20Sopenharmony_ci blit->d = 1; 4678c2ecf20Sopenharmony_ci blit->w = dirty->unit_x2 - dirty->unit_x1; 4688c2ecf20Sopenharmony_ci blit->h = dirty->unit_y2 - dirty->unit_y1; 4698c2ecf20Sopenharmony_ci dirty->num_hits++; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) 4728c2ecf20Sopenharmony_ci return; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Destination bounding box */ 4758c2ecf20Sopenharmony_ci ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1); 4768c2ecf20Sopenharmony_ci ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1); 4778c2ecf20Sopenharmony_ci ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2); 4788c2ecf20Sopenharmony_ci ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2); 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci/** 4828c2ecf20Sopenharmony_ci * vmw_stdu_bo_fifo_commit - Callback to fill in and submit a DMA command. 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * @dirty: The closure structure. 4858c2ecf20Sopenharmony_ci * 4868c2ecf20Sopenharmony_ci * Fills in the missing fields in a DMA command, and optionally encodes 4878c2ecf20Sopenharmony_ci * a screen target update command, depending on transfer direction. 4888c2ecf20Sopenharmony_ci */ 4898c2ecf20Sopenharmony_cistatic void vmw_stdu_bo_fifo_commit(struct vmw_kms_dirty *dirty) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *ddirty = 4928c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 4938c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu = 4948c2ecf20Sopenharmony_ci container_of(dirty->unit, typeof(*stdu), base); 4958c2ecf20Sopenharmony_ci struct vmw_stdu_dma *cmd = dirty->cmd; 4968c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; 4978c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix *suffix = 4988c2ecf20Sopenharmony_ci (SVGA3dCmdSurfaceDMASuffix *) &blit[dirty->num_hits]; 4998c2ecf20Sopenharmony_ci size_t blit_size = sizeof(*blit) * dirty->num_hits + sizeof(*suffix); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!dirty->num_hits) { 5028c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 0); 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_DMA; 5078c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body) + blit_size; 5088c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(&ddirty->buf->base, &cmd->body.guest.ptr); 5098c2ecf20Sopenharmony_ci cmd->body.guest.pitch = ddirty->pitch; 5108c2ecf20Sopenharmony_ci cmd->body.host.sid = stdu->display_srf->res.id; 5118c2ecf20Sopenharmony_ci cmd->body.host.face = 0; 5128c2ecf20Sopenharmony_ci cmd->body.host.mipmap = 0; 5138c2ecf20Sopenharmony_ci cmd->body.transfer = ddirty->transfer; 5148c2ecf20Sopenharmony_ci suffix->suffixSize = sizeof(*suffix); 5158c2ecf20Sopenharmony_ci suffix->maximumOffset = ddirty->buf->base.num_pages * PAGE_SIZE; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM) { 5188c2ecf20Sopenharmony_ci blit_size += sizeof(struct vmw_stdu_update); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci vmw_stdu_populate_update(&suffix[1], stdu->base.unit, 5218c2ecf20Sopenharmony_ci ddirty->left, ddirty->right, 5228c2ecf20Sopenharmony_ci ddirty->top, ddirty->bottom); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, sizeof(*cmd) + blit_size); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci stdu->display_srf->res.res_dirty = true; 5288c2ecf20Sopenharmony_ci ddirty->left = ddirty->top = S32_MAX; 5298c2ecf20Sopenharmony_ci ddirty->right = ddirty->bottom = S32_MIN; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/** 5348c2ecf20Sopenharmony_ci * vmw_stdu_bo_cpu_clip - Callback to encode a CPU blit 5358c2ecf20Sopenharmony_ci * 5368c2ecf20Sopenharmony_ci * @dirty: The closure structure. 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * This function calculates the bounding box for all the incoming clips. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_cistatic void vmw_stdu_bo_cpu_clip(struct vmw_kms_dirty *dirty) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *ddirty = 5438c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci dirty->num_hits = 1; 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* Calculate destination bounding box */ 5488c2ecf20Sopenharmony_ci ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1); 5498c2ecf20Sopenharmony_ci ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1); 5508c2ecf20Sopenharmony_ci ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2); 5518c2ecf20Sopenharmony_ci ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci /* 5548c2ecf20Sopenharmony_ci * Calculate content bounding box. We only need the top-left 5558c2ecf20Sopenharmony_ci * coordinate because width and height will be the same as the 5568c2ecf20Sopenharmony_ci * destination bounding box above 5578c2ecf20Sopenharmony_ci */ 5588c2ecf20Sopenharmony_ci ddirty->fb_left = min_t(s32, ddirty->fb_left, dirty->fb_x); 5598c2ecf20Sopenharmony_ci ddirty->fb_top = min_t(s32, ddirty->fb_top, dirty->fb_y); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci/** 5648c2ecf20Sopenharmony_ci * vmw_stdu_bo_cpu_commit - Callback to do a CPU blit from buffer object 5658c2ecf20Sopenharmony_ci * 5668c2ecf20Sopenharmony_ci * @dirty: The closure structure. 5678c2ecf20Sopenharmony_ci * 5688c2ecf20Sopenharmony_ci * For the special case when we cannot create a proxy surface in a 5698c2ecf20Sopenharmony_ci * 2D VM, we have to do a CPU blit ourselves. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_cistatic void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty) 5728c2ecf20Sopenharmony_ci{ 5738c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *ddirty = 5748c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 5758c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu = 5768c2ecf20Sopenharmony_ci container_of(dirty->unit, typeof(*stdu), base); 5778c2ecf20Sopenharmony_ci s32 width, height; 5788c2ecf20Sopenharmony_ci s32 src_pitch, dst_pitch; 5798c2ecf20Sopenharmony_ci struct ttm_buffer_object *src_bo, *dst_bo; 5808c2ecf20Sopenharmony_ci u32 src_offset, dst_offset; 5818c2ecf20Sopenharmony_ci struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci if (!dirty->num_hits) 5848c2ecf20Sopenharmony_ci return; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci width = ddirty->right - ddirty->left; 5878c2ecf20Sopenharmony_ci height = ddirty->bottom - ddirty->top; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci if (width == 0 || height == 0) 5908c2ecf20Sopenharmony_ci return; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* Assume we are blitting from Guest (bo) to Host (display_srf) */ 5938c2ecf20Sopenharmony_ci dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; 5948c2ecf20Sopenharmony_ci dst_bo = &stdu->display_srf->res.backup->base; 5958c2ecf20Sopenharmony_ci dst_offset = ddirty->top * dst_pitch + ddirty->left * stdu->cpp; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci src_pitch = ddirty->pitch; 5988c2ecf20Sopenharmony_ci src_bo = &ddirty->buf->base; 5998c2ecf20Sopenharmony_ci src_offset = ddirty->fb_top * src_pitch + ddirty->fb_left * stdu->cpp; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Swap src and dst if the assumption was wrong. */ 6028c2ecf20Sopenharmony_ci if (ddirty->transfer != SVGA3D_WRITE_HOST_VRAM) { 6038c2ecf20Sopenharmony_ci swap(dst_pitch, src_pitch); 6048c2ecf20Sopenharmony_ci swap(dst_bo, src_bo); 6058c2ecf20Sopenharmony_ci swap(src_offset, dst_offset); 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, 6098c2ecf20Sopenharmony_ci src_bo, src_offset, src_pitch, 6108c2ecf20Sopenharmony_ci width * stdu->cpp, height, &diff); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (ddirty->transfer == SVGA3D_WRITE_HOST_VRAM && 6138c2ecf20Sopenharmony_ci drm_rect_visible(&diff.rect)) { 6148c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 6158c2ecf20Sopenharmony_ci struct vmw_stdu_update *cmd; 6168c2ecf20Sopenharmony_ci struct drm_clip_rect region; 6178c2ecf20Sopenharmony_ci int ret; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* We are updating the actual surface, not a proxy */ 6208c2ecf20Sopenharmony_ci region.x1 = diff.rect.x1; 6218c2ecf20Sopenharmony_ci region.x2 = diff.rect.x2; 6228c2ecf20Sopenharmony_ci region.y1 = diff.rect.y1; 6238c2ecf20Sopenharmony_ci region.y2 = diff.rect.y2; 6248c2ecf20Sopenharmony_ci ret = vmw_kms_update_proxy(&stdu->display_srf->res, ®ion, 6258c2ecf20Sopenharmony_ci 1, 1); 6268c2ecf20Sopenharmony_ci if (ret) 6278c2ecf20Sopenharmony_ci goto out_cleanup; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci dev_priv = vmw_priv(stdu->base.crtc.dev); 6318c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 6328c2ecf20Sopenharmony_ci if (!cmd) 6338c2ecf20Sopenharmony_ci goto out_cleanup; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci vmw_stdu_populate_update(cmd, stdu->base.unit, 6368c2ecf20Sopenharmony_ci region.x1, region.x2, 6378c2ecf20Sopenharmony_ci region.y1, region.y2); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 6408c2ecf20Sopenharmony_ci } 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ciout_cleanup: 6438c2ecf20Sopenharmony_ci ddirty->left = ddirty->top = ddirty->fb_left = ddirty->fb_top = S32_MAX; 6448c2ecf20Sopenharmony_ci ddirty->right = ddirty->bottom = S32_MIN; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/** 6488c2ecf20Sopenharmony_ci * vmw_kms_stdu_dma - Perform a DMA transfer between a buffer-object backed 6498c2ecf20Sopenharmony_ci * framebuffer and the screen target system. 6508c2ecf20Sopenharmony_ci * 6518c2ecf20Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 6528c2ecf20Sopenharmony_ci * @file_priv: Pointer to a struct drm-file identifying the caller. May be 6538c2ecf20Sopenharmony_ci * set to NULL, but then @user_fence_rep must also be set to NULL. 6548c2ecf20Sopenharmony_ci * @vfb: Pointer to the buffer-object backed framebuffer. 6558c2ecf20Sopenharmony_ci * @clips: Array of clip rects. Either @clips or @vclips must be NULL. 6568c2ecf20Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 6578c2ecf20Sopenharmony_ci * be NULL. 6588c2ecf20Sopenharmony_ci * @num_clips: Number of clip rects in @clips or @vclips. 6598c2ecf20Sopenharmony_ci * @increment: Increment to use when looping over @clips or @vclips. 6608c2ecf20Sopenharmony_ci * @to_surface: Whether to DMA to the screen target system as opposed to 6618c2ecf20Sopenharmony_ci * from the screen target system. 6628c2ecf20Sopenharmony_ci * @interruptible: Whether to perform waits interruptible if possible. 6638c2ecf20Sopenharmony_ci * @crtc: If crtc is passed, perform stdu dma on that crtc only. 6648c2ecf20Sopenharmony_ci * 6658c2ecf20Sopenharmony_ci * If DMA-ing till the screen target system, the function will also notify 6668c2ecf20Sopenharmony_ci * the screen target system that a bounding box of the cliprects has been 6678c2ecf20Sopenharmony_ci * updated. 6688c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 6698c2ecf20Sopenharmony_ci * interrupted. 6708c2ecf20Sopenharmony_ci */ 6718c2ecf20Sopenharmony_ciint vmw_kms_stdu_dma(struct vmw_private *dev_priv, 6728c2ecf20Sopenharmony_ci struct drm_file *file_priv, 6738c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 6748c2ecf20Sopenharmony_ci struct drm_vmw_fence_rep __user *user_fence_rep, 6758c2ecf20Sopenharmony_ci struct drm_clip_rect *clips, 6768c2ecf20Sopenharmony_ci struct drm_vmw_rect *vclips, 6778c2ecf20Sopenharmony_ci uint32_t num_clips, 6788c2ecf20Sopenharmony_ci int increment, 6798c2ecf20Sopenharmony_ci bool to_surface, 6808c2ecf20Sopenharmony_ci bool interruptible, 6818c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 6828c2ecf20Sopenharmony_ci{ 6838c2ecf20Sopenharmony_ci struct vmw_buffer_object *buf = 6848c2ecf20Sopenharmony_ci container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; 6858c2ecf20Sopenharmony_ci struct vmw_stdu_dirty ddirty; 6868c2ecf20Sopenharmony_ci int ret; 6878c2ecf20Sopenharmony_ci bool cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); 6888c2ecf20Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* 6918c2ecf20Sopenharmony_ci * VMs without 3D support don't have the surface DMA command and 6928c2ecf20Sopenharmony_ci * we'll be using a CPU blit, and the framebuffer should be moved out 6938c2ecf20Sopenharmony_ci * of VRAM. 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci ret = vmw_validation_add_bo(&val_ctx, buf, false, cpu_blit); 6968c2ecf20Sopenharmony_ci if (ret) 6978c2ecf20Sopenharmony_ci return ret; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); 7008c2ecf20Sopenharmony_ci if (ret) 7018c2ecf20Sopenharmony_ci goto out_unref; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci ddirty.transfer = (to_surface) ? SVGA3D_WRITE_HOST_VRAM : 7048c2ecf20Sopenharmony_ci SVGA3D_READ_HOST_VRAM; 7058c2ecf20Sopenharmony_ci ddirty.left = ddirty.top = S32_MAX; 7068c2ecf20Sopenharmony_ci ddirty.right = ddirty.bottom = S32_MIN; 7078c2ecf20Sopenharmony_ci ddirty.fb_left = ddirty.fb_top = S32_MAX; 7088c2ecf20Sopenharmony_ci ddirty.pitch = vfb->base.pitches[0]; 7098c2ecf20Sopenharmony_ci ddirty.buf = buf; 7108c2ecf20Sopenharmony_ci ddirty.base.fifo_commit = vmw_stdu_bo_fifo_commit; 7118c2ecf20Sopenharmony_ci ddirty.base.clip = vmw_stdu_bo_clip; 7128c2ecf20Sopenharmony_ci ddirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_dma) + 7138c2ecf20Sopenharmony_ci num_clips * sizeof(SVGA3dCopyBox) + 7148c2ecf20Sopenharmony_ci sizeof(SVGA3dCmdSurfaceDMASuffix); 7158c2ecf20Sopenharmony_ci if (to_surface) 7168c2ecf20Sopenharmony_ci ddirty.base.fifo_reserve_size += sizeof(struct vmw_stdu_update); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (cpu_blit) { 7208c2ecf20Sopenharmony_ci ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit; 7218c2ecf20Sopenharmony_ci ddirty.base.clip = vmw_stdu_bo_cpu_clip; 7228c2ecf20Sopenharmony_ci ddirty.base.fifo_reserve_size = 0; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ddirty.base.crtc = crtc; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips, 7288c2ecf20Sopenharmony_ci 0, 0, num_clips, increment, &ddirty.base); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL, 7318c2ecf20Sopenharmony_ci user_fence_rep); 7328c2ecf20Sopenharmony_ci return ret; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ciout_unref: 7358c2ecf20Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 7368c2ecf20Sopenharmony_ci return ret; 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/** 7408c2ecf20Sopenharmony_ci * vmw_stdu_surface_clip - Callback to encode a surface copy command cliprect 7418c2ecf20Sopenharmony_ci * 7428c2ecf20Sopenharmony_ci * @dirty: The closure structure. 7438c2ecf20Sopenharmony_ci * 7448c2ecf20Sopenharmony_ci * Encodes a surface copy command cliprect and updates the bounding box 7458c2ecf20Sopenharmony_ci * for the copy. 7468c2ecf20Sopenharmony_ci */ 7478c2ecf20Sopenharmony_cistatic void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *sdirty = 7508c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 7518c2ecf20Sopenharmony_ci struct vmw_stdu_surface_copy *cmd = dirty->cmd; 7528c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu = 7538c2ecf20Sopenharmony_ci container_of(dirty->unit, typeof(*stdu), base); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (sdirty->sid != stdu->display_srf->res.id) { 7568c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci blit += dirty->num_hits; 7598c2ecf20Sopenharmony_ci blit->srcx = dirty->fb_x; 7608c2ecf20Sopenharmony_ci blit->srcy = dirty->fb_y; 7618c2ecf20Sopenharmony_ci blit->x = dirty->unit_x1; 7628c2ecf20Sopenharmony_ci blit->y = dirty->unit_y1; 7638c2ecf20Sopenharmony_ci blit->d = 1; 7648c2ecf20Sopenharmony_ci blit->w = dirty->unit_x2 - dirty->unit_x1; 7658c2ecf20Sopenharmony_ci blit->h = dirty->unit_y2 - dirty->unit_y1; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci dirty->num_hits++; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Destination bounding box */ 7718c2ecf20Sopenharmony_ci sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1); 7728c2ecf20Sopenharmony_ci sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1); 7738c2ecf20Sopenharmony_ci sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2); 7748c2ecf20Sopenharmony_ci sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/** 7788c2ecf20Sopenharmony_ci * vmw_stdu_surface_fifo_commit - Callback to fill in and submit a surface 7798c2ecf20Sopenharmony_ci * copy command. 7808c2ecf20Sopenharmony_ci * 7818c2ecf20Sopenharmony_ci * @dirty: The closure structure. 7828c2ecf20Sopenharmony_ci * 7838c2ecf20Sopenharmony_ci * Fills in the missing fields in a surface copy command, and encodes a screen 7848c2ecf20Sopenharmony_ci * target update command. 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_cistatic void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct vmw_stdu_dirty *sdirty = 7898c2ecf20Sopenharmony_ci container_of(dirty, struct vmw_stdu_dirty, base); 7908c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu = 7918c2ecf20Sopenharmony_ci container_of(dirty->unit, typeof(*stdu), base); 7928c2ecf20Sopenharmony_ci struct vmw_stdu_surface_copy *cmd = dirty->cmd; 7938c2ecf20Sopenharmony_ci struct vmw_stdu_update *update; 7948c2ecf20Sopenharmony_ci size_t blit_size = sizeof(SVGA3dCopyBox) * dirty->num_hits; 7958c2ecf20Sopenharmony_ci size_t commit_size; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (!dirty->num_hits) { 7988c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 0); 7998c2ecf20Sopenharmony_ci return; 8008c2ecf20Sopenharmony_ci } 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci if (sdirty->sid != stdu->display_srf->res.id) { 8038c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1]; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_SURFACE_COPY; 8068c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body) + blit_size; 8078c2ecf20Sopenharmony_ci cmd->body.src.sid = sdirty->sid; 8088c2ecf20Sopenharmony_ci cmd->body.dest.sid = stdu->display_srf->res.id; 8098c2ecf20Sopenharmony_ci update = (struct vmw_stdu_update *) &blit[dirty->num_hits]; 8108c2ecf20Sopenharmony_ci commit_size = sizeof(*cmd) + blit_size + sizeof(*update); 8118c2ecf20Sopenharmony_ci stdu->display_srf->res.res_dirty = true; 8128c2ecf20Sopenharmony_ci } else { 8138c2ecf20Sopenharmony_ci update = dirty->cmd; 8148c2ecf20Sopenharmony_ci commit_size = sizeof(*update); 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci vmw_stdu_populate_update(update, stdu->base.unit, sdirty->left, 8188c2ecf20Sopenharmony_ci sdirty->right, sdirty->top, sdirty->bottom); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, commit_size); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci sdirty->left = sdirty->top = S32_MAX; 8238c2ecf20Sopenharmony_ci sdirty->right = sdirty->bottom = S32_MIN; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci/** 8278c2ecf20Sopenharmony_ci * vmw_kms_stdu_surface_dirty - Dirty part of a surface backed framebuffer 8288c2ecf20Sopenharmony_ci * 8298c2ecf20Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 8308c2ecf20Sopenharmony_ci * @framebuffer: Pointer to the surface-buffer backed framebuffer. 8318c2ecf20Sopenharmony_ci * @clips: Array of clip rects. Either @clips or @vclips must be NULL. 8328c2ecf20Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 8338c2ecf20Sopenharmony_ci * be NULL. 8348c2ecf20Sopenharmony_ci * @srf: Pointer to surface to blit from. If NULL, the surface attached 8358c2ecf20Sopenharmony_ci * to @framebuffer will be used. 8368c2ecf20Sopenharmony_ci * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. 8378c2ecf20Sopenharmony_ci * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. 8388c2ecf20Sopenharmony_ci * @num_clips: Number of clip rects in @clips. 8398c2ecf20Sopenharmony_ci * @inc: Increment to use when looping over @clips. 8408c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to a 8418c2ecf20Sopenharmony_ci * struct vmw_fence_obj. The returned fence pointer may be NULL in which 8428c2ecf20Sopenharmony_ci * case the device has already synchronized. 8438c2ecf20Sopenharmony_ci * @crtc: If crtc is passed, perform surface dirty on that crtc only. 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 8468c2ecf20Sopenharmony_ci * interrupted. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ciint vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv, 8498c2ecf20Sopenharmony_ci struct vmw_framebuffer *framebuffer, 8508c2ecf20Sopenharmony_ci struct drm_clip_rect *clips, 8518c2ecf20Sopenharmony_ci struct drm_vmw_rect *vclips, 8528c2ecf20Sopenharmony_ci struct vmw_resource *srf, 8538c2ecf20Sopenharmony_ci s32 dest_x, 8548c2ecf20Sopenharmony_ci s32 dest_y, 8558c2ecf20Sopenharmony_ci unsigned num_clips, int inc, 8568c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence, 8578c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs = 8608c2ecf20Sopenharmony_ci container_of(framebuffer, typeof(*vfbs), base); 8618c2ecf20Sopenharmony_ci struct vmw_stdu_dirty sdirty; 8628c2ecf20Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 8638c2ecf20Sopenharmony_ci int ret; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (!srf) 8668c2ecf20Sopenharmony_ci srf = &vfbs->surface->res; 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, 8698c2ecf20Sopenharmony_ci NULL, NULL); 8708c2ecf20Sopenharmony_ci if (ret) 8718c2ecf20Sopenharmony_ci return ret; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); 8748c2ecf20Sopenharmony_ci if (ret) 8758c2ecf20Sopenharmony_ci goto out_unref; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (vfbs->is_bo_proxy) { 8788c2ecf20Sopenharmony_ci ret = vmw_kms_update_proxy(srf, clips, num_clips, inc); 8798c2ecf20Sopenharmony_ci if (ret) 8808c2ecf20Sopenharmony_ci goto out_finish; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit; 8848c2ecf20Sopenharmony_ci sdirty.base.clip = vmw_kms_stdu_surface_clip; 8858c2ecf20Sopenharmony_ci sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) + 8868c2ecf20Sopenharmony_ci sizeof(SVGA3dCopyBox) * num_clips + 8878c2ecf20Sopenharmony_ci sizeof(struct vmw_stdu_update); 8888c2ecf20Sopenharmony_ci sdirty.base.crtc = crtc; 8898c2ecf20Sopenharmony_ci sdirty.sid = srf->id; 8908c2ecf20Sopenharmony_ci sdirty.left = sdirty.top = S32_MAX; 8918c2ecf20Sopenharmony_ci sdirty.right = sdirty.bottom = S32_MIN; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 8948c2ecf20Sopenharmony_ci dest_x, dest_y, num_clips, inc, 8958c2ecf20Sopenharmony_ci &sdirty.base); 8968c2ecf20Sopenharmony_ciout_finish: 8978c2ecf20Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 8988c2ecf20Sopenharmony_ci NULL); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci return ret; 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ciout_unref: 9038c2ecf20Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 9048c2ecf20Sopenharmony_ci return ret; 9058c2ecf20Sopenharmony_ci} 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci/* 9098c2ecf20Sopenharmony_ci * Screen Target CRTC dispatch table 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic const struct drm_crtc_funcs vmw_stdu_crtc_funcs = { 9128c2ecf20Sopenharmony_ci .gamma_set = vmw_du_crtc_gamma_set, 9138c2ecf20Sopenharmony_ci .destroy = vmw_stdu_crtc_destroy, 9148c2ecf20Sopenharmony_ci .reset = vmw_du_crtc_reset, 9158c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 9168c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_crtc_destroy_state, 9178c2ecf20Sopenharmony_ci .set_config = drm_atomic_helper_set_config, 9188c2ecf20Sopenharmony_ci .page_flip = drm_atomic_helper_page_flip, 9198c2ecf20Sopenharmony_ci .get_vblank_counter = vmw_get_vblank_counter, 9208c2ecf20Sopenharmony_ci .enable_vblank = vmw_enable_vblank, 9218c2ecf20Sopenharmony_ci .disable_vblank = vmw_disable_vblank, 9228c2ecf20Sopenharmony_ci}; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci/****************************************************************************** 9278c2ecf20Sopenharmony_ci * Screen Target Display Unit Encoder Functions 9288c2ecf20Sopenharmony_ci *****************************************************************************/ 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci/** 9318c2ecf20Sopenharmony_ci * vmw_stdu_encoder_destroy - cleans up the STDU 9328c2ecf20Sopenharmony_ci * 9338c2ecf20Sopenharmony_ci * @encoder: used the get the containing STDU 9348c2ecf20Sopenharmony_ci * 9358c2ecf20Sopenharmony_ci * vmwgfx cleans up crtc/encoder/connector all at the same time so technically 9368c2ecf20Sopenharmony_ci * this can be a no-op. Nevertheless, it doesn't hurt of have this in case 9378c2ecf20Sopenharmony_ci * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't 9388c2ecf20Sopenharmony_ci * get called. 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_cistatic void vmw_stdu_encoder_destroy(struct drm_encoder *encoder) 9418c2ecf20Sopenharmony_ci{ 9428c2ecf20Sopenharmony_ci vmw_stdu_destroy(vmw_encoder_to_stdu(encoder)); 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs vmw_stdu_encoder_funcs = { 9468c2ecf20Sopenharmony_ci .destroy = vmw_stdu_encoder_destroy, 9478c2ecf20Sopenharmony_ci}; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci/****************************************************************************** 9528c2ecf20Sopenharmony_ci * Screen Target Display Unit Connector Functions 9538c2ecf20Sopenharmony_ci *****************************************************************************/ 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci/** 9568c2ecf20Sopenharmony_ci * vmw_stdu_connector_destroy - cleans up the STDU 9578c2ecf20Sopenharmony_ci * 9588c2ecf20Sopenharmony_ci * @connector: used to get the containing STDU 9598c2ecf20Sopenharmony_ci * 9608c2ecf20Sopenharmony_ci * vmwgfx cleans up crtc/encoder/connector all at the same time so technically 9618c2ecf20Sopenharmony_ci * this can be a no-op. Nevertheless, it doesn't hurt of have this in case 9628c2ecf20Sopenharmony_ci * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't 9638c2ecf20Sopenharmony_ci * get called. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_cistatic void vmw_stdu_connector_destroy(struct drm_connector *connector) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci vmw_stdu_destroy(vmw_connector_to_stdu(connector)); 9688c2ecf20Sopenharmony_ci} 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs vmw_stdu_connector_funcs = { 9738c2ecf20Sopenharmony_ci .dpms = vmw_du_connector_dpms, 9748c2ecf20Sopenharmony_ci .detect = vmw_du_connector_detect, 9758c2ecf20Sopenharmony_ci .fill_modes = vmw_du_connector_fill_modes, 9768c2ecf20Sopenharmony_ci .destroy = vmw_stdu_connector_destroy, 9778c2ecf20Sopenharmony_ci .reset = vmw_du_connector_reset, 9788c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_connector_duplicate_state, 9798c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_connector_destroy_state, 9808c2ecf20Sopenharmony_ci}; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic const struct 9848c2ecf20Sopenharmony_cidrm_connector_helper_funcs vmw_stdu_connector_helper_funcs = { 9858c2ecf20Sopenharmony_ci}; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/****************************************************************************** 9908c2ecf20Sopenharmony_ci * Screen Target Display Plane Functions 9918c2ecf20Sopenharmony_ci *****************************************************************************/ 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci/** 9968c2ecf20Sopenharmony_ci * vmw_stdu_primary_plane_cleanup_fb - Unpins the display surface 9978c2ecf20Sopenharmony_ci * 9988c2ecf20Sopenharmony_ci * @plane: display plane 9998c2ecf20Sopenharmony_ci * @old_state: Contains the FB to clean up 10008c2ecf20Sopenharmony_ci * 10018c2ecf20Sopenharmony_ci * Unpins the display surface 10028c2ecf20Sopenharmony_ci * 10038c2ecf20Sopenharmony_ci * Returns 0 on success 10048c2ecf20Sopenharmony_ci */ 10058c2ecf20Sopenharmony_cistatic void 10068c2ecf20Sopenharmony_civmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane, 10078c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (vps->surf) 10128c2ecf20Sopenharmony_ci WARN_ON(!vps->pinned); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci vmw_du_plane_cleanup_fb(plane, old_state); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci vps->content_fb_type = SAME_AS_DISPLAY; 10178c2ecf20Sopenharmony_ci vps->cpp = 0; 10188c2ecf20Sopenharmony_ci} 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci/** 10238c2ecf20Sopenharmony_ci * vmw_stdu_primary_plane_prepare_fb - Readies the display surface 10248c2ecf20Sopenharmony_ci * 10258c2ecf20Sopenharmony_ci * @plane: display plane 10268c2ecf20Sopenharmony_ci * @new_state: info on the new plane state, including the FB 10278c2ecf20Sopenharmony_ci * 10288c2ecf20Sopenharmony_ci * This function allocates a new display surface if the content is 10298c2ecf20Sopenharmony_ci * backed by a buffer object. The display surface is pinned here, and it'll 10308c2ecf20Sopenharmony_ci * be unpinned in .cleanup_fb() 10318c2ecf20Sopenharmony_ci * 10328c2ecf20Sopenharmony_ci * Returns 0 on success 10338c2ecf20Sopenharmony_ci */ 10348c2ecf20Sopenharmony_cistatic int 10358c2ecf20Sopenharmony_civmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane, 10368c2ecf20Sopenharmony_ci struct drm_plane_state *new_state) 10378c2ecf20Sopenharmony_ci{ 10388c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(plane->dev); 10398c2ecf20Sopenharmony_ci struct drm_framebuffer *new_fb = new_state->fb; 10408c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb; 10418c2ecf20Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 10428c2ecf20Sopenharmony_ci enum stdu_content_type new_content_type; 10438c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *new_vfbs; 10448c2ecf20Sopenharmony_ci uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h; 10458c2ecf20Sopenharmony_ci int ret; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci /* No FB to prepare */ 10488c2ecf20Sopenharmony_ci if (!new_fb) { 10498c2ecf20Sopenharmony_ci if (vps->surf) { 10508c2ecf20Sopenharmony_ci WARN_ON(vps->pinned != 0); 10518c2ecf20Sopenharmony_ci vmw_surface_unreference(&vps->surf); 10528c2ecf20Sopenharmony_ci } 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return 0; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci vfb = vmw_framebuffer_to_vfb(new_fb); 10588c2ecf20Sopenharmony_ci new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb); 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci if (new_vfbs && 10618c2ecf20Sopenharmony_ci new_vfbs->surface->metadata.base_size.width == hdisplay && 10628c2ecf20Sopenharmony_ci new_vfbs->surface->metadata.base_size.height == vdisplay) 10638c2ecf20Sopenharmony_ci new_content_type = SAME_AS_DISPLAY; 10648c2ecf20Sopenharmony_ci else if (vfb->bo) 10658c2ecf20Sopenharmony_ci new_content_type = SEPARATE_BO; 10668c2ecf20Sopenharmony_ci else 10678c2ecf20Sopenharmony_ci new_content_type = SEPARATE_SURFACE; 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci if (new_content_type != SAME_AS_DISPLAY) { 10708c2ecf20Sopenharmony_ci struct vmw_surface_metadata metadata = {0}; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci /* 10738c2ecf20Sopenharmony_ci * If content buffer is a buffer object, then we have to 10748c2ecf20Sopenharmony_ci * construct surface info 10758c2ecf20Sopenharmony_ci */ 10768c2ecf20Sopenharmony_ci if (new_content_type == SEPARATE_BO) { 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci switch (new_fb->format->cpp[0]*8) { 10798c2ecf20Sopenharmony_ci case 32: 10808c2ecf20Sopenharmony_ci metadata.format = SVGA3D_X8R8G8B8; 10818c2ecf20Sopenharmony_ci break; 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci case 16: 10848c2ecf20Sopenharmony_ci metadata.format = SVGA3D_R5G6B5; 10858c2ecf20Sopenharmony_ci break; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci case 8: 10888c2ecf20Sopenharmony_ci metadata.format = SVGA3D_P8; 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci default: 10928c2ecf20Sopenharmony_ci DRM_ERROR("Invalid format\n"); 10938c2ecf20Sopenharmony_ci return -EINVAL; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci metadata.mip_levels[0] = 1; 10978c2ecf20Sopenharmony_ci metadata.num_sizes = 1; 10988c2ecf20Sopenharmony_ci metadata.scanout = true; 10998c2ecf20Sopenharmony_ci } else { 11008c2ecf20Sopenharmony_ci metadata = new_vfbs->surface->metadata; 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci metadata.base_size.width = hdisplay; 11048c2ecf20Sopenharmony_ci metadata.base_size.height = vdisplay; 11058c2ecf20Sopenharmony_ci metadata.base_size.depth = 1; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci if (vps->surf) { 11088c2ecf20Sopenharmony_ci struct drm_vmw_size cur_base_size = 11098c2ecf20Sopenharmony_ci vps->surf->metadata.base_size; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (cur_base_size.width != metadata.base_size.width || 11128c2ecf20Sopenharmony_ci cur_base_size.height != metadata.base_size.height || 11138c2ecf20Sopenharmony_ci vps->surf->metadata.format != metadata.format) { 11148c2ecf20Sopenharmony_ci WARN_ON(vps->pinned != 0); 11158c2ecf20Sopenharmony_ci vmw_surface_unreference(&vps->surf); 11168c2ecf20Sopenharmony_ci } 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci if (!vps->surf) { 11218c2ecf20Sopenharmony_ci ret = vmw_gb_surface_define(dev_priv, 0, &metadata, 11228c2ecf20Sopenharmony_ci &vps->surf); 11238c2ecf20Sopenharmony_ci if (ret != 0) { 11248c2ecf20Sopenharmony_ci DRM_ERROR("Couldn't allocate STDU surface.\n"); 11258c2ecf20Sopenharmony_ci return ret; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci } else { 11298c2ecf20Sopenharmony_ci /* 11308c2ecf20Sopenharmony_ci * prepare_fb and clean_fb should only take care of pinning 11318c2ecf20Sopenharmony_ci * and unpinning. References are tracked by state objects. 11328c2ecf20Sopenharmony_ci * The only time we add a reference in prepare_fb is if the 11338c2ecf20Sopenharmony_ci * state object doesn't have a reference to begin with 11348c2ecf20Sopenharmony_ci */ 11358c2ecf20Sopenharmony_ci if (vps->surf) { 11368c2ecf20Sopenharmony_ci WARN_ON(vps->pinned != 0); 11378c2ecf20Sopenharmony_ci vmw_surface_unreference(&vps->surf); 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci vps->surf = vmw_surface_reference(new_vfbs->surface); 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci if (vps->surf) { 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* Pin new surface before flipping */ 11468c2ecf20Sopenharmony_ci ret = vmw_resource_pin(&vps->surf->res, false); 11478c2ecf20Sopenharmony_ci if (ret) 11488c2ecf20Sopenharmony_ci goto out_srf_unref; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci vps->pinned++; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci vps->content_fb_type = new_content_type; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* 11568c2ecf20Sopenharmony_ci * This should only happen if the buffer object is too large to create a 11578c2ecf20Sopenharmony_ci * proxy surface for. 11588c2ecf20Sopenharmony_ci * If we are a 2D VM with a buffer object then we have to use CPU blit 11598c2ecf20Sopenharmony_ci * so cache these mappings 11608c2ecf20Sopenharmony_ci */ 11618c2ecf20Sopenharmony_ci if (vps->content_fb_type == SEPARATE_BO && 11628c2ecf20Sopenharmony_ci !(dev_priv->capabilities & SVGA_CAP_3D)) 11638c2ecf20Sopenharmony_ci vps->cpp = new_fb->pitches[0] / new_fb->width; 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_ci return 0; 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ciout_srf_unref: 11688c2ecf20Sopenharmony_ci vmw_surface_unreference(&vps->surf); 11698c2ecf20Sopenharmony_ci return ret; 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_fifo_size(struct vmw_du_update_plane *update, 11738c2ecf20Sopenharmony_ci uint32_t num_hits) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci return sizeof(struct vmw_stdu_dma) + sizeof(SVGA3dCopyBox) * num_hits + 11768c2ecf20Sopenharmony_ci sizeof(SVGA3dCmdSurfaceDMASuffix) + 11778c2ecf20Sopenharmony_ci sizeof(struct vmw_stdu_update); 11788c2ecf20Sopenharmony_ci} 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update, 11818c2ecf20Sopenharmony_ci uint32_t num_hits) 11828c2ecf20Sopenharmony_ci{ 11838c2ecf20Sopenharmony_ci return sizeof(struct vmw_stdu_update_gb_image) + 11848c2ecf20Sopenharmony_ci sizeof(struct vmw_stdu_update); 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_populate_dma(struct vmw_du_update_plane *update, 11888c2ecf20Sopenharmony_ci void *cmd, uint32_t num_hits) 11898c2ecf20Sopenharmony_ci{ 11908c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 11918c2ecf20Sopenharmony_ci struct vmw_framebuffer_bo *vfbbo; 11928c2ecf20Sopenharmony_ci struct vmw_stdu_dma *cmd_dma = cmd; 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci stdu = container_of(update->du, typeof(*stdu), base); 11958c2ecf20Sopenharmony_ci vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci cmd_dma->header.id = SVGA_3D_CMD_SURFACE_DMA; 11988c2ecf20Sopenharmony_ci cmd_dma->header.size = sizeof(cmd_dma->body) + 11998c2ecf20Sopenharmony_ci sizeof(struct SVGA3dCopyBox) * num_hits + 12008c2ecf20Sopenharmony_ci sizeof(SVGA3dCmdSurfaceDMASuffix); 12018c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &cmd_dma->body.guest.ptr); 12028c2ecf20Sopenharmony_ci cmd_dma->body.guest.pitch = update->vfb->base.pitches[0]; 12038c2ecf20Sopenharmony_ci cmd_dma->body.host.sid = stdu->display_srf->res.id; 12048c2ecf20Sopenharmony_ci cmd_dma->body.host.face = 0; 12058c2ecf20Sopenharmony_ci cmd_dma->body.host.mipmap = 0; 12068c2ecf20Sopenharmony_ci cmd_dma->body.transfer = SVGA3D_WRITE_HOST_VRAM; 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return sizeof(*cmd_dma); 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_populate_clip(struct vmw_du_update_plane *update, 12128c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *clip, 12138c2ecf20Sopenharmony_ci uint32_t fb_x, uint32_t fb_y) 12148c2ecf20Sopenharmony_ci{ 12158c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *box = cmd; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci box->srcx = fb_x; 12188c2ecf20Sopenharmony_ci box->srcy = fb_y; 12198c2ecf20Sopenharmony_ci box->srcz = 0; 12208c2ecf20Sopenharmony_ci box->x = clip->x1; 12218c2ecf20Sopenharmony_ci box->y = clip->y1; 12228c2ecf20Sopenharmony_ci box->z = 0; 12238c2ecf20Sopenharmony_ci box->w = drm_rect_width(clip); 12248c2ecf20Sopenharmony_ci box->h = drm_rect_height(clip); 12258c2ecf20Sopenharmony_ci box->d = 1; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci return sizeof(*box); 12288c2ecf20Sopenharmony_ci} 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_populate_update(struct vmw_du_update_plane *update, 12318c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *bb) 12328c2ecf20Sopenharmony_ci{ 12338c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 12348c2ecf20Sopenharmony_ci struct vmw_framebuffer_bo *vfbbo; 12358c2ecf20Sopenharmony_ci SVGA3dCmdSurfaceDMASuffix *suffix = cmd; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci stdu = container_of(update->du, typeof(*stdu), base); 12388c2ecf20Sopenharmony_ci vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci suffix->suffixSize = sizeof(*suffix); 12418c2ecf20Sopenharmony_ci suffix->maximumOffset = vfbbo->buffer->base.num_pages * PAGE_SIZE; 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci vmw_stdu_populate_update(&suffix[1], stdu->base.unit, bb->x1, bb->x2, 12448c2ecf20Sopenharmony_ci bb->y1, bb->y2); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return sizeof(*suffix) + sizeof(struct vmw_stdu_update); 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane *update, 12508c2ecf20Sopenharmony_ci void *cmd, uint32_t num_hits) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct vmw_du_update_plane_buffer *bo_update = 12538c2ecf20Sopenharmony_ci container_of(update, typeof(*bo_update), base); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci bo_update->fb_left = INT_MAX; 12568c2ecf20Sopenharmony_ci bo_update->fb_top = INT_MAX; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci return 0; 12598c2ecf20Sopenharmony_ci} 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane *update, 12628c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *clip, 12638c2ecf20Sopenharmony_ci uint32_t fb_x, uint32_t fb_y) 12648c2ecf20Sopenharmony_ci{ 12658c2ecf20Sopenharmony_ci struct vmw_du_update_plane_buffer *bo_update = 12668c2ecf20Sopenharmony_ci container_of(update, typeof(*bo_update), base); 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x); 12698c2ecf20Sopenharmony_ci bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci return 0; 12728c2ecf20Sopenharmony_ci} 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_cistatic uint32_t 12758c2ecf20Sopenharmony_civmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane *update, void *cmd, 12768c2ecf20Sopenharmony_ci struct drm_rect *bb) 12778c2ecf20Sopenharmony_ci{ 12788c2ecf20Sopenharmony_ci struct vmw_du_update_plane_buffer *bo_update; 12798c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 12808c2ecf20Sopenharmony_ci struct vmw_framebuffer_bo *vfbbo; 12818c2ecf20Sopenharmony_ci struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0); 12828c2ecf20Sopenharmony_ci struct vmw_stdu_update_gb_image *cmd_img = cmd; 12838c2ecf20Sopenharmony_ci struct vmw_stdu_update *cmd_update; 12848c2ecf20Sopenharmony_ci struct ttm_buffer_object *src_bo, *dst_bo; 12858c2ecf20Sopenharmony_ci u32 src_offset, dst_offset; 12868c2ecf20Sopenharmony_ci s32 src_pitch, dst_pitch; 12878c2ecf20Sopenharmony_ci s32 width, height; 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci bo_update = container_of(update, typeof(*bo_update), base); 12908c2ecf20Sopenharmony_ci stdu = container_of(update->du, typeof(*stdu), base); 12918c2ecf20Sopenharmony_ci vfbbo = container_of(update->vfb, typeof(*vfbbo), base); 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci width = bb->x2 - bb->x1; 12948c2ecf20Sopenharmony_ci height = bb->y2 - bb->y1; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci diff.cpp = stdu->cpp; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci dst_bo = &stdu->display_srf->res.backup->base; 12998c2ecf20Sopenharmony_ci dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp; 13008c2ecf20Sopenharmony_ci dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci src_bo = &vfbbo->buffer->base; 13038c2ecf20Sopenharmony_ci src_pitch = update->vfb->base.pitches[0]; 13048c2ecf20Sopenharmony_ci src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left * 13058c2ecf20Sopenharmony_ci stdu->cpp; 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci (void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo, 13088c2ecf20Sopenharmony_ci src_offset, src_pitch, width * stdu->cpp, height, 13098c2ecf20Sopenharmony_ci &diff); 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci if (drm_rect_visible(&diff.rect)) { 13128c2ecf20Sopenharmony_ci SVGA3dBox *box = &cmd_img->body.box; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 13158c2ecf20Sopenharmony_ci cmd_img->header.size = sizeof(cmd_img->body); 13168c2ecf20Sopenharmony_ci cmd_img->body.image.sid = stdu->display_srf->res.id; 13178c2ecf20Sopenharmony_ci cmd_img->body.image.face = 0; 13188c2ecf20Sopenharmony_ci cmd_img->body.image.mipmap = 0; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci box->x = diff.rect.x1; 13218c2ecf20Sopenharmony_ci box->y = diff.rect.y1; 13228c2ecf20Sopenharmony_ci box->z = 0; 13238c2ecf20Sopenharmony_ci box->w = drm_rect_width(&diff.rect); 13248c2ecf20Sopenharmony_ci box->h = drm_rect_height(&diff.rect); 13258c2ecf20Sopenharmony_ci box->d = 1; 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci cmd_update = (struct vmw_stdu_update *)&cmd_img[1]; 13288c2ecf20Sopenharmony_ci vmw_stdu_populate_update(cmd_update, stdu->base.unit, 13298c2ecf20Sopenharmony_ci diff.rect.x1, diff.rect.x2, 13308c2ecf20Sopenharmony_ci diff.rect.y1, diff.rect.y2); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci return sizeof(*cmd_img) + sizeof(*cmd_update); 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci return 0; 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci/** 13398c2ecf20Sopenharmony_ci * vmw_stdu_plane_update_bo - Update display unit for bo backed fb. 13408c2ecf20Sopenharmony_ci * @dev_priv: device private. 13418c2ecf20Sopenharmony_ci * @plane: plane state. 13428c2ecf20Sopenharmony_ci * @old_state: old plane state. 13438c2ecf20Sopenharmony_ci * @vfb: framebuffer which is blitted to display unit. 13448c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 13458c2ecf20Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 13468c2ecf20Sopenharmony_ci * has already synchronized. 13478c2ecf20Sopenharmony_ci * 13488c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 13498c2ecf20Sopenharmony_ci */ 13508c2ecf20Sopenharmony_cistatic int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv, 13518c2ecf20Sopenharmony_ci struct drm_plane *plane, 13528c2ecf20Sopenharmony_ci struct drm_plane_state *old_state, 13538c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 13548c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci struct vmw_du_update_plane_buffer bo_update; 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); 13598c2ecf20Sopenharmony_ci bo_update.base.plane = plane; 13608c2ecf20Sopenharmony_ci bo_update.base.old_state = old_state; 13618c2ecf20Sopenharmony_ci bo_update.base.dev_priv = dev_priv; 13628c2ecf20Sopenharmony_ci bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); 13638c2ecf20Sopenharmony_ci bo_update.base.vfb = vfb; 13648c2ecf20Sopenharmony_ci bo_update.base.out_fence = out_fence; 13658c2ecf20Sopenharmony_ci bo_update.base.mutex = NULL; 13668c2ecf20Sopenharmony_ci bo_update.base.cpu_blit = !(dev_priv->capabilities & SVGA_CAP_3D); 13678c2ecf20Sopenharmony_ci bo_update.base.intr = false; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci /* 13708c2ecf20Sopenharmony_ci * VM without 3D support don't have surface DMA command and framebuffer 13718c2ecf20Sopenharmony_ci * should be moved out of VRAM. 13728c2ecf20Sopenharmony_ci */ 13738c2ecf20Sopenharmony_ci if (bo_update.base.cpu_blit) { 13748c2ecf20Sopenharmony_ci bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu; 13758c2ecf20Sopenharmony_ci bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu; 13768c2ecf20Sopenharmony_ci bo_update.base.clip = vmw_stdu_bo_clip_cpu; 13778c2ecf20Sopenharmony_ci bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu; 13788c2ecf20Sopenharmony_ci } else { 13798c2ecf20Sopenharmony_ci bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size; 13808c2ecf20Sopenharmony_ci bo_update.base.pre_clip = vmw_stdu_bo_populate_dma; 13818c2ecf20Sopenharmony_ci bo_update.base.clip = vmw_stdu_bo_populate_clip; 13828c2ecf20Sopenharmony_ci bo_update.base.post_clip = vmw_stdu_bo_populate_update; 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci return vmw_du_helper_plane_update(&bo_update.base); 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic uint32_t 13898c2ecf20Sopenharmony_civmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update, 13908c2ecf20Sopenharmony_ci uint32_t num_hits) 13918c2ecf20Sopenharmony_ci{ 13928c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 13938c2ecf20Sopenharmony_ci uint32_t size = 0; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (vfbs->is_bo_proxy) 13988c2ecf20Sopenharmony_ci size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci size += sizeof(struct vmw_stdu_update); 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci return size; 14038c2ecf20Sopenharmony_ci} 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_cistatic uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update, 14068c2ecf20Sopenharmony_ci uint32_t num_hits) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 14098c2ecf20Sopenharmony_ci uint32_t size = 0; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (vfbs->is_bo_proxy) 14148c2ecf20Sopenharmony_ci size += sizeof(struct vmw_stdu_update_gb_image) * num_hits; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) * 14178c2ecf20Sopenharmony_ci num_hits + sizeof(struct vmw_stdu_update); 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci return size; 14208c2ecf20Sopenharmony_ci} 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_cistatic uint32_t 14238c2ecf20Sopenharmony_civmw_stdu_surface_update_proxy(struct vmw_du_update_plane *update, void *cmd) 14248c2ecf20Sopenharmony_ci{ 14258c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 14268c2ecf20Sopenharmony_ci struct drm_plane_state *state = update->plane->state; 14278c2ecf20Sopenharmony_ci struct drm_plane_state *old_state = update->old_state; 14288c2ecf20Sopenharmony_ci struct vmw_stdu_update_gb_image *cmd_update = cmd; 14298c2ecf20Sopenharmony_ci struct drm_atomic_helper_damage_iter iter; 14308c2ecf20Sopenharmony_ci struct drm_rect clip; 14318c2ecf20Sopenharmony_ci uint32_t copy_size = 0; 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci /* 14368c2ecf20Sopenharmony_ci * proxy surface is special where a buffer object type fb is wrapped 14378c2ecf20Sopenharmony_ci * in a surface and need an update gb image command to sync with device. 14388c2ecf20Sopenharmony_ci */ 14398c2ecf20Sopenharmony_ci drm_atomic_helper_damage_iter_init(&iter, old_state, state); 14408c2ecf20Sopenharmony_ci drm_atomic_for_each_plane_damage(&iter, &clip) { 14418c2ecf20Sopenharmony_ci SVGA3dBox *box = &cmd_update->body.box; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci cmd_update->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE; 14448c2ecf20Sopenharmony_ci cmd_update->header.size = sizeof(cmd_update->body); 14458c2ecf20Sopenharmony_ci cmd_update->body.image.sid = vfbs->surface->res.id; 14468c2ecf20Sopenharmony_ci cmd_update->body.image.face = 0; 14478c2ecf20Sopenharmony_ci cmd_update->body.image.mipmap = 0; 14488c2ecf20Sopenharmony_ci 14498c2ecf20Sopenharmony_ci box->x = clip.x1; 14508c2ecf20Sopenharmony_ci box->y = clip.y1; 14518c2ecf20Sopenharmony_ci box->z = 0; 14528c2ecf20Sopenharmony_ci box->w = drm_rect_width(&clip); 14538c2ecf20Sopenharmony_ci box->h = drm_rect_height(&clip); 14548c2ecf20Sopenharmony_ci box->d = 1; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci copy_size += sizeof(*cmd_update); 14578c2ecf20Sopenharmony_ci cmd_update++; 14588c2ecf20Sopenharmony_ci } 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci return copy_size; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_cistatic uint32_t 14648c2ecf20Sopenharmony_civmw_stdu_surface_populate_copy(struct vmw_du_update_plane *update, void *cmd, 14658c2ecf20Sopenharmony_ci uint32_t num_hits) 14668c2ecf20Sopenharmony_ci{ 14678c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 14688c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 14698c2ecf20Sopenharmony_ci struct vmw_stdu_surface_copy *cmd_copy = cmd; 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci stdu = container_of(update->du, typeof(*stdu), base); 14728c2ecf20Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY; 14758c2ecf20Sopenharmony_ci cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) * 14768c2ecf20Sopenharmony_ci num_hits; 14778c2ecf20Sopenharmony_ci cmd_copy->body.src.sid = vfbs->surface->res.id; 14788c2ecf20Sopenharmony_ci cmd_copy->body.dest.sid = stdu->display_srf->res.id; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci return sizeof(*cmd_copy); 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic uint32_t 14848c2ecf20Sopenharmony_civmw_stdu_surface_populate_clip(struct vmw_du_update_plane *update, void *cmd, 14858c2ecf20Sopenharmony_ci struct drm_rect *clip, uint32_t fb_x, 14868c2ecf20Sopenharmony_ci uint32_t fb_y) 14878c2ecf20Sopenharmony_ci{ 14888c2ecf20Sopenharmony_ci struct SVGA3dCopyBox *box = cmd; 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_ci box->srcx = fb_x; 14918c2ecf20Sopenharmony_ci box->srcy = fb_y; 14928c2ecf20Sopenharmony_ci box->srcz = 0; 14938c2ecf20Sopenharmony_ci box->x = clip->x1; 14948c2ecf20Sopenharmony_ci box->y = clip->y1; 14958c2ecf20Sopenharmony_ci box->z = 0; 14968c2ecf20Sopenharmony_ci box->w = drm_rect_width(clip); 14978c2ecf20Sopenharmony_ci box->h = drm_rect_height(clip); 14988c2ecf20Sopenharmony_ci box->d = 1; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci return sizeof(*box); 15018c2ecf20Sopenharmony_ci} 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_cistatic uint32_t 15048c2ecf20Sopenharmony_civmw_stdu_surface_populate_update(struct vmw_du_update_plane *update, void *cmd, 15058c2ecf20Sopenharmony_ci struct drm_rect *bb) 15068c2ecf20Sopenharmony_ci{ 15078c2ecf20Sopenharmony_ci vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1, 15088c2ecf20Sopenharmony_ci bb->y2); 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci return sizeof(struct vmw_stdu_update); 15118c2ecf20Sopenharmony_ci} 15128c2ecf20Sopenharmony_ci 15138c2ecf20Sopenharmony_ci/** 15148c2ecf20Sopenharmony_ci * vmw_stdu_plane_update_surface - Update display unit for surface backed fb 15158c2ecf20Sopenharmony_ci * @dev_priv: Device private 15168c2ecf20Sopenharmony_ci * @plane: Plane state 15178c2ecf20Sopenharmony_ci * @old_state: Old plane state 15188c2ecf20Sopenharmony_ci * @vfb: Framebuffer which is blitted to display unit 15198c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 15208c2ecf20Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 15218c2ecf20Sopenharmony_ci * has already synchronized. 15228c2ecf20Sopenharmony_ci * 15238c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 15248c2ecf20Sopenharmony_ci */ 15258c2ecf20Sopenharmony_cistatic int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv, 15268c2ecf20Sopenharmony_ci struct drm_plane *plane, 15278c2ecf20Sopenharmony_ci struct drm_plane_state *old_state, 15288c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 15298c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence) 15308c2ecf20Sopenharmony_ci{ 15318c2ecf20Sopenharmony_ci struct vmw_du_update_plane srf_update; 15328c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 15338c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci stdu = vmw_crtc_to_stdu(plane->state->crtc); 15368c2ecf20Sopenharmony_ci vfbs = container_of(vfb, typeof(*vfbs), base); 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_ci memset(&srf_update, 0, sizeof(struct vmw_du_update_plane)); 15398c2ecf20Sopenharmony_ci srf_update.plane = plane; 15408c2ecf20Sopenharmony_ci srf_update.old_state = old_state; 15418c2ecf20Sopenharmony_ci srf_update.dev_priv = dev_priv; 15428c2ecf20Sopenharmony_ci srf_update.du = vmw_crtc_to_du(plane->state->crtc); 15438c2ecf20Sopenharmony_ci srf_update.vfb = vfb; 15448c2ecf20Sopenharmony_ci srf_update.out_fence = out_fence; 15458c2ecf20Sopenharmony_ci srf_update.mutex = &dev_priv->cmdbuf_mutex; 15468c2ecf20Sopenharmony_ci srf_update.cpu_blit = false; 15478c2ecf20Sopenharmony_ci srf_update.intr = true; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (vfbs->is_bo_proxy) 15508c2ecf20Sopenharmony_ci srf_update.post_prepare = vmw_stdu_surface_update_proxy; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci if (vfbs->surface->res.id != stdu->display_srf->res.id) { 15538c2ecf20Sopenharmony_ci srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size; 15548c2ecf20Sopenharmony_ci srf_update.pre_clip = vmw_stdu_surface_populate_copy; 15558c2ecf20Sopenharmony_ci srf_update.clip = vmw_stdu_surface_populate_clip; 15568c2ecf20Sopenharmony_ci } else { 15578c2ecf20Sopenharmony_ci srf_update.calc_fifo_size = 15588c2ecf20Sopenharmony_ci vmw_stdu_surface_fifo_size_same_display; 15598c2ecf20Sopenharmony_ci } 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci srf_update.post_clip = vmw_stdu_surface_populate_update; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci return vmw_du_helper_plane_update(&srf_update); 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci/** 15678c2ecf20Sopenharmony_ci * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane 15688c2ecf20Sopenharmony_ci * @plane: display plane 15698c2ecf20Sopenharmony_ci * @old_state: Only used to get crtc info 15708c2ecf20Sopenharmony_ci * 15718c2ecf20Sopenharmony_ci * Formally update stdu->display_srf to the new plane, and bind the new 15728c2ecf20Sopenharmony_ci * plane STDU. This function is called during the commit phase when 15738c2ecf20Sopenharmony_ci * all the preparation have been done and all the configurations have 15748c2ecf20Sopenharmony_ci * been checked. 15758c2ecf20Sopenharmony_ci */ 15768c2ecf20Sopenharmony_cistatic void 15778c2ecf20Sopenharmony_civmw_stdu_primary_plane_atomic_update(struct drm_plane *plane, 15788c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(plane->state); 15818c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc; 15828c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 15838c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *event; 15848c2ecf20Sopenharmony_ci struct vmw_fence_obj *fence = NULL; 15858c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 15868c2ecf20Sopenharmony_ci int ret; 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci /* If case of device error, maintain consistent atomic state */ 15898c2ecf20Sopenharmony_ci if (crtc && plane->state->fb) { 15908c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb = 15918c2ecf20Sopenharmony_ci vmw_framebuffer_to_vfb(plane->state->fb); 15928c2ecf20Sopenharmony_ci stdu = vmw_crtc_to_stdu(crtc); 15938c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci stdu->display_srf = vps->surf; 15968c2ecf20Sopenharmony_ci stdu->content_fb_type = vps->content_fb_type; 15978c2ecf20Sopenharmony_ci stdu->cpp = vps->cpp; 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res); 16008c2ecf20Sopenharmony_ci if (ret) 16018c2ecf20Sopenharmony_ci DRM_ERROR("Failed to bind surface to STDU.\n"); 16028c2ecf20Sopenharmony_ci 16038c2ecf20Sopenharmony_ci if (vfb->bo) 16048c2ecf20Sopenharmony_ci ret = vmw_stdu_plane_update_bo(dev_priv, plane, 16058c2ecf20Sopenharmony_ci old_state, vfb, &fence); 16068c2ecf20Sopenharmony_ci else 16078c2ecf20Sopenharmony_ci ret = vmw_stdu_plane_update_surface(dev_priv, plane, 16088c2ecf20Sopenharmony_ci old_state, vfb, 16098c2ecf20Sopenharmony_ci &fence); 16108c2ecf20Sopenharmony_ci if (ret) 16118c2ecf20Sopenharmony_ci DRM_ERROR("Failed to update STDU.\n"); 16128c2ecf20Sopenharmony_ci } else { 16138c2ecf20Sopenharmony_ci crtc = old_state->crtc; 16148c2ecf20Sopenharmony_ci stdu = vmw_crtc_to_stdu(crtc); 16158c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci /* Blank STDU when fb and crtc are NULL */ 16188c2ecf20Sopenharmony_ci if (!stdu->defined) 16198c2ecf20Sopenharmony_ci return; 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci ret = vmw_stdu_bind_st(dev_priv, stdu, NULL); 16228c2ecf20Sopenharmony_ci if (ret) 16238c2ecf20Sopenharmony_ci DRM_ERROR("Failed to blank STDU\n"); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci ret = vmw_stdu_update_st(dev_priv, stdu); 16268c2ecf20Sopenharmony_ci if (ret) 16278c2ecf20Sopenharmony_ci DRM_ERROR("Failed to update STDU.\n"); 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci return; 16308c2ecf20Sopenharmony_ci } 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci /* In case of error, vblank event is send in vmw_du_crtc_atomic_flush */ 16338c2ecf20Sopenharmony_ci event = crtc->state->event; 16348c2ecf20Sopenharmony_ci if (event && fence) { 16358c2ecf20Sopenharmony_ci struct drm_file *file_priv = event->base.file_priv; 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci ret = vmw_event_fence_action_queue(file_priv, 16388c2ecf20Sopenharmony_ci fence, 16398c2ecf20Sopenharmony_ci &event->base, 16408c2ecf20Sopenharmony_ci &event->event.vbl.tv_sec, 16418c2ecf20Sopenharmony_ci &event->event.vbl.tv_usec, 16428c2ecf20Sopenharmony_ci true); 16438c2ecf20Sopenharmony_ci if (ret) 16448c2ecf20Sopenharmony_ci DRM_ERROR("Failed to queue event on fence.\n"); 16458c2ecf20Sopenharmony_ci else 16468c2ecf20Sopenharmony_ci crtc->state->event = NULL; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (fence) 16508c2ecf20Sopenharmony_ci vmw_fence_obj_unreference(&fence); 16518c2ecf20Sopenharmony_ci} 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs vmw_stdu_plane_funcs = { 16558c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 16568c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 16578c2ecf20Sopenharmony_ci .destroy = vmw_du_primary_plane_destroy, 16588c2ecf20Sopenharmony_ci .reset = vmw_du_plane_reset, 16598c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 16608c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 16618c2ecf20Sopenharmony_ci}; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs vmw_stdu_cursor_funcs = { 16648c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 16658c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 16668c2ecf20Sopenharmony_ci .destroy = vmw_du_cursor_plane_destroy, 16678c2ecf20Sopenharmony_ci .reset = vmw_du_plane_reset, 16688c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 16698c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 16708c2ecf20Sopenharmony_ci}; 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci/* 16748c2ecf20Sopenharmony_ci * Atomic Helpers 16758c2ecf20Sopenharmony_ci */ 16768c2ecf20Sopenharmony_cistatic const struct 16778c2ecf20Sopenharmony_cidrm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = { 16788c2ecf20Sopenharmony_ci .atomic_check = vmw_du_cursor_plane_atomic_check, 16798c2ecf20Sopenharmony_ci .atomic_update = vmw_du_cursor_plane_atomic_update, 16808c2ecf20Sopenharmony_ci .prepare_fb = vmw_du_cursor_plane_prepare_fb, 16818c2ecf20Sopenharmony_ci .cleanup_fb = vmw_du_plane_cleanup_fb, 16828c2ecf20Sopenharmony_ci}; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_cistatic const struct 16858c2ecf20Sopenharmony_cidrm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = { 16868c2ecf20Sopenharmony_ci .atomic_check = vmw_du_primary_plane_atomic_check, 16878c2ecf20Sopenharmony_ci .atomic_update = vmw_stdu_primary_plane_atomic_update, 16888c2ecf20Sopenharmony_ci .prepare_fb = vmw_stdu_primary_plane_prepare_fb, 16898c2ecf20Sopenharmony_ci .cleanup_fb = vmw_stdu_primary_plane_cleanup_fb, 16908c2ecf20Sopenharmony_ci}; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_cistatic const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = { 16938c2ecf20Sopenharmony_ci .prepare = vmw_stdu_crtc_helper_prepare, 16948c2ecf20Sopenharmony_ci .mode_set_nofb = vmw_stdu_crtc_mode_set_nofb, 16958c2ecf20Sopenharmony_ci .atomic_check = vmw_du_crtc_atomic_check, 16968c2ecf20Sopenharmony_ci .atomic_begin = vmw_du_crtc_atomic_begin, 16978c2ecf20Sopenharmony_ci .atomic_flush = vmw_du_crtc_atomic_flush, 16988c2ecf20Sopenharmony_ci .atomic_enable = vmw_stdu_crtc_atomic_enable, 16998c2ecf20Sopenharmony_ci .atomic_disable = vmw_stdu_crtc_atomic_disable, 17008c2ecf20Sopenharmony_ci}; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci 17038c2ecf20Sopenharmony_ci/** 17048c2ecf20Sopenharmony_ci * vmw_stdu_init - Sets up a Screen Target Display Unit 17058c2ecf20Sopenharmony_ci * 17068c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 17078c2ecf20Sopenharmony_ci * @unit: unit number range from 0 to VMWGFX_NUM_DISPLAY_UNITS 17088c2ecf20Sopenharmony_ci * 17098c2ecf20Sopenharmony_ci * This function is called once per CRTC, and allocates one Screen Target 17108c2ecf20Sopenharmony_ci * display unit to represent that CRTC. Since the SVGA device does not separate 17118c2ecf20Sopenharmony_ci * out encoder and connector, they are represented as part of the STDU as well. 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_cistatic int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit) 17148c2ecf20Sopenharmony_ci{ 17158c2ecf20Sopenharmony_ci struct vmw_screen_target_display_unit *stdu; 17168c2ecf20Sopenharmony_ci struct drm_device *dev = dev_priv->dev; 17178c2ecf20Sopenharmony_ci struct drm_connector *connector; 17188c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 17198c2ecf20Sopenharmony_ci struct drm_plane *primary, *cursor; 17208c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 17218c2ecf20Sopenharmony_ci int ret; 17228c2ecf20Sopenharmony_ci 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci stdu = kzalloc(sizeof(*stdu), GFP_KERNEL); 17258c2ecf20Sopenharmony_ci if (!stdu) 17268c2ecf20Sopenharmony_ci return -ENOMEM; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci stdu->base.unit = unit; 17298c2ecf20Sopenharmony_ci crtc = &stdu->base.crtc; 17308c2ecf20Sopenharmony_ci encoder = &stdu->base.encoder; 17318c2ecf20Sopenharmony_ci connector = &stdu->base.connector; 17328c2ecf20Sopenharmony_ci primary = &stdu->base.primary; 17338c2ecf20Sopenharmony_ci cursor = &stdu->base.cursor; 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci stdu->base.pref_active = (unit == 0); 17368c2ecf20Sopenharmony_ci stdu->base.pref_width = dev_priv->initial_width; 17378c2ecf20Sopenharmony_ci stdu->base.pref_height = dev_priv->initial_height; 17388c2ecf20Sopenharmony_ci stdu->base.is_implicit = false; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci /* Initialize primary plane */ 17418c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(dev, primary, 17428c2ecf20Sopenharmony_ci 0, &vmw_stdu_plane_funcs, 17438c2ecf20Sopenharmony_ci vmw_primary_plane_formats, 17448c2ecf20Sopenharmony_ci ARRAY_SIZE(vmw_primary_plane_formats), 17458c2ecf20Sopenharmony_ci NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 17468c2ecf20Sopenharmony_ci if (ret) { 17478c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize primary plane"); 17488c2ecf20Sopenharmony_ci goto err_free; 17498c2ecf20Sopenharmony_ci } 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs); 17528c2ecf20Sopenharmony_ci drm_plane_enable_fb_damage_clips(primary); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci /* Initialize cursor plane */ 17558c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(dev, cursor, 17568c2ecf20Sopenharmony_ci 0, &vmw_stdu_cursor_funcs, 17578c2ecf20Sopenharmony_ci vmw_cursor_plane_formats, 17588c2ecf20Sopenharmony_ci ARRAY_SIZE(vmw_cursor_plane_formats), 17598c2ecf20Sopenharmony_ci NULL, DRM_PLANE_TYPE_CURSOR, NULL); 17608c2ecf20Sopenharmony_ci if (ret) { 17618c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize cursor plane"); 17628c2ecf20Sopenharmony_ci drm_plane_cleanup(&stdu->base.primary); 17638c2ecf20Sopenharmony_ci goto err_free; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci drm_plane_helper_add(cursor, &vmw_stdu_cursor_plane_helper_funcs); 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs, 17698c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 17708c2ecf20Sopenharmony_ci if (ret) { 17718c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize connector\n"); 17728c2ecf20Sopenharmony_ci goto err_free; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs); 17768c2ecf20Sopenharmony_ci connector->status = vmw_du_connector_detect(connector, false); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs, 17798c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 17808c2ecf20Sopenharmony_ci if (ret) { 17818c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize encoder\n"); 17828c2ecf20Sopenharmony_ci goto err_free_connector; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci (void) drm_connector_attach_encoder(connector, encoder); 17868c2ecf20Sopenharmony_ci encoder->possible_crtcs = (1 << unit); 17878c2ecf20Sopenharmony_ci encoder->possible_clones = 0; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci ret = drm_connector_register(connector); 17908c2ecf20Sopenharmony_ci if (ret) { 17918c2ecf20Sopenharmony_ci DRM_ERROR("Failed to register connector\n"); 17928c2ecf20Sopenharmony_ci goto err_free_encoder; 17938c2ecf20Sopenharmony_ci } 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci ret = drm_crtc_init_with_planes(dev, crtc, &stdu->base.primary, 17968c2ecf20Sopenharmony_ci &stdu->base.cursor, 17978c2ecf20Sopenharmony_ci &vmw_stdu_crtc_funcs, NULL); 17988c2ecf20Sopenharmony_ci if (ret) { 17998c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize CRTC\n"); 18008c2ecf20Sopenharmony_ci goto err_free_unregister; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci drm_mode_crtc_set_gamma_size(crtc, 256); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 18088c2ecf20Sopenharmony_ci dev_priv->hotplug_mode_update_property, 1); 18098c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 18108c2ecf20Sopenharmony_ci dev->mode_config.suggested_x_property, 0); 18118c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 18128c2ecf20Sopenharmony_ci dev->mode_config.suggested_y_property, 0); 18138c2ecf20Sopenharmony_ci return 0; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cierr_free_unregister: 18168c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 18178c2ecf20Sopenharmony_cierr_free_encoder: 18188c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 18198c2ecf20Sopenharmony_cierr_free_connector: 18208c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 18218c2ecf20Sopenharmony_cierr_free: 18228c2ecf20Sopenharmony_ci kfree(stdu); 18238c2ecf20Sopenharmony_ci return ret; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci/** 18298c2ecf20Sopenharmony_ci * vmw_stdu_destroy - Cleans up a vmw_screen_target_display_unit 18308c2ecf20Sopenharmony_ci * 18318c2ecf20Sopenharmony_ci * @stdu: Screen Target Display Unit to be destroyed 18328c2ecf20Sopenharmony_ci * 18338c2ecf20Sopenharmony_ci * Clean up after vmw_stdu_init 18348c2ecf20Sopenharmony_ci */ 18358c2ecf20Sopenharmony_cistatic void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu) 18368c2ecf20Sopenharmony_ci{ 18378c2ecf20Sopenharmony_ci vmw_du_cleanup(&stdu->base); 18388c2ecf20Sopenharmony_ci kfree(stdu); 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci/****************************************************************************** 18448c2ecf20Sopenharmony_ci * Screen Target Display KMS Functions 18458c2ecf20Sopenharmony_ci * 18468c2ecf20Sopenharmony_ci * These functions are called by the common KMS code in vmwgfx_kms.c 18478c2ecf20Sopenharmony_ci *****************************************************************************/ 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci/** 18508c2ecf20Sopenharmony_ci * vmw_kms_stdu_init_display - Initializes a Screen Target based display 18518c2ecf20Sopenharmony_ci * 18528c2ecf20Sopenharmony_ci * @dev_priv: VMW DRM device 18538c2ecf20Sopenharmony_ci * 18548c2ecf20Sopenharmony_ci * This function initialize a Screen Target based display device. It checks 18558c2ecf20Sopenharmony_ci * the capability bits to make sure the underlying hardware can support 18568c2ecf20Sopenharmony_ci * screen targets, and then creates the maximum number of CRTCs, a.k.a Display 18578c2ecf20Sopenharmony_ci * Units, as supported by the display hardware. 18588c2ecf20Sopenharmony_ci * 18598c2ecf20Sopenharmony_ci * RETURNS: 18608c2ecf20Sopenharmony_ci * 0 on success, error code otherwise 18618c2ecf20Sopenharmony_ci */ 18628c2ecf20Sopenharmony_ciint vmw_kms_stdu_init_display(struct vmw_private *dev_priv) 18638c2ecf20Sopenharmony_ci{ 18648c2ecf20Sopenharmony_ci struct drm_device *dev = dev_priv->dev; 18658c2ecf20Sopenharmony_ci int i, ret; 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci /* Do nothing if Screen Target support is turned off */ 18698c2ecf20Sopenharmony_ci if (!VMWGFX_ENABLE_SCREEN_TARGET_OTABLE || !dev_priv->has_mob) 18708c2ecf20Sopenharmony_ci return -ENOSYS; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS)) 18738c2ecf20Sopenharmony_ci return -ENOSYS; 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 18768c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 18778c2ecf20Sopenharmony_ci return ret; 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci dev_priv->active_display_unit = vmw_du_screen_target; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) { 18828c2ecf20Sopenharmony_ci ret = vmw_stdu_init(dev_priv, i); 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) { 18858c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize STDU %d", i); 18868c2ecf20Sopenharmony_ci return ret; 18878c2ecf20Sopenharmony_ci } 18888c2ecf20Sopenharmony_ci } 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci drm_mode_config_reset(dev); 18918c2ecf20Sopenharmony_ci 18928c2ecf20Sopenharmony_ci DRM_INFO("Screen Target Display device initialized\n"); 18938c2ecf20Sopenharmony_ci 18948c2ecf20Sopenharmony_ci return 0; 18958c2ecf20Sopenharmony_ci} 1896