18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 28c2ecf20Sopenharmony_ci/************************************************************************** 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright 2011-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 378c2ecf20Sopenharmony_ci#define vmw_crtc_to_sou(x) \ 388c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.crtc) 398c2ecf20Sopenharmony_ci#define vmw_encoder_to_sou(x) \ 408c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.encoder) 418c2ecf20Sopenharmony_ci#define vmw_connector_to_sou(x) \ 428c2ecf20Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.connector) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/** 458c2ecf20Sopenharmony_ci * struct vmw_kms_sou_surface_dirty - Closure structure for 468c2ecf20Sopenharmony_ci * blit surface to screen command. 478c2ecf20Sopenharmony_ci * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). 488c2ecf20Sopenharmony_ci * @left: Left side of bounding box. 498c2ecf20Sopenharmony_ci * @right: Right side of bounding box. 508c2ecf20Sopenharmony_ci * @top: Top side of bounding box. 518c2ecf20Sopenharmony_ci * @bottom: Bottom side of bounding box. 528c2ecf20Sopenharmony_ci * @dst_x: Difference between source clip rects and framebuffer coordinates. 538c2ecf20Sopenharmony_ci * @dst_y: Difference between source clip rects and framebuffer coordinates. 548c2ecf20Sopenharmony_ci * @sid: Surface id of surface to copy from. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistruct vmw_kms_sou_surface_dirty { 578c2ecf20Sopenharmony_ci struct vmw_kms_dirty base; 588c2ecf20Sopenharmony_ci s32 left, right, top, bottom; 598c2ecf20Sopenharmony_ci s32 dst_x, dst_y; 608c2ecf20Sopenharmony_ci u32 sid; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * SVGA commands that are used by this code. Please see the device headers 658c2ecf20Sopenharmony_ci * for explanation. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistruct vmw_kms_sou_readback_blit { 688c2ecf20Sopenharmony_ci uint32 header; 698c2ecf20Sopenharmony_ci SVGAFifoCmdBlitScreenToGMRFB body; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct vmw_kms_sou_bo_blit { 738c2ecf20Sopenharmony_ci uint32 header; 748c2ecf20Sopenharmony_ci SVGAFifoCmdBlitGMRFBToScreen body; 758c2ecf20Sopenharmony_ci}; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct vmw_kms_sou_dirty_cmd { 788c2ecf20Sopenharmony_ci SVGA3dCmdHeader header; 798c2ecf20Sopenharmony_ci SVGA3dCmdBlitSurfaceToScreen body; 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistruct vmw_kms_sou_define_gmrfb { 838c2ecf20Sopenharmony_ci uint32_t header; 848c2ecf20Sopenharmony_ci SVGAFifoCmdDefineGMRFB body; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/** 888c2ecf20Sopenharmony_ci * Display unit using screen objects. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistruct vmw_screen_object_unit { 918c2ecf20Sopenharmony_ci struct vmw_display_unit base; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci unsigned long buffer_size; /**< Size of allocated buffer */ 948c2ecf20Sopenharmony_ci struct vmw_buffer_object *buffer; /**< Backing store buffer */ 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci bool defined; 978c2ecf20Sopenharmony_ci}; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void vmw_sou_destroy(struct vmw_screen_object_unit *sou) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci vmw_du_cleanup(&sou->base); 1028c2ecf20Sopenharmony_ci kfree(sou); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci/* 1078c2ecf20Sopenharmony_ci * Screen Object Display Unit CRTC functions 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic void vmw_sou_crtc_destroy(struct drm_crtc *crtc) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci vmw_sou_destroy(vmw_crtc_to_sou(crtc)); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/** 1168c2ecf20Sopenharmony_ci * Send the fifo command to create a screen. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic int vmw_sou_fifo_create(struct vmw_private *dev_priv, 1198c2ecf20Sopenharmony_ci struct vmw_screen_object_unit *sou, 1208c2ecf20Sopenharmony_ci int x, int y, 1218c2ecf20Sopenharmony_ci struct drm_display_mode *mode) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci size_t fifo_size; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci struct { 1268c2ecf20Sopenharmony_ci struct { 1278c2ecf20Sopenharmony_ci uint32_t cmdType; 1288c2ecf20Sopenharmony_ci } header; 1298c2ecf20Sopenharmony_ci SVGAScreenObject obj; 1308c2ecf20Sopenharmony_ci } *cmd; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci BUG_ON(!sou->buffer); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci fifo_size = sizeof(*cmd); 1358c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, fifo_size); 1368c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 1378c2ecf20Sopenharmony_ci return -ENOMEM; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci memset(cmd, 0, fifo_size); 1408c2ecf20Sopenharmony_ci cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN; 1418c2ecf20Sopenharmony_ci cmd->obj.structSize = sizeof(SVGAScreenObject); 1428c2ecf20Sopenharmony_ci cmd->obj.id = sou->base.unit; 1438c2ecf20Sopenharmony_ci cmd->obj.flags = SVGA_SCREEN_HAS_ROOT | 1448c2ecf20Sopenharmony_ci (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); 1458c2ecf20Sopenharmony_ci cmd->obj.size.width = mode->hdisplay; 1468c2ecf20Sopenharmony_ci cmd->obj.size.height = mode->vdisplay; 1478c2ecf20Sopenharmony_ci cmd->obj.root.x = x; 1488c2ecf20Sopenharmony_ci cmd->obj.root.y = y; 1498c2ecf20Sopenharmony_ci sou->base.set_gui_x = cmd->obj.root.x; 1508c2ecf20Sopenharmony_ci sou->base.set_gui_y = cmd->obj.root.y; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Ok to assume that buffer is pinned in vram */ 1538c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(&sou->buffer->base, &cmd->obj.backingStore.ptr); 1548c2ecf20Sopenharmony_ci cmd->obj.backingStore.pitch = mode->hdisplay * 4; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, fifo_size); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci sou->defined = true; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci/** 1648c2ecf20Sopenharmony_ci * Send the fifo command to destroy a screen. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_cistatic int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, 1678c2ecf20Sopenharmony_ci struct vmw_screen_object_unit *sou) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci size_t fifo_size; 1708c2ecf20Sopenharmony_ci int ret; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci struct { 1738c2ecf20Sopenharmony_ci struct { 1748c2ecf20Sopenharmony_ci uint32_t cmdType; 1758c2ecf20Sopenharmony_ci } header; 1768c2ecf20Sopenharmony_ci SVGAFifoCmdDestroyScreen body; 1778c2ecf20Sopenharmony_ci } *cmd; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* no need to do anything */ 1808c2ecf20Sopenharmony_ci if (unlikely(!sou->defined)) 1818c2ecf20Sopenharmony_ci return 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci fifo_size = sizeof(*cmd); 1848c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, fifo_size); 1858c2ecf20Sopenharmony_ci if (unlikely(cmd == NULL)) 1868c2ecf20Sopenharmony_ci return -ENOMEM; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci memset(cmd, 0, fifo_size); 1898c2ecf20Sopenharmony_ci cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN; 1908c2ecf20Sopenharmony_ci cmd->body.screenId = sou->base.unit; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, fifo_size); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Force sync */ 1958c2ecf20Sopenharmony_ci ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); 1968c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 1978c2ecf20Sopenharmony_ci DRM_ERROR("Failed to sync with HW"); 1988c2ecf20Sopenharmony_ci else 1998c2ecf20Sopenharmony_ci sou->defined = false; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci return ret; 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/** 2058c2ecf20Sopenharmony_ci * vmw_sou_crtc_mode_set_nofb - Create new screen 2068c2ecf20Sopenharmony_ci * 2078c2ecf20Sopenharmony_ci * @crtc: CRTC associated with the new screen 2088c2ecf20Sopenharmony_ci * 2098c2ecf20Sopenharmony_ci * This function creates/destroys a screen. This function cannot fail, so if 2108c2ecf20Sopenharmony_ci * somehow we run into a failure, just do the best we can to get out. 2118c2ecf20Sopenharmony_ci */ 2128c2ecf20Sopenharmony_cistatic void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 2158c2ecf20Sopenharmony_ci struct vmw_screen_object_unit *sou; 2168c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb; 2178c2ecf20Sopenharmony_ci struct drm_framebuffer *fb; 2188c2ecf20Sopenharmony_ci struct drm_plane_state *ps; 2198c2ecf20Sopenharmony_ci struct vmw_plane_state *vps; 2208c2ecf20Sopenharmony_ci int ret; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci sou = vmw_crtc_to_sou(crtc); 2238c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 2248c2ecf20Sopenharmony_ci ps = crtc->primary->state; 2258c2ecf20Sopenharmony_ci fb = ps->fb; 2268c2ecf20Sopenharmony_ci vps = vmw_plane_state_to_vps(ps); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (sou->defined) { 2318c2ecf20Sopenharmony_ci ret = vmw_sou_fifo_destroy(dev_priv, sou); 2328c2ecf20Sopenharmony_ci if (ret) { 2338c2ecf20Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Object\n"); 2348c2ecf20Sopenharmony_ci return; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (vfb) { 2398c2ecf20Sopenharmony_ci struct drm_connector_state *conn_state; 2408c2ecf20Sopenharmony_ci struct vmw_connector_state *vmw_conn_state; 2418c2ecf20Sopenharmony_ci int x, y; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci sou->buffer = vps->bo; 2448c2ecf20Sopenharmony_ci sou->buffer_size = vps->bo_size; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci conn_state = sou->base.connector.state; 2478c2ecf20Sopenharmony_ci vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci x = vmw_conn_state->gui_x; 2508c2ecf20Sopenharmony_ci y = vmw_conn_state->gui_y; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); 2538c2ecf20Sopenharmony_ci if (ret) 2548c2ecf20Sopenharmony_ci DRM_ERROR("Failed to define Screen Object %dx%d\n", 2558c2ecf20Sopenharmony_ci crtc->x, crtc->y); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci } else { 2588c2ecf20Sopenharmony_ci sou->buffer = NULL; 2598c2ecf20Sopenharmony_ci sou->buffer_size = 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * vmw_sou_crtc_helper_prepare - Noop 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * @crtc: CRTC associated with the new screen 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Prepares the CRTC for a mode set, but we don't need to do anything here. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_cistatic void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci} 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci/** 2758c2ecf20Sopenharmony_ci * vmw_sou_crtc_atomic_enable - Noop 2768c2ecf20Sopenharmony_ci * 2778c2ecf20Sopenharmony_ci * @crtc: CRTC associated with the new screen 2788c2ecf20Sopenharmony_ci * 2798c2ecf20Sopenharmony_ci * This is called after a mode set has been completed. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_cistatic void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc, 2828c2ecf20Sopenharmony_ci struct drm_crtc_state *old_state) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * vmw_sou_crtc_atomic_disable - Turns off CRTC 2888c2ecf20Sopenharmony_ci * 2898c2ecf20Sopenharmony_ci * @crtc: CRTC to be turned off 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistatic void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc, 2928c2ecf20Sopenharmony_ci struct drm_crtc_state *old_state) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 2958c2ecf20Sopenharmony_ci struct vmw_screen_object_unit *sou; 2968c2ecf20Sopenharmony_ci int ret; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (!crtc) { 3008c2ecf20Sopenharmony_ci DRM_ERROR("CRTC is NULL\n"); 3018c2ecf20Sopenharmony_ci return; 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci sou = vmw_crtc_to_sou(crtc); 3058c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (sou->defined) { 3088c2ecf20Sopenharmony_ci ret = vmw_sou_fifo_destroy(dev_priv, sou); 3098c2ecf20Sopenharmony_ci if (ret) 3108c2ecf20Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Object\n"); 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { 3158c2ecf20Sopenharmony_ci .gamma_set = vmw_du_crtc_gamma_set, 3168c2ecf20Sopenharmony_ci .destroy = vmw_sou_crtc_destroy, 3178c2ecf20Sopenharmony_ci .reset = vmw_du_crtc_reset, 3188c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 3198c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_crtc_destroy_state, 3208c2ecf20Sopenharmony_ci .set_config = drm_atomic_helper_set_config, 3218c2ecf20Sopenharmony_ci .page_flip = drm_atomic_helper_page_flip, 3228c2ecf20Sopenharmony_ci .get_vblank_counter = vmw_get_vblank_counter, 3238c2ecf20Sopenharmony_ci .enable_vblank = vmw_enable_vblank, 3248c2ecf20Sopenharmony_ci .disable_vblank = vmw_disable_vblank, 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci/* 3288c2ecf20Sopenharmony_ci * Screen Object Display Unit encoder functions 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic void vmw_sou_encoder_destroy(struct drm_encoder *encoder) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci vmw_sou_destroy(vmw_encoder_to_sou(encoder)); 3348c2ecf20Sopenharmony_ci} 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cistatic const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = { 3378c2ecf20Sopenharmony_ci .destroy = vmw_sou_encoder_destroy, 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci/* 3418c2ecf20Sopenharmony_ci * Screen Object Display Unit connector functions 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void vmw_sou_connector_destroy(struct drm_connector *connector) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci vmw_sou_destroy(vmw_connector_to_sou(connector)); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct drm_connector_funcs vmw_sou_connector_funcs = { 3508c2ecf20Sopenharmony_ci .dpms = vmw_du_connector_dpms, 3518c2ecf20Sopenharmony_ci .detect = vmw_du_connector_detect, 3528c2ecf20Sopenharmony_ci .fill_modes = vmw_du_connector_fill_modes, 3538c2ecf20Sopenharmony_ci .destroy = vmw_sou_connector_destroy, 3548c2ecf20Sopenharmony_ci .reset = vmw_du_connector_reset, 3558c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_connector_duplicate_state, 3568c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_connector_destroy_state, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic const struct 3618c2ecf20Sopenharmony_cidrm_connector_helper_funcs vmw_sou_connector_helper_funcs = { 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci/* 3678c2ecf20Sopenharmony_ci * Screen Object Display Plane Functions 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci/** 3718c2ecf20Sopenharmony_ci * vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer 3728c2ecf20Sopenharmony_ci * 3738c2ecf20Sopenharmony_ci * @plane: display plane 3748c2ecf20Sopenharmony_ci * @old_state: Contains the FB to clean up 3758c2ecf20Sopenharmony_ci * 3768c2ecf20Sopenharmony_ci * Unpins the display surface 3778c2ecf20Sopenharmony_ci * 3788c2ecf20Sopenharmony_ci * Returns 0 on success 3798c2ecf20Sopenharmony_ci */ 3808c2ecf20Sopenharmony_cistatic void 3818c2ecf20Sopenharmony_civmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, 3828c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 3858c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc ? 3868c2ecf20Sopenharmony_ci plane->state->crtc : old_state->crtc; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci if (vps->bo) 3898c2ecf20Sopenharmony_ci vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false); 3908c2ecf20Sopenharmony_ci vmw_bo_unreference(&vps->bo); 3918c2ecf20Sopenharmony_ci vps->bo_size = 0; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci vmw_du_plane_cleanup_fb(plane, old_state); 3948c2ecf20Sopenharmony_ci} 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci/** 3988c2ecf20Sopenharmony_ci * vmw_sou_primary_plane_prepare_fb - allocate backing buffer 3998c2ecf20Sopenharmony_ci * 4008c2ecf20Sopenharmony_ci * @plane: display plane 4018c2ecf20Sopenharmony_ci * @new_state: info on the new plane state, including the FB 4028c2ecf20Sopenharmony_ci * 4038c2ecf20Sopenharmony_ci * The SOU backing buffer is our equivalent of the display plane. 4048c2ecf20Sopenharmony_ci * 4058c2ecf20Sopenharmony_ci * Returns 0 on success 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_cistatic int 4088c2ecf20Sopenharmony_civmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, 4098c2ecf20Sopenharmony_ci struct drm_plane_state *new_state) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct drm_framebuffer *new_fb = new_state->fb; 4128c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc; 4138c2ecf20Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 4148c2ecf20Sopenharmony_ci struct vmw_private *dev_priv; 4158c2ecf20Sopenharmony_ci size_t size; 4168c2ecf20Sopenharmony_ci int ret; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci if (!new_fb) { 4208c2ecf20Sopenharmony_ci vmw_bo_unreference(&vps->bo); 4218c2ecf20Sopenharmony_ci vps->bo_size = 0; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci size = new_state->crtc_w * new_state->crtc_h * 4; 4278c2ecf20Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (vps->bo) { 4308c2ecf20Sopenharmony_ci if (vps->bo_size == size) { 4318c2ecf20Sopenharmony_ci /* 4328c2ecf20Sopenharmony_ci * Note that this might temporarily up the pin-count 4338c2ecf20Sopenharmony_ci * to 2, until cleanup_fb() is called. 4348c2ecf20Sopenharmony_ci */ 4358c2ecf20Sopenharmony_ci return vmw_bo_pin_in_vram(dev_priv, vps->bo, 4368c2ecf20Sopenharmony_ci true); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci vmw_bo_unreference(&vps->bo); 4408c2ecf20Sopenharmony_ci vps->bo_size = 0; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci vps->bo = kzalloc(sizeof(*vps->bo), GFP_KERNEL); 4448c2ecf20Sopenharmony_ci if (!vps->bo) 4458c2ecf20Sopenharmony_ci return -ENOMEM; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci vmw_svga_enable(dev_priv); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* After we have alloced the backing store might not be able to 4508c2ecf20Sopenharmony_ci * resume the overlays, this is preferred to failing to alloc. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci vmw_overlay_pause_all(dev_priv); 4538c2ecf20Sopenharmony_ci ret = vmw_bo_init(dev_priv, vps->bo, size, 4548c2ecf20Sopenharmony_ci &vmw_vram_ne_placement, 4558c2ecf20Sopenharmony_ci false, &vmw_bo_bo_free); 4568c2ecf20Sopenharmony_ci vmw_overlay_resume_all(dev_priv); 4578c2ecf20Sopenharmony_ci if (ret) { 4588c2ecf20Sopenharmony_ci vps->bo = NULL; /* vmw_bo_init frees on error */ 4598c2ecf20Sopenharmony_ci return ret; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci vps->bo_size = size; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci /* 4658c2ecf20Sopenharmony_ci * TTM already thinks the buffer is pinned, but make sure the 4668c2ecf20Sopenharmony_ci * pin_count is upped. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, 4728c2ecf20Sopenharmony_ci uint32_t num_hits) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci return sizeof(struct vmw_kms_sou_define_gmrfb) + 4758c2ecf20Sopenharmony_ci sizeof(struct vmw_kms_sou_bo_blit) * num_hits; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update, 4798c2ecf20Sopenharmony_ci void *cmd) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct vmw_framebuffer_bo *vfbbo = 4828c2ecf20Sopenharmony_ci container_of(update->vfb, typeof(*vfbbo), base); 4838c2ecf20Sopenharmony_ci struct vmw_kms_sou_define_gmrfb *gmr = cmd; 4848c2ecf20Sopenharmony_ci int depth = update->vfb->base.format->depth; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* Emulate RGBA support, contrary to svga_reg.h this is not 4878c2ecf20Sopenharmony_ci * supported by hosts. This is only a problem if we are reading 4888c2ecf20Sopenharmony_ci * this value later and expecting what we uploaded back. 4898c2ecf20Sopenharmony_ci */ 4908c2ecf20Sopenharmony_ci if (depth == 32) 4918c2ecf20Sopenharmony_ci depth = 24; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci gmr->header = SVGA_CMD_DEFINE_GMRFB; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8; 4968c2ecf20Sopenharmony_ci gmr->body.format.colorDepth = depth; 4978c2ecf20Sopenharmony_ci gmr->body.format.reserved = 0; 4988c2ecf20Sopenharmony_ci gmr->body.bytesPerLine = update->vfb->base.pitches[0]; 4998c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(&vfbbo->buffer->base, &gmr->body.ptr); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return sizeof(*gmr); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update, 5058c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *clip, 5068c2ecf20Sopenharmony_ci uint32_t fb_x, uint32_t fb_y) 5078c2ecf20Sopenharmony_ci{ 5088c2ecf20Sopenharmony_ci struct vmw_kms_sou_bo_blit *blit = cmd; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 5118c2ecf20Sopenharmony_ci blit->body.destScreenId = update->du->unit; 5128c2ecf20Sopenharmony_ci blit->body.srcOrigin.x = fb_x; 5138c2ecf20Sopenharmony_ci blit->body.srcOrigin.y = fb_y; 5148c2ecf20Sopenharmony_ci blit->body.destRect.left = clip->x1; 5158c2ecf20Sopenharmony_ci blit->body.destRect.top = clip->y1; 5168c2ecf20Sopenharmony_ci blit->body.destRect.right = clip->x2; 5178c2ecf20Sopenharmony_ci blit->body.destRect.bottom = clip->y2; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return sizeof(*blit); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update, 5238c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *bb) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/** 5298c2ecf20Sopenharmony_ci * vmw_sou_plane_update_bo - Update display unit for bo backed fb. 5308c2ecf20Sopenharmony_ci * @dev_priv: Device private. 5318c2ecf20Sopenharmony_ci * @plane: Plane state. 5328c2ecf20Sopenharmony_ci * @old_state: Old plane state. 5338c2ecf20Sopenharmony_ci * @vfb: Framebuffer which is blitted to display unit. 5348c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 5358c2ecf20Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 5368c2ecf20Sopenharmony_ci * has already synchronized. 5378c2ecf20Sopenharmony_ci * 5388c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 5398c2ecf20Sopenharmony_ci */ 5408c2ecf20Sopenharmony_cistatic int vmw_sou_plane_update_bo(struct vmw_private *dev_priv, 5418c2ecf20Sopenharmony_ci struct drm_plane *plane, 5428c2ecf20Sopenharmony_ci struct drm_plane_state *old_state, 5438c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 5448c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct vmw_du_update_plane_buffer bo_update; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); 5498c2ecf20Sopenharmony_ci bo_update.base.plane = plane; 5508c2ecf20Sopenharmony_ci bo_update.base.old_state = old_state; 5518c2ecf20Sopenharmony_ci bo_update.base.dev_priv = dev_priv; 5528c2ecf20Sopenharmony_ci bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); 5538c2ecf20Sopenharmony_ci bo_update.base.vfb = vfb; 5548c2ecf20Sopenharmony_ci bo_update.base.out_fence = out_fence; 5558c2ecf20Sopenharmony_ci bo_update.base.mutex = NULL; 5568c2ecf20Sopenharmony_ci bo_update.base.cpu_blit = false; 5578c2ecf20Sopenharmony_ci bo_update.base.intr = true; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size; 5608c2ecf20Sopenharmony_ci bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb; 5618c2ecf20Sopenharmony_ci bo_update.base.clip = vmw_sou_bo_populate_clip; 5628c2ecf20Sopenharmony_ci bo_update.base.post_clip = vmw_stud_bo_post_clip; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return vmw_du_helper_plane_update(&bo_update.base); 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update, 5688c2ecf20Sopenharmony_ci uint32_t num_hits) 5698c2ecf20Sopenharmony_ci{ 5708c2ecf20Sopenharmony_ci return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * 5718c2ecf20Sopenharmony_ci num_hits; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update, 5758c2ecf20Sopenharmony_ci void *cmd) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci struct vmw_du_update_plane_surface *srf_update; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci srf_update = container_of(update, typeof(*srf_update), base); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* 5828c2ecf20Sopenharmony_ci * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that 5838c2ecf20Sopenharmony_ci * its bounding box is filled before iterating over all the clips. So 5848c2ecf20Sopenharmony_ci * store the FIFO start address and revisit to fill the details. 5858c2ecf20Sopenharmony_ci */ 5868c2ecf20Sopenharmony_ci srf_update->cmd_start = cmd; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return 0; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update, 5928c2ecf20Sopenharmony_ci void *cmd, uint32_t num_hits) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *blit = cmd; 5958c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; 6008c2ecf20Sopenharmony_ci blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * 6018c2ecf20Sopenharmony_ci num_hits; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci blit->body.srcImage.sid = vfbs->surface->res.id; 6048c2ecf20Sopenharmony_ci blit->body.destScreenId = update->du->unit; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* Update the source and destination bounding box later in post_clip */ 6078c2ecf20Sopenharmony_ci blit->body.srcRect.left = 0; 6088c2ecf20Sopenharmony_ci blit->body.srcRect.top = 0; 6098c2ecf20Sopenharmony_ci blit->body.srcRect.right = 0; 6108c2ecf20Sopenharmony_ci blit->body.srcRect.bottom = 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci blit->body.destRect.left = 0; 6138c2ecf20Sopenharmony_ci blit->body.destRect.top = 0; 6148c2ecf20Sopenharmony_ci blit->body.destRect.right = 0; 6158c2ecf20Sopenharmony_ci blit->body.destRect.bottom = 0; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci return sizeof(*blit); 6188c2ecf20Sopenharmony_ci} 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update, 6218c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *clip, 6228c2ecf20Sopenharmony_ci uint32_t src_x, uint32_t src_y) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci SVGASignedRect *rect = cmd; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* 6278c2ecf20Sopenharmony_ci * rects are relative to dest bounding box rect on screen object, so 6288c2ecf20Sopenharmony_ci * translate to it later in post_clip 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci rect->left = clip->x1; 6318c2ecf20Sopenharmony_ci rect->top = clip->y1; 6328c2ecf20Sopenharmony_ci rect->right = clip->x2; 6338c2ecf20Sopenharmony_ci rect->bottom = clip->y2; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return sizeof(*rect); 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update, 6398c2ecf20Sopenharmony_ci void *cmd, struct drm_rect *bb) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct vmw_du_update_plane_surface *srf_update; 6428c2ecf20Sopenharmony_ci struct drm_plane_state *state = update->plane->state; 6438c2ecf20Sopenharmony_ci struct drm_rect src_bb; 6448c2ecf20Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *blit; 6458c2ecf20Sopenharmony_ci SVGASignedRect *rect; 6468c2ecf20Sopenharmony_ci uint32_t num_hits; 6478c2ecf20Sopenharmony_ci int translate_src_x; 6488c2ecf20Sopenharmony_ci int translate_src_y; 6498c2ecf20Sopenharmony_ci int i; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci srf_update = container_of(update, typeof(*srf_update), base); 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci blit = srf_update->cmd_start; 6548c2ecf20Sopenharmony_ci rect = (SVGASignedRect *)&blit[1]; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci num_hits = (blit->header.size - sizeof(blit->body))/ 6578c2ecf20Sopenharmony_ci sizeof(SVGASignedRect); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci src_bb = *bb; 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* To translate bb back to fb src coord */ 6628c2ecf20Sopenharmony_ci translate_src_x = (state->src_x >> 16) - state->crtc_x; 6638c2ecf20Sopenharmony_ci translate_src_y = (state->src_y >> 16) - state->crtc_y; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci drm_rect_translate(&src_bb, translate_src_x, translate_src_y); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci blit->body.srcRect.left = src_bb.x1; 6688c2ecf20Sopenharmony_ci blit->body.srcRect.top = src_bb.y1; 6698c2ecf20Sopenharmony_ci blit->body.srcRect.right = src_bb.x2; 6708c2ecf20Sopenharmony_ci blit->body.srcRect.bottom = src_bb.y2; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci blit->body.destRect.left = bb->x1; 6738c2ecf20Sopenharmony_ci blit->body.destRect.top = bb->y1; 6748c2ecf20Sopenharmony_ci blit->body.destRect.right = bb->x2; 6758c2ecf20Sopenharmony_ci blit->body.destRect.bottom = bb->y2; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* rects are relative to dest bb rect */ 6788c2ecf20Sopenharmony_ci for (i = 0; i < num_hits; i++) { 6798c2ecf20Sopenharmony_ci rect->left -= bb->x1; 6808c2ecf20Sopenharmony_ci rect->top -= bb->y1; 6818c2ecf20Sopenharmony_ci rect->right -= bb->x1; 6828c2ecf20Sopenharmony_ci rect->bottom -= bb->y1; 6838c2ecf20Sopenharmony_ci rect++; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci return 0; 6878c2ecf20Sopenharmony_ci} 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci/** 6908c2ecf20Sopenharmony_ci * vmw_sou_plane_update_surface - Update display unit for surface backed fb. 6918c2ecf20Sopenharmony_ci * @dev_priv: Device private. 6928c2ecf20Sopenharmony_ci * @plane: Plane state. 6938c2ecf20Sopenharmony_ci * @old_state: Old plane state. 6948c2ecf20Sopenharmony_ci * @vfb: Framebuffer which is blitted to display unit 6958c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 6968c2ecf20Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 6978c2ecf20Sopenharmony_ci * has already synchronized. 6988c2ecf20Sopenharmony_ci * 6998c2ecf20Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 7008c2ecf20Sopenharmony_ci */ 7018c2ecf20Sopenharmony_cistatic int vmw_sou_plane_update_surface(struct vmw_private *dev_priv, 7028c2ecf20Sopenharmony_ci struct drm_plane *plane, 7038c2ecf20Sopenharmony_ci struct drm_plane_state *old_state, 7048c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 7058c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci struct vmw_du_update_plane_surface srf_update; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface)); 7108c2ecf20Sopenharmony_ci srf_update.base.plane = plane; 7118c2ecf20Sopenharmony_ci srf_update.base.old_state = old_state; 7128c2ecf20Sopenharmony_ci srf_update.base.dev_priv = dev_priv; 7138c2ecf20Sopenharmony_ci srf_update.base.du = vmw_crtc_to_du(plane->state->crtc); 7148c2ecf20Sopenharmony_ci srf_update.base.vfb = vfb; 7158c2ecf20Sopenharmony_ci srf_update.base.out_fence = out_fence; 7168c2ecf20Sopenharmony_ci srf_update.base.mutex = &dev_priv->cmdbuf_mutex; 7178c2ecf20Sopenharmony_ci srf_update.base.cpu_blit = false; 7188c2ecf20Sopenharmony_ci srf_update.base.intr = true; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size; 7218c2ecf20Sopenharmony_ci srf_update.base.post_prepare = vmw_sou_surface_post_prepare; 7228c2ecf20Sopenharmony_ci srf_update.base.pre_clip = vmw_sou_surface_pre_clip; 7238c2ecf20Sopenharmony_ci srf_update.base.clip = vmw_sou_surface_clip_rect; 7248c2ecf20Sopenharmony_ci srf_update.base.post_clip = vmw_sou_surface_post_clip; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return vmw_du_helper_plane_update(&srf_update.base); 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic void 7308c2ecf20Sopenharmony_civmw_sou_primary_plane_atomic_update(struct drm_plane *plane, 7318c2ecf20Sopenharmony_ci struct drm_plane_state *old_state) 7328c2ecf20Sopenharmony_ci{ 7338c2ecf20Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc; 7348c2ecf20Sopenharmony_ci struct drm_pending_vblank_event *event = NULL; 7358c2ecf20Sopenharmony_ci struct vmw_fence_obj *fence = NULL; 7368c2ecf20Sopenharmony_ci int ret; 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci /* In case of device error, maintain consistent atomic state */ 7398c2ecf20Sopenharmony_ci if (crtc && plane->state->fb) { 7408c2ecf20Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(crtc->dev); 7418c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb = 7428c2ecf20Sopenharmony_ci vmw_framebuffer_to_vfb(plane->state->fb); 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci if (vfb->bo) 7458c2ecf20Sopenharmony_ci ret = vmw_sou_plane_update_bo(dev_priv, plane, 7468c2ecf20Sopenharmony_ci old_state, vfb, &fence); 7478c2ecf20Sopenharmony_ci else 7488c2ecf20Sopenharmony_ci ret = vmw_sou_plane_update_surface(dev_priv, plane, 7498c2ecf20Sopenharmony_ci old_state, vfb, 7508c2ecf20Sopenharmony_ci &fence); 7518c2ecf20Sopenharmony_ci if (ret != 0) 7528c2ecf20Sopenharmony_ci DRM_ERROR("Failed to update screen.\n"); 7538c2ecf20Sopenharmony_ci } else { 7548c2ecf20Sopenharmony_ci /* Do nothing when fb and crtc is NULL (blank crtc) */ 7558c2ecf20Sopenharmony_ci return; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* For error case vblank event is send from vmw_du_crtc_atomic_flush */ 7598c2ecf20Sopenharmony_ci event = crtc->state->event; 7608c2ecf20Sopenharmony_ci if (event && fence) { 7618c2ecf20Sopenharmony_ci struct drm_file *file_priv = event->base.file_priv; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ret = vmw_event_fence_action_queue(file_priv, 7648c2ecf20Sopenharmony_ci fence, 7658c2ecf20Sopenharmony_ci &event->base, 7668c2ecf20Sopenharmony_ci &event->event.vbl.tv_sec, 7678c2ecf20Sopenharmony_ci &event->event.vbl.tv_usec, 7688c2ecf20Sopenharmony_ci true); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 7718c2ecf20Sopenharmony_ci DRM_ERROR("Failed to queue event on fence.\n"); 7728c2ecf20Sopenharmony_ci else 7738c2ecf20Sopenharmony_ci crtc->state->event = NULL; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (fence) 7778c2ecf20Sopenharmony_ci vmw_fence_obj_unreference(&fence); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs vmw_sou_plane_funcs = { 7828c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 7838c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 7848c2ecf20Sopenharmony_ci .destroy = vmw_du_primary_plane_destroy, 7858c2ecf20Sopenharmony_ci .reset = vmw_du_plane_reset, 7868c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 7878c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 7888c2ecf20Sopenharmony_ci}; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic const struct drm_plane_funcs vmw_sou_cursor_funcs = { 7918c2ecf20Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 7928c2ecf20Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 7938c2ecf20Sopenharmony_ci .destroy = vmw_du_cursor_plane_destroy, 7948c2ecf20Sopenharmony_ci .reset = vmw_du_plane_reset, 7958c2ecf20Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 7968c2ecf20Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 7978c2ecf20Sopenharmony_ci}; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci/* 8008c2ecf20Sopenharmony_ci * Atomic Helpers 8018c2ecf20Sopenharmony_ci */ 8028c2ecf20Sopenharmony_cistatic const struct 8038c2ecf20Sopenharmony_cidrm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = { 8048c2ecf20Sopenharmony_ci .atomic_check = vmw_du_cursor_plane_atomic_check, 8058c2ecf20Sopenharmony_ci .atomic_update = vmw_du_cursor_plane_atomic_update, 8068c2ecf20Sopenharmony_ci .prepare_fb = vmw_du_cursor_plane_prepare_fb, 8078c2ecf20Sopenharmony_ci .cleanup_fb = vmw_du_plane_cleanup_fb, 8088c2ecf20Sopenharmony_ci}; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_cistatic const struct 8118c2ecf20Sopenharmony_cidrm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = { 8128c2ecf20Sopenharmony_ci .atomic_check = vmw_du_primary_plane_atomic_check, 8138c2ecf20Sopenharmony_ci .atomic_update = vmw_sou_primary_plane_atomic_update, 8148c2ecf20Sopenharmony_ci .prepare_fb = vmw_sou_primary_plane_prepare_fb, 8158c2ecf20Sopenharmony_ci .cleanup_fb = vmw_sou_primary_plane_cleanup_fb, 8168c2ecf20Sopenharmony_ci}; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { 8198c2ecf20Sopenharmony_ci .prepare = vmw_sou_crtc_helper_prepare, 8208c2ecf20Sopenharmony_ci .mode_set_nofb = vmw_sou_crtc_mode_set_nofb, 8218c2ecf20Sopenharmony_ci .atomic_check = vmw_du_crtc_atomic_check, 8228c2ecf20Sopenharmony_ci .atomic_begin = vmw_du_crtc_atomic_begin, 8238c2ecf20Sopenharmony_ci .atomic_flush = vmw_du_crtc_atomic_flush, 8248c2ecf20Sopenharmony_ci .atomic_enable = vmw_sou_crtc_atomic_enable, 8258c2ecf20Sopenharmony_ci .atomic_disable = vmw_sou_crtc_atomic_disable, 8268c2ecf20Sopenharmony_ci}; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci struct vmw_screen_object_unit *sou; 8328c2ecf20Sopenharmony_ci struct drm_device *dev = dev_priv->dev; 8338c2ecf20Sopenharmony_ci struct drm_connector *connector; 8348c2ecf20Sopenharmony_ci struct drm_encoder *encoder; 8358c2ecf20Sopenharmony_ci struct drm_plane *primary, *cursor; 8368c2ecf20Sopenharmony_ci struct drm_crtc *crtc; 8378c2ecf20Sopenharmony_ci int ret; 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci sou = kzalloc(sizeof(*sou), GFP_KERNEL); 8408c2ecf20Sopenharmony_ci if (!sou) 8418c2ecf20Sopenharmony_ci return -ENOMEM; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci sou->base.unit = unit; 8448c2ecf20Sopenharmony_ci crtc = &sou->base.crtc; 8458c2ecf20Sopenharmony_ci encoder = &sou->base.encoder; 8468c2ecf20Sopenharmony_ci connector = &sou->base.connector; 8478c2ecf20Sopenharmony_ci primary = &sou->base.primary; 8488c2ecf20Sopenharmony_ci cursor = &sou->base.cursor; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci sou->base.pref_active = (unit == 0); 8518c2ecf20Sopenharmony_ci sou->base.pref_width = dev_priv->initial_width; 8528c2ecf20Sopenharmony_ci sou->base.pref_height = dev_priv->initial_height; 8538c2ecf20Sopenharmony_ci sou->base.pref_mode = NULL; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci /* 8568c2ecf20Sopenharmony_ci * Remove this after enabling atomic because property values can 8578c2ecf20Sopenharmony_ci * only exist in a state object 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci sou->base.is_implicit = false; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* Initialize primary plane */ 8628c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(dev, &sou->base.primary, 8638c2ecf20Sopenharmony_ci 0, &vmw_sou_plane_funcs, 8648c2ecf20Sopenharmony_ci vmw_primary_plane_formats, 8658c2ecf20Sopenharmony_ci ARRAY_SIZE(vmw_primary_plane_formats), 8668c2ecf20Sopenharmony_ci NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 8678c2ecf20Sopenharmony_ci if (ret) { 8688c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize primary plane"); 8698c2ecf20Sopenharmony_ci goto err_free; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); 8738c2ecf20Sopenharmony_ci drm_plane_enable_fb_damage_clips(primary); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Initialize cursor plane */ 8768c2ecf20Sopenharmony_ci ret = drm_universal_plane_init(dev, &sou->base.cursor, 8778c2ecf20Sopenharmony_ci 0, &vmw_sou_cursor_funcs, 8788c2ecf20Sopenharmony_ci vmw_cursor_plane_formats, 8798c2ecf20Sopenharmony_ci ARRAY_SIZE(vmw_cursor_plane_formats), 8808c2ecf20Sopenharmony_ci NULL, DRM_PLANE_TYPE_CURSOR, NULL); 8818c2ecf20Sopenharmony_ci if (ret) { 8828c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize cursor plane"); 8838c2ecf20Sopenharmony_ci drm_plane_cleanup(&sou->base.primary); 8848c2ecf20Sopenharmony_ci goto err_free; 8858c2ecf20Sopenharmony_ci } 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci drm_plane_helper_add(cursor, &vmw_sou_cursor_plane_helper_funcs); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs, 8908c2ecf20Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 8918c2ecf20Sopenharmony_ci if (ret) { 8928c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize connector\n"); 8938c2ecf20Sopenharmony_ci goto err_free; 8948c2ecf20Sopenharmony_ci } 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); 8978c2ecf20Sopenharmony_ci connector->status = vmw_du_connector_detect(connector, true); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, 9008c2ecf20Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 9018c2ecf20Sopenharmony_ci if (ret) { 9028c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize encoder\n"); 9038c2ecf20Sopenharmony_ci goto err_free_connector; 9048c2ecf20Sopenharmony_ci } 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci (void) drm_connector_attach_encoder(connector, encoder); 9078c2ecf20Sopenharmony_ci encoder->possible_crtcs = (1 << unit); 9088c2ecf20Sopenharmony_ci encoder->possible_clones = 0; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci ret = drm_connector_register(connector); 9118c2ecf20Sopenharmony_ci if (ret) { 9128c2ecf20Sopenharmony_ci DRM_ERROR("Failed to register connector\n"); 9138c2ecf20Sopenharmony_ci goto err_free_encoder; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci ret = drm_crtc_init_with_planes(dev, crtc, &sou->base.primary, 9178c2ecf20Sopenharmony_ci &sou->base.cursor, 9188c2ecf20Sopenharmony_ci &vmw_screen_object_crtc_funcs, NULL); 9198c2ecf20Sopenharmony_ci if (ret) { 9208c2ecf20Sopenharmony_ci DRM_ERROR("Failed to initialize CRTC\n"); 9218c2ecf20Sopenharmony_ci goto err_free_unregister; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci drm_mode_crtc_set_gamma_size(crtc, 256); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 9298c2ecf20Sopenharmony_ci dev_priv->hotplug_mode_update_property, 1); 9308c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 9318c2ecf20Sopenharmony_ci dev->mode_config.suggested_x_property, 0); 9328c2ecf20Sopenharmony_ci drm_object_attach_property(&connector->base, 9338c2ecf20Sopenharmony_ci dev->mode_config.suggested_y_property, 0); 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cierr_free_unregister: 9378c2ecf20Sopenharmony_ci drm_connector_unregister(connector); 9388c2ecf20Sopenharmony_cierr_free_encoder: 9398c2ecf20Sopenharmony_ci drm_encoder_cleanup(encoder); 9408c2ecf20Sopenharmony_cierr_free_connector: 9418c2ecf20Sopenharmony_ci drm_connector_cleanup(connector); 9428c2ecf20Sopenharmony_cierr_free: 9438c2ecf20Sopenharmony_ci kfree(sou); 9448c2ecf20Sopenharmony_ci return ret; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ciint vmw_kms_sou_init_display(struct vmw_private *dev_priv) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct drm_device *dev = dev_priv->dev; 9508c2ecf20Sopenharmony_ci int i, ret; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Screen objects won't work if GMR's aren't available */ 9538c2ecf20Sopenharmony_ci if (!dev_priv->has_gmr) 9548c2ecf20Sopenharmony_ci return -ENOSYS; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { 9578c2ecf20Sopenharmony_ci DRM_INFO("Not using screen objects," 9588c2ecf20Sopenharmony_ci " missing cap SCREEN_OBJECT_2\n"); 9598c2ecf20Sopenharmony_ci return -ENOSYS; 9608c2ecf20Sopenharmony_ci } 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = -ENOMEM; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci ret = drm_vblank_init(dev, VMWGFX_NUM_DISPLAY_UNITS); 9658c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 9668c2ecf20Sopenharmony_ci return ret; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 9698c2ecf20Sopenharmony_ci vmw_sou_init(dev_priv, i); 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci dev_priv->active_display_unit = vmw_du_screen_object; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci drm_mode_config_reset(dev); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci DRM_INFO("Screen Objects Display Unit initialized\n"); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci return 0; 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_cistatic int do_bo_define_gmrfb(struct vmw_private *dev_priv, 9818c2ecf20Sopenharmony_ci struct vmw_framebuffer *framebuffer) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct vmw_buffer_object *buf = 9848c2ecf20Sopenharmony_ci container_of(framebuffer, struct vmw_framebuffer_bo, 9858c2ecf20Sopenharmony_ci base)->buffer; 9868c2ecf20Sopenharmony_ci int depth = framebuffer->base.format->depth; 9878c2ecf20Sopenharmony_ci struct { 9888c2ecf20Sopenharmony_ci uint32_t header; 9898c2ecf20Sopenharmony_ci SVGAFifoCmdDefineGMRFB body; 9908c2ecf20Sopenharmony_ci } *cmd; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Emulate RGBA support, contrary to svga_reg.h this is not 9938c2ecf20Sopenharmony_ci * supported by hosts. This is only a problem if we are reading 9948c2ecf20Sopenharmony_ci * this value later and expecting what we uploaded back. 9958c2ecf20Sopenharmony_ci */ 9968c2ecf20Sopenharmony_ci if (depth == 32) 9978c2ecf20Sopenharmony_ci depth = 24; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci cmd = VMW_FIFO_RESERVE(dev_priv, sizeof(*cmd)); 10008c2ecf20Sopenharmony_ci if (!cmd) 10018c2ecf20Sopenharmony_ci return -ENOMEM; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci cmd->header = SVGA_CMD_DEFINE_GMRFB; 10048c2ecf20Sopenharmony_ci cmd->body.format.bitsPerPixel = framebuffer->base.format->cpp[0] * 8; 10058c2ecf20Sopenharmony_ci cmd->body.format.colorDepth = depth; 10068c2ecf20Sopenharmony_ci cmd->body.format.reserved = 0; 10078c2ecf20Sopenharmony_ci cmd->body.bytesPerLine = framebuffer->base.pitches[0]; 10088c2ecf20Sopenharmony_ci /* Buffer is reserved in vram or GMR */ 10098c2ecf20Sopenharmony_ci vmw_bo_get_guest_ptr(&buf->base, &cmd->body.ptr); 10108c2ecf20Sopenharmony_ci vmw_fifo_commit(dev_priv, sizeof(*cmd)); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci return 0; 10138c2ecf20Sopenharmony_ci} 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci/** 10168c2ecf20Sopenharmony_ci * vmw_sou_surface_fifo_commit - Callback to fill in and submit a 10178c2ecf20Sopenharmony_ci * blit surface to screen command. 10188c2ecf20Sopenharmony_ci * 10198c2ecf20Sopenharmony_ci * @dirty: The closure structure. 10208c2ecf20Sopenharmony_ci * 10218c2ecf20Sopenharmony_ci * Fills in the missing fields in the command, and translates the cliprects 10228c2ecf20Sopenharmony_ci * to match the destination bounding box encoded. 10238c2ecf20Sopenharmony_ci */ 10248c2ecf20Sopenharmony_cistatic void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci struct vmw_kms_sou_surface_dirty *sdirty = 10278c2ecf20Sopenharmony_ci container_of(dirty, typeof(*sdirty), base); 10288c2ecf20Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; 10298c2ecf20Sopenharmony_ci s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x; 10308c2ecf20Sopenharmony_ci s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y; 10318c2ecf20Sopenharmony_ci size_t region_size = dirty->num_hits * sizeof(SVGASignedRect); 10328c2ecf20Sopenharmony_ci SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; 10338c2ecf20Sopenharmony_ci int i; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci if (!dirty->num_hits) { 10368c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 0); 10378c2ecf20Sopenharmony_ci return; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; 10418c2ecf20Sopenharmony_ci cmd->header.size = sizeof(cmd->body) + region_size; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci /* 10448c2ecf20Sopenharmony_ci * Use the destination bounding box to specify destination - and 10458c2ecf20Sopenharmony_ci * source bounding regions. 10468c2ecf20Sopenharmony_ci */ 10478c2ecf20Sopenharmony_ci cmd->body.destRect.left = sdirty->left; 10488c2ecf20Sopenharmony_ci cmd->body.destRect.right = sdirty->right; 10498c2ecf20Sopenharmony_ci cmd->body.destRect.top = sdirty->top; 10508c2ecf20Sopenharmony_ci cmd->body.destRect.bottom = sdirty->bottom; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci cmd->body.srcRect.left = sdirty->left + trans_x; 10538c2ecf20Sopenharmony_ci cmd->body.srcRect.right = sdirty->right + trans_x; 10548c2ecf20Sopenharmony_ci cmd->body.srcRect.top = sdirty->top + trans_y; 10558c2ecf20Sopenharmony_ci cmd->body.srcRect.bottom = sdirty->bottom + trans_y; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci cmd->body.srcImage.sid = sdirty->sid; 10588c2ecf20Sopenharmony_ci cmd->body.destScreenId = dirty->unit->unit; 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci /* Blits are relative to the destination rect. Translate. */ 10618c2ecf20Sopenharmony_ci for (i = 0; i < dirty->num_hits; ++i, ++blit) { 10628c2ecf20Sopenharmony_ci blit->left -= sdirty->left; 10638c2ecf20Sopenharmony_ci blit->right -= sdirty->left; 10648c2ecf20Sopenharmony_ci blit->top -= sdirty->top; 10658c2ecf20Sopenharmony_ci blit->bottom -= sdirty->top; 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, region_size + sizeof(*cmd)); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci sdirty->left = sdirty->top = S32_MAX; 10718c2ecf20Sopenharmony_ci sdirty->right = sdirty->bottom = S32_MIN; 10728c2ecf20Sopenharmony_ci} 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci/** 10758c2ecf20Sopenharmony_ci * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect. 10768c2ecf20Sopenharmony_ci * 10778c2ecf20Sopenharmony_ci * @dirty: The closure structure 10788c2ecf20Sopenharmony_ci * 10798c2ecf20Sopenharmony_ci * Encodes a SVGASignedRect cliprect and updates the bounding box of the 10808c2ecf20Sopenharmony_ci * BLIT_SURFACE_TO_SCREEN command. 10818c2ecf20Sopenharmony_ci */ 10828c2ecf20Sopenharmony_cistatic void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty) 10838c2ecf20Sopenharmony_ci{ 10848c2ecf20Sopenharmony_ci struct vmw_kms_sou_surface_dirty *sdirty = 10858c2ecf20Sopenharmony_ci container_of(dirty, typeof(*sdirty), base); 10868c2ecf20Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; 10878c2ecf20Sopenharmony_ci SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci /* Destination rect. */ 10908c2ecf20Sopenharmony_ci blit += dirty->num_hits; 10918c2ecf20Sopenharmony_ci blit->left = dirty->unit_x1; 10928c2ecf20Sopenharmony_ci blit->top = dirty->unit_y1; 10938c2ecf20Sopenharmony_ci blit->right = dirty->unit_x2; 10948c2ecf20Sopenharmony_ci blit->bottom = dirty->unit_y2; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* Destination bounding box */ 10978c2ecf20Sopenharmony_ci sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1); 10988c2ecf20Sopenharmony_ci sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1); 10998c2ecf20Sopenharmony_ci sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2); 11008c2ecf20Sopenharmony_ci sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci dirty->num_hits++; 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/** 11068c2ecf20Sopenharmony_ci * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer 11078c2ecf20Sopenharmony_ci * 11088c2ecf20Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 11098c2ecf20Sopenharmony_ci * @framebuffer: Pointer to the surface-buffer backed framebuffer. 11108c2ecf20Sopenharmony_ci * @clips: Array of clip rects. Either @clips or @vclips must be NULL. 11118c2ecf20Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 11128c2ecf20Sopenharmony_ci * be NULL. 11138c2ecf20Sopenharmony_ci * @srf: Pointer to surface to blit from. If NULL, the surface attached 11148c2ecf20Sopenharmony_ci * to @framebuffer will be used. 11158c2ecf20Sopenharmony_ci * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. 11168c2ecf20Sopenharmony_ci * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. 11178c2ecf20Sopenharmony_ci * @num_clips: Number of clip rects in @clips. 11188c2ecf20Sopenharmony_ci * @inc: Increment to use when looping over @clips. 11198c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to a 11208c2ecf20Sopenharmony_ci * struct vmw_fence_obj. The returned fence pointer may be NULL in which 11218c2ecf20Sopenharmony_ci * case the device has already synchronized. 11228c2ecf20Sopenharmony_ci * @crtc: If crtc is passed, perform surface dirty on that crtc only. 11238c2ecf20Sopenharmony_ci * 11248c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 11258c2ecf20Sopenharmony_ci * interrupted. 11268c2ecf20Sopenharmony_ci */ 11278c2ecf20Sopenharmony_ciint vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, 11288c2ecf20Sopenharmony_ci struct vmw_framebuffer *framebuffer, 11298c2ecf20Sopenharmony_ci struct drm_clip_rect *clips, 11308c2ecf20Sopenharmony_ci struct drm_vmw_rect *vclips, 11318c2ecf20Sopenharmony_ci struct vmw_resource *srf, 11328c2ecf20Sopenharmony_ci s32 dest_x, 11338c2ecf20Sopenharmony_ci s32 dest_y, 11348c2ecf20Sopenharmony_ci unsigned num_clips, int inc, 11358c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence, 11368c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci struct vmw_framebuffer_surface *vfbs = 11398c2ecf20Sopenharmony_ci container_of(framebuffer, typeof(*vfbs), base); 11408c2ecf20Sopenharmony_ci struct vmw_kms_sou_surface_dirty sdirty; 11418c2ecf20Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 11428c2ecf20Sopenharmony_ci int ret; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (!srf) 11458c2ecf20Sopenharmony_ci srf = &vfbs->surface->res; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_ci ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, 11488c2ecf20Sopenharmony_ci NULL, NULL); 11498c2ecf20Sopenharmony_ci if (ret) 11508c2ecf20Sopenharmony_ci return ret; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); 11538c2ecf20Sopenharmony_ci if (ret) 11548c2ecf20Sopenharmony_ci goto out_unref; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit; 11578c2ecf20Sopenharmony_ci sdirty.base.clip = vmw_sou_surface_clip; 11588c2ecf20Sopenharmony_ci sdirty.base.dev_priv = dev_priv; 11598c2ecf20Sopenharmony_ci sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + 11608c2ecf20Sopenharmony_ci sizeof(SVGASignedRect) * num_clips; 11618c2ecf20Sopenharmony_ci sdirty.base.crtc = crtc; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci sdirty.sid = srf->id; 11648c2ecf20Sopenharmony_ci sdirty.left = sdirty.top = S32_MAX; 11658c2ecf20Sopenharmony_ci sdirty.right = sdirty.bottom = S32_MIN; 11668c2ecf20Sopenharmony_ci sdirty.dst_x = dest_x; 11678c2ecf20Sopenharmony_ci sdirty.dst_y = dest_y; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 11708c2ecf20Sopenharmony_ci dest_x, dest_y, num_clips, inc, 11718c2ecf20Sopenharmony_ci &sdirty.base); 11728c2ecf20Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 11738c2ecf20Sopenharmony_ci NULL); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci return ret; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ciout_unref: 11788c2ecf20Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 11798c2ecf20Sopenharmony_ci return ret; 11808c2ecf20Sopenharmony_ci} 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci/** 11838c2ecf20Sopenharmony_ci * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips. 11848c2ecf20Sopenharmony_ci * 11858c2ecf20Sopenharmony_ci * @dirty: The closure structure. 11868c2ecf20Sopenharmony_ci * 11878c2ecf20Sopenharmony_ci * Commits a previously built command buffer of readback clips. 11888c2ecf20Sopenharmony_ci */ 11898c2ecf20Sopenharmony_cistatic void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci if (!dirty->num_hits) { 11928c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 0); 11938c2ecf20Sopenharmony_ci return; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 11978c2ecf20Sopenharmony_ci sizeof(struct vmw_kms_sou_bo_blit) * 11988c2ecf20Sopenharmony_ci dirty->num_hits); 11998c2ecf20Sopenharmony_ci} 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci/** 12028c2ecf20Sopenharmony_ci * vmw_sou_bo_clip - Callback to encode a readback cliprect. 12038c2ecf20Sopenharmony_ci * 12048c2ecf20Sopenharmony_ci * @dirty: The closure structure 12058c2ecf20Sopenharmony_ci * 12068c2ecf20Sopenharmony_ci * Encodes a BLIT_GMRFB_TO_SCREEN cliprect. 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_cistatic void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty) 12098c2ecf20Sopenharmony_ci{ 12108c2ecf20Sopenharmony_ci struct vmw_kms_sou_bo_blit *blit = dirty->cmd; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_ci blit += dirty->num_hits; 12138c2ecf20Sopenharmony_ci blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 12148c2ecf20Sopenharmony_ci blit->body.destScreenId = dirty->unit->unit; 12158c2ecf20Sopenharmony_ci blit->body.srcOrigin.x = dirty->fb_x; 12168c2ecf20Sopenharmony_ci blit->body.srcOrigin.y = dirty->fb_y; 12178c2ecf20Sopenharmony_ci blit->body.destRect.left = dirty->unit_x1; 12188c2ecf20Sopenharmony_ci blit->body.destRect.top = dirty->unit_y1; 12198c2ecf20Sopenharmony_ci blit->body.destRect.right = dirty->unit_x2; 12208c2ecf20Sopenharmony_ci blit->body.destRect.bottom = dirty->unit_y2; 12218c2ecf20Sopenharmony_ci dirty->num_hits++; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/** 12258c2ecf20Sopenharmony_ci * vmw_kms_do_bo_dirty - Dirty part of a buffer-object backed framebuffer 12268c2ecf20Sopenharmony_ci * 12278c2ecf20Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 12288c2ecf20Sopenharmony_ci * @framebuffer: Pointer to the buffer-object backed framebuffer. 12298c2ecf20Sopenharmony_ci * @clips: Array of clip rects. 12308c2ecf20Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 12318c2ecf20Sopenharmony_ci * be NULL. 12328c2ecf20Sopenharmony_ci * @num_clips: Number of clip rects in @clips. 12338c2ecf20Sopenharmony_ci * @increment: Increment to use when looping over @clips. 12348c2ecf20Sopenharmony_ci * @interruptible: Whether to perform waits interruptible if possible. 12358c2ecf20Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to a 12368c2ecf20Sopenharmony_ci * struct vmw_fence_obj. The returned fence pointer may be NULL in which 12378c2ecf20Sopenharmony_ci * case the device has already synchronized. 12388c2ecf20Sopenharmony_ci * @crtc: If crtc is passed, perform bo dirty on that crtc only. 12398c2ecf20Sopenharmony_ci * 12408c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 12418c2ecf20Sopenharmony_ci * interrupted. 12428c2ecf20Sopenharmony_ci */ 12438c2ecf20Sopenharmony_ciint vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, 12448c2ecf20Sopenharmony_ci struct vmw_framebuffer *framebuffer, 12458c2ecf20Sopenharmony_ci struct drm_clip_rect *clips, 12468c2ecf20Sopenharmony_ci struct drm_vmw_rect *vclips, 12478c2ecf20Sopenharmony_ci unsigned num_clips, int increment, 12488c2ecf20Sopenharmony_ci bool interruptible, 12498c2ecf20Sopenharmony_ci struct vmw_fence_obj **out_fence, 12508c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct vmw_buffer_object *buf = 12538c2ecf20Sopenharmony_ci container_of(framebuffer, struct vmw_framebuffer_bo, 12548c2ecf20Sopenharmony_ci base)->buffer; 12558c2ecf20Sopenharmony_ci struct vmw_kms_dirty dirty; 12568c2ecf20Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 12578c2ecf20Sopenharmony_ci int ret; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci ret = vmw_validation_add_bo(&val_ctx, buf, false, false); 12608c2ecf20Sopenharmony_ci if (ret) 12618c2ecf20Sopenharmony_ci return ret; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); 12648c2ecf20Sopenharmony_ci if (ret) 12658c2ecf20Sopenharmony_ci goto out_unref; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci ret = do_bo_define_gmrfb(dev_priv, framebuffer); 12688c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 12698c2ecf20Sopenharmony_ci goto out_revert; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci dirty.crtc = crtc; 12728c2ecf20Sopenharmony_ci dirty.fifo_commit = vmw_sou_bo_fifo_commit; 12738c2ecf20Sopenharmony_ci dirty.clip = vmw_sou_bo_clip; 12748c2ecf20Sopenharmony_ci dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) * 12758c2ecf20Sopenharmony_ci num_clips; 12768c2ecf20Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 12778c2ecf20Sopenharmony_ci 0, 0, num_clips, increment, &dirty); 12788c2ecf20Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 12798c2ecf20Sopenharmony_ci NULL); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return ret; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ciout_revert: 12848c2ecf20Sopenharmony_ci vmw_validation_revert(&val_ctx); 12858c2ecf20Sopenharmony_ciout_unref: 12868c2ecf20Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci return ret; 12898c2ecf20Sopenharmony_ci} 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci/** 12938c2ecf20Sopenharmony_ci * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips. 12948c2ecf20Sopenharmony_ci * 12958c2ecf20Sopenharmony_ci * @dirty: The closure structure. 12968c2ecf20Sopenharmony_ci * 12978c2ecf20Sopenharmony_ci * Commits a previously built command buffer of readback clips. 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_cistatic void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci if (!dirty->num_hits) { 13028c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 0); 13038c2ecf20Sopenharmony_ci return; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci vmw_fifo_commit(dirty->dev_priv, 13078c2ecf20Sopenharmony_ci sizeof(struct vmw_kms_sou_readback_blit) * 13088c2ecf20Sopenharmony_ci dirty->num_hits); 13098c2ecf20Sopenharmony_ci} 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci/** 13128c2ecf20Sopenharmony_ci * vmw_sou_readback_clip - Callback to encode a readback cliprect. 13138c2ecf20Sopenharmony_ci * 13148c2ecf20Sopenharmony_ci * @dirty: The closure structure 13158c2ecf20Sopenharmony_ci * 13168c2ecf20Sopenharmony_ci * Encodes a BLIT_SCREEN_TO_GMRFB cliprect. 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_cistatic void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci struct vmw_kms_sou_readback_blit *blit = dirty->cmd; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci blit += dirty->num_hits; 13238c2ecf20Sopenharmony_ci blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; 13248c2ecf20Sopenharmony_ci blit->body.srcScreenId = dirty->unit->unit; 13258c2ecf20Sopenharmony_ci blit->body.destOrigin.x = dirty->fb_x; 13268c2ecf20Sopenharmony_ci blit->body.destOrigin.y = dirty->fb_y; 13278c2ecf20Sopenharmony_ci blit->body.srcRect.left = dirty->unit_x1; 13288c2ecf20Sopenharmony_ci blit->body.srcRect.top = dirty->unit_y1; 13298c2ecf20Sopenharmony_ci blit->body.srcRect.right = dirty->unit_x2; 13308c2ecf20Sopenharmony_ci blit->body.srcRect.bottom = dirty->unit_y2; 13318c2ecf20Sopenharmony_ci dirty->num_hits++; 13328c2ecf20Sopenharmony_ci} 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci/** 13358c2ecf20Sopenharmony_ci * vmw_kms_sou_readback - Perform a readback from the screen object system to 13368c2ecf20Sopenharmony_ci * a buffer-object backed framebuffer. 13378c2ecf20Sopenharmony_ci * 13388c2ecf20Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 13398c2ecf20Sopenharmony_ci * @file_priv: Pointer to a struct drm_file identifying the caller. 13408c2ecf20Sopenharmony_ci * Must be set to NULL if @user_fence_rep is NULL. 13418c2ecf20Sopenharmony_ci * @vfb: Pointer to the buffer-object backed framebuffer. 13428c2ecf20Sopenharmony_ci * @user_fence_rep: User-space provided structure for fence information. 13438c2ecf20Sopenharmony_ci * Must be set to non-NULL if @file_priv is non-NULL. 13448c2ecf20Sopenharmony_ci * @vclips: Array of clip rects. 13458c2ecf20Sopenharmony_ci * @num_clips: Number of clip rects in @vclips. 13468c2ecf20Sopenharmony_ci * @crtc: If crtc is passed, readback on that crtc only. 13478c2ecf20Sopenharmony_ci * 13488c2ecf20Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 13498c2ecf20Sopenharmony_ci * interrupted. 13508c2ecf20Sopenharmony_ci */ 13518c2ecf20Sopenharmony_ciint vmw_kms_sou_readback(struct vmw_private *dev_priv, 13528c2ecf20Sopenharmony_ci struct drm_file *file_priv, 13538c2ecf20Sopenharmony_ci struct vmw_framebuffer *vfb, 13548c2ecf20Sopenharmony_ci struct drm_vmw_fence_rep __user *user_fence_rep, 13558c2ecf20Sopenharmony_ci struct drm_vmw_rect *vclips, 13568c2ecf20Sopenharmony_ci uint32_t num_clips, 13578c2ecf20Sopenharmony_ci struct drm_crtc *crtc) 13588c2ecf20Sopenharmony_ci{ 13598c2ecf20Sopenharmony_ci struct vmw_buffer_object *buf = 13608c2ecf20Sopenharmony_ci container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; 13618c2ecf20Sopenharmony_ci struct vmw_kms_dirty dirty; 13628c2ecf20Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 13638c2ecf20Sopenharmony_ci int ret; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci ret = vmw_validation_add_bo(&val_ctx, buf, false, false); 13668c2ecf20Sopenharmony_ci if (ret) 13678c2ecf20Sopenharmony_ci return ret; 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, NULL, true); 13708c2ecf20Sopenharmony_ci if (ret) 13718c2ecf20Sopenharmony_ci goto out_unref; 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci ret = do_bo_define_gmrfb(dev_priv, vfb); 13748c2ecf20Sopenharmony_ci if (unlikely(ret != 0)) 13758c2ecf20Sopenharmony_ci goto out_revert; 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_ci dirty.crtc = crtc; 13788c2ecf20Sopenharmony_ci dirty.fifo_commit = vmw_sou_readback_fifo_commit; 13798c2ecf20Sopenharmony_ci dirty.clip = vmw_sou_readback_clip; 13808c2ecf20Sopenharmony_ci dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * 13818c2ecf20Sopenharmony_ci num_clips; 13828c2ecf20Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips, 13838c2ecf20Sopenharmony_ci 0, 0, num_clips, 1, &dirty); 13848c2ecf20Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL, 13858c2ecf20Sopenharmony_ci user_fence_rep); 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci return ret; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ciout_revert: 13908c2ecf20Sopenharmony_ci vmw_validation_revert(&val_ctx); 13918c2ecf20Sopenharmony_ciout_unref: 13928c2ecf20Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci return ret; 13958c2ecf20Sopenharmony_ci} 1396