162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 OR MIT 262306a36Sopenharmony_ci/************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2011-2023 VMware, Inc., Palo Alto, CA., USA 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the 862306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 962306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 1062306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1162306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1262306a36Sopenharmony_ci * the following conditions: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 1562306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 1662306a36Sopenharmony_ci * of the Software. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1962306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2062306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 2162306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 2262306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 2362306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 2462306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci **************************************************************************/ 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "vmwgfx_bo.h" 2962306a36Sopenharmony_ci#include "vmwgfx_kms.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#include <drm/drm_atomic.h> 3262306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 3362306a36Sopenharmony_ci#include <drm/drm_damage_helper.h> 3462306a36Sopenharmony_ci#include <drm/drm_fourcc.h> 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define vmw_crtc_to_sou(x) \ 3762306a36Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.crtc) 3862306a36Sopenharmony_ci#define vmw_encoder_to_sou(x) \ 3962306a36Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.encoder) 4062306a36Sopenharmony_ci#define vmw_connector_to_sou(x) \ 4162306a36Sopenharmony_ci container_of(x, struct vmw_screen_object_unit, base.connector) 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * struct vmw_kms_sou_surface_dirty - Closure structure for 4562306a36Sopenharmony_ci * blit surface to screen command. 4662306a36Sopenharmony_ci * @base: The base type we derive from. Used by vmw_kms_helper_dirty(). 4762306a36Sopenharmony_ci * @left: Left side of bounding box. 4862306a36Sopenharmony_ci * @right: Right side of bounding box. 4962306a36Sopenharmony_ci * @top: Top side of bounding box. 5062306a36Sopenharmony_ci * @bottom: Bottom side of bounding box. 5162306a36Sopenharmony_ci * @dst_x: Difference between source clip rects and framebuffer coordinates. 5262306a36Sopenharmony_ci * @dst_y: Difference between source clip rects and framebuffer coordinates. 5362306a36Sopenharmony_ci * @sid: Surface id of surface to copy from. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_cistruct vmw_kms_sou_surface_dirty { 5662306a36Sopenharmony_ci struct vmw_kms_dirty base; 5762306a36Sopenharmony_ci s32 left, right, top, bottom; 5862306a36Sopenharmony_ci s32 dst_x, dst_y; 5962306a36Sopenharmony_ci u32 sid; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * SVGA commands that are used by this code. Please see the device headers 6462306a36Sopenharmony_ci * for explanation. 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistruct vmw_kms_sou_readback_blit { 6762306a36Sopenharmony_ci uint32 header; 6862306a36Sopenharmony_ci SVGAFifoCmdBlitScreenToGMRFB body; 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct vmw_kms_sou_bo_blit { 7262306a36Sopenharmony_ci uint32 header; 7362306a36Sopenharmony_ci SVGAFifoCmdBlitGMRFBToScreen body; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct vmw_kms_sou_dirty_cmd { 7762306a36Sopenharmony_ci SVGA3dCmdHeader header; 7862306a36Sopenharmony_ci SVGA3dCmdBlitSurfaceToScreen body; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct vmw_kms_sou_define_gmrfb { 8262306a36Sopenharmony_ci uint32_t header; 8362306a36Sopenharmony_ci SVGAFifoCmdDefineGMRFB body; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* 8762306a36Sopenharmony_ci * Display unit using screen objects. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistruct vmw_screen_object_unit { 9062306a36Sopenharmony_ci struct vmw_display_unit base; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci unsigned long buffer_size; /**< Size of allocated buffer */ 9362306a36Sopenharmony_ci struct vmw_bo *buffer; /**< Backing store buffer */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci bool defined; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void vmw_sou_destroy(struct vmw_screen_object_unit *sou) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci vmw_du_cleanup(&sou->base); 10162306a36Sopenharmony_ci kfree(sou); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Screen Object Display Unit CRTC functions 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void vmw_sou_crtc_destroy(struct drm_crtc *crtc) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci vmw_sou_destroy(vmw_crtc_to_sou(crtc)); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * Send the fifo command to create a screen. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic int vmw_sou_fifo_create(struct vmw_private *dev_priv, 11862306a36Sopenharmony_ci struct vmw_screen_object_unit *sou, 11962306a36Sopenharmony_ci int x, int y, 12062306a36Sopenharmony_ci struct drm_display_mode *mode) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci size_t fifo_size; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci struct { 12562306a36Sopenharmony_ci struct { 12662306a36Sopenharmony_ci uint32_t cmdType; 12762306a36Sopenharmony_ci } header; 12862306a36Sopenharmony_ci SVGAScreenObject obj; 12962306a36Sopenharmony_ci } *cmd; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci BUG_ON(!sou->buffer); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci fifo_size = sizeof(*cmd); 13462306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, fifo_size); 13562306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 13662306a36Sopenharmony_ci return -ENOMEM; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci memset(cmd, 0, fifo_size); 13962306a36Sopenharmony_ci cmd->header.cmdType = SVGA_CMD_DEFINE_SCREEN; 14062306a36Sopenharmony_ci cmd->obj.structSize = sizeof(SVGAScreenObject); 14162306a36Sopenharmony_ci cmd->obj.id = sou->base.unit; 14262306a36Sopenharmony_ci cmd->obj.flags = SVGA_SCREEN_HAS_ROOT | 14362306a36Sopenharmony_ci (sou->base.unit == 0 ? SVGA_SCREEN_IS_PRIMARY : 0); 14462306a36Sopenharmony_ci cmd->obj.size.width = mode->hdisplay; 14562306a36Sopenharmony_ci cmd->obj.size.height = mode->vdisplay; 14662306a36Sopenharmony_ci cmd->obj.root.x = x; 14762306a36Sopenharmony_ci cmd->obj.root.y = y; 14862306a36Sopenharmony_ci sou->base.set_gui_x = cmd->obj.root.x; 14962306a36Sopenharmony_ci sou->base.set_gui_y = cmd->obj.root.y; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Ok to assume that buffer is pinned in vram */ 15262306a36Sopenharmony_ci vmw_bo_get_guest_ptr(&sou->buffer->tbo, &cmd->obj.backingStore.ptr); 15362306a36Sopenharmony_ci cmd->obj.backingStore.pitch = mode->hdisplay * 4; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, fifo_size); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci sou->defined = true; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci/* 16362306a36Sopenharmony_ci * Send the fifo command to destroy a screen. 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic int vmw_sou_fifo_destroy(struct vmw_private *dev_priv, 16662306a36Sopenharmony_ci struct vmw_screen_object_unit *sou) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci size_t fifo_size; 16962306a36Sopenharmony_ci int ret; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci struct { 17262306a36Sopenharmony_ci struct { 17362306a36Sopenharmony_ci uint32_t cmdType; 17462306a36Sopenharmony_ci } header; 17562306a36Sopenharmony_ci SVGAFifoCmdDestroyScreen body; 17662306a36Sopenharmony_ci } *cmd; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* no need to do anything */ 17962306a36Sopenharmony_ci if (unlikely(!sou->defined)) 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci fifo_size = sizeof(*cmd); 18362306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, fifo_size); 18462306a36Sopenharmony_ci if (unlikely(cmd == NULL)) 18562306a36Sopenharmony_ci return -ENOMEM; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci memset(cmd, 0, fifo_size); 18862306a36Sopenharmony_ci cmd->header.cmdType = SVGA_CMD_DESTROY_SCREEN; 18962306a36Sopenharmony_ci cmd->body.screenId = sou->base.unit; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, fifo_size); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Force sync */ 19462306a36Sopenharmony_ci ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ); 19562306a36Sopenharmony_ci if (unlikely(ret != 0)) 19662306a36Sopenharmony_ci DRM_ERROR("Failed to sync with HW"); 19762306a36Sopenharmony_ci else 19862306a36Sopenharmony_ci sou->defined = false; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return ret; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/** 20462306a36Sopenharmony_ci * vmw_sou_crtc_mode_set_nofb - Create new screen 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * @crtc: CRTC associated with the new screen 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * This function creates/destroys a screen. This function cannot fail, so if 20962306a36Sopenharmony_ci * somehow we run into a failure, just do the best we can to get out. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic void vmw_sou_crtc_mode_set_nofb(struct drm_crtc *crtc) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct vmw_private *dev_priv; 21462306a36Sopenharmony_ci struct vmw_screen_object_unit *sou; 21562306a36Sopenharmony_ci struct vmw_framebuffer *vfb; 21662306a36Sopenharmony_ci struct drm_framebuffer *fb; 21762306a36Sopenharmony_ci struct drm_plane_state *ps; 21862306a36Sopenharmony_ci struct vmw_plane_state *vps; 21962306a36Sopenharmony_ci int ret; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci sou = vmw_crtc_to_sou(crtc); 22262306a36Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 22362306a36Sopenharmony_ci ps = crtc->primary->state; 22462306a36Sopenharmony_ci fb = ps->fb; 22562306a36Sopenharmony_ci vps = vmw_plane_state_to_vps(ps); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci vfb = (fb) ? vmw_framebuffer_to_vfb(fb) : NULL; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (sou->defined) { 23062306a36Sopenharmony_ci ret = vmw_sou_fifo_destroy(dev_priv, sou); 23162306a36Sopenharmony_ci if (ret) { 23262306a36Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Object\n"); 23362306a36Sopenharmony_ci return; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci if (vfb) { 23862306a36Sopenharmony_ci struct drm_connector_state *conn_state; 23962306a36Sopenharmony_ci struct vmw_connector_state *vmw_conn_state; 24062306a36Sopenharmony_ci int x, y; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci sou->buffer = vps->bo; 24362306a36Sopenharmony_ci sou->buffer_size = vps->bo_size; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci conn_state = sou->base.connector.state; 24662306a36Sopenharmony_ci vmw_conn_state = vmw_connector_state_to_vcs(conn_state); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci x = vmw_conn_state->gui_x; 24962306a36Sopenharmony_ci y = vmw_conn_state->gui_y; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = vmw_sou_fifo_create(dev_priv, sou, x, y, &crtc->mode); 25262306a36Sopenharmony_ci if (ret) 25362306a36Sopenharmony_ci DRM_ERROR("Failed to define Screen Object %dx%d\n", 25462306a36Sopenharmony_ci crtc->x, crtc->y); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci } else { 25762306a36Sopenharmony_ci sou->buffer = NULL; 25862306a36Sopenharmony_ci sou->buffer_size = 0; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/** 26362306a36Sopenharmony_ci * vmw_sou_crtc_helper_prepare - Noop 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * @crtc: CRTC associated with the new screen 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * Prepares the CRTC for a mode set, but we don't need to do anything here. 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_cistatic void vmw_sou_crtc_helper_prepare(struct drm_crtc *crtc) 27062306a36Sopenharmony_ci{ 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci/** 27462306a36Sopenharmony_ci * vmw_sou_crtc_atomic_enable - Noop 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * @crtc: CRTC associated with the new screen 27762306a36Sopenharmony_ci * @state: Unused 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * This is called after a mode set has been completed. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_cistatic void vmw_sou_crtc_atomic_enable(struct drm_crtc *crtc, 28262306a36Sopenharmony_ci struct drm_atomic_state *state) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/** 28762306a36Sopenharmony_ci * vmw_sou_crtc_atomic_disable - Turns off CRTC 28862306a36Sopenharmony_ci * 28962306a36Sopenharmony_ci * @crtc: CRTC to be turned off 29062306a36Sopenharmony_ci * @state: Unused 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_cistatic void vmw_sou_crtc_atomic_disable(struct drm_crtc *crtc, 29362306a36Sopenharmony_ci struct drm_atomic_state *state) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct vmw_private *dev_priv; 29662306a36Sopenharmony_ci struct vmw_screen_object_unit *sou; 29762306a36Sopenharmony_ci int ret; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci if (!crtc) { 30162306a36Sopenharmony_ci DRM_ERROR("CRTC is NULL\n"); 30262306a36Sopenharmony_ci return; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci sou = vmw_crtc_to_sou(crtc); 30662306a36Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (sou->defined) { 30962306a36Sopenharmony_ci ret = vmw_sou_fifo_destroy(dev_priv, sou); 31062306a36Sopenharmony_ci if (ret) 31162306a36Sopenharmony_ci DRM_ERROR("Failed to destroy Screen Object\n"); 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = { 31662306a36Sopenharmony_ci .gamma_set = vmw_du_crtc_gamma_set, 31762306a36Sopenharmony_ci .destroy = vmw_sou_crtc_destroy, 31862306a36Sopenharmony_ci .reset = vmw_du_crtc_reset, 31962306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_crtc_duplicate_state, 32062306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_crtc_destroy_state, 32162306a36Sopenharmony_ci .set_config = drm_atomic_helper_set_config, 32262306a36Sopenharmony_ci .page_flip = drm_atomic_helper_page_flip, 32362306a36Sopenharmony_ci}; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* 32662306a36Sopenharmony_ci * Screen Object Display Unit encoder functions 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic void vmw_sou_encoder_destroy(struct drm_encoder *encoder) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci vmw_sou_destroy(vmw_encoder_to_sou(encoder)); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = { 33562306a36Sopenharmony_ci .destroy = vmw_sou_encoder_destroy, 33662306a36Sopenharmony_ci}; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* 33962306a36Sopenharmony_ci * Screen Object Display Unit connector functions 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void vmw_sou_connector_destroy(struct drm_connector *connector) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci vmw_sou_destroy(vmw_connector_to_sou(connector)); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic const struct drm_connector_funcs vmw_sou_connector_funcs = { 34862306a36Sopenharmony_ci .dpms = vmw_du_connector_dpms, 34962306a36Sopenharmony_ci .detect = vmw_du_connector_detect, 35062306a36Sopenharmony_ci .fill_modes = vmw_du_connector_fill_modes, 35162306a36Sopenharmony_ci .destroy = vmw_sou_connector_destroy, 35262306a36Sopenharmony_ci .reset = vmw_du_connector_reset, 35362306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_connector_duplicate_state, 35462306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_connector_destroy_state, 35562306a36Sopenharmony_ci}; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic const struct 35962306a36Sopenharmony_cidrm_connector_helper_funcs vmw_sou_connector_helper_funcs = { 36062306a36Sopenharmony_ci}; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci/* 36562306a36Sopenharmony_ci * Screen Object Display Plane Functions 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * @plane: display plane 37262306a36Sopenharmony_ci * @old_state: Contains the FB to clean up 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * Unpins the display surface 37562306a36Sopenharmony_ci * 37662306a36Sopenharmony_ci * Returns 0 on success 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_cistatic void 37962306a36Sopenharmony_civmw_sou_primary_plane_cleanup_fb(struct drm_plane *plane, 38062306a36Sopenharmony_ci struct drm_plane_state *old_state) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state); 38362306a36Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc ? 38462306a36Sopenharmony_ci plane->state->crtc : old_state->crtc; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (vps->bo) 38762306a36Sopenharmony_ci vmw_bo_unpin(vmw_priv(crtc->dev), vps->bo, false); 38862306a36Sopenharmony_ci vmw_bo_unreference(&vps->bo); 38962306a36Sopenharmony_ci vps->bo_size = 0; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci vmw_du_plane_cleanup_fb(plane, old_state); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/** 39662306a36Sopenharmony_ci * vmw_sou_primary_plane_prepare_fb - allocate backing buffer 39762306a36Sopenharmony_ci * 39862306a36Sopenharmony_ci * @plane: display plane 39962306a36Sopenharmony_ci * @new_state: info on the new plane state, including the FB 40062306a36Sopenharmony_ci * 40162306a36Sopenharmony_ci * The SOU backing buffer is our equivalent of the display plane. 40262306a36Sopenharmony_ci * 40362306a36Sopenharmony_ci * Returns 0 on success 40462306a36Sopenharmony_ci */ 40562306a36Sopenharmony_cistatic int 40662306a36Sopenharmony_civmw_sou_primary_plane_prepare_fb(struct drm_plane *plane, 40762306a36Sopenharmony_ci struct drm_plane_state *new_state) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct drm_framebuffer *new_fb = new_state->fb; 41062306a36Sopenharmony_ci struct drm_crtc *crtc = plane->state->crtc ?: new_state->crtc; 41162306a36Sopenharmony_ci struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state); 41262306a36Sopenharmony_ci struct vmw_private *dev_priv; 41362306a36Sopenharmony_ci int ret; 41462306a36Sopenharmony_ci struct vmw_bo_params bo_params = { 41562306a36Sopenharmony_ci .domain = VMW_BO_DOMAIN_VRAM, 41662306a36Sopenharmony_ci .busy_domain = VMW_BO_DOMAIN_VRAM, 41762306a36Sopenharmony_ci .bo_type = ttm_bo_type_device, 41862306a36Sopenharmony_ci .pin = true 41962306a36Sopenharmony_ci }; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (!new_fb) { 42262306a36Sopenharmony_ci vmw_bo_unreference(&vps->bo); 42362306a36Sopenharmony_ci vps->bo_size = 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci bo_params.size = new_state->crtc_w * new_state->crtc_h * 4; 42962306a36Sopenharmony_ci dev_priv = vmw_priv(crtc->dev); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (vps->bo) { 43262306a36Sopenharmony_ci if (vps->bo_size == bo_params.size) { 43362306a36Sopenharmony_ci /* 43462306a36Sopenharmony_ci * Note that this might temporarily up the pin-count 43562306a36Sopenharmony_ci * to 2, until cleanup_fb() is called. 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_ci return vmw_bo_pin_in_vram(dev_priv, vps->bo, 43862306a36Sopenharmony_ci true); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci vmw_bo_unreference(&vps->bo); 44262306a36Sopenharmony_ci vps->bo_size = 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci vmw_svga_enable(dev_priv); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* After we have alloced the backing store might not be able to 44862306a36Sopenharmony_ci * resume the overlays, this is preferred to failing to alloc. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_ci vmw_overlay_pause_all(dev_priv); 45162306a36Sopenharmony_ci ret = vmw_bo_create(dev_priv, &bo_params, &vps->bo); 45262306a36Sopenharmony_ci vmw_overlay_resume_all(dev_priv); 45362306a36Sopenharmony_ci if (ret) 45462306a36Sopenharmony_ci return ret; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci vps->bo_size = bo_params.size; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* 45962306a36Sopenharmony_ci * TTM already thinks the buffer is pinned, but make sure the 46062306a36Sopenharmony_ci * pin_count is upped. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ci return vmw_bo_pin_in_vram(dev_priv, vps->bo, true); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic uint32_t vmw_sou_bo_fifo_size(struct vmw_du_update_plane *update, 46662306a36Sopenharmony_ci uint32_t num_hits) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci return sizeof(struct vmw_kms_sou_define_gmrfb) + 46962306a36Sopenharmony_ci sizeof(struct vmw_kms_sou_bo_blit) * num_hits; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic uint32_t vmw_sou_bo_define_gmrfb(struct vmw_du_update_plane *update, 47362306a36Sopenharmony_ci void *cmd) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct vmw_framebuffer_bo *vfbbo = 47662306a36Sopenharmony_ci container_of(update->vfb, typeof(*vfbbo), base); 47762306a36Sopenharmony_ci struct vmw_kms_sou_define_gmrfb *gmr = cmd; 47862306a36Sopenharmony_ci int depth = update->vfb->base.format->depth; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Emulate RGBA support, contrary to svga_reg.h this is not 48162306a36Sopenharmony_ci * supported by hosts. This is only a problem if we are reading 48262306a36Sopenharmony_ci * this value later and expecting what we uploaded back. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_ci if (depth == 32) 48562306a36Sopenharmony_ci depth = 24; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci gmr->header = SVGA_CMD_DEFINE_GMRFB; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci gmr->body.format.bitsPerPixel = update->vfb->base.format->cpp[0] * 8; 49062306a36Sopenharmony_ci gmr->body.format.colorDepth = depth; 49162306a36Sopenharmony_ci gmr->body.format.reserved = 0; 49262306a36Sopenharmony_ci gmr->body.bytesPerLine = update->vfb->base.pitches[0]; 49362306a36Sopenharmony_ci vmw_bo_get_guest_ptr(&vfbbo->buffer->tbo, &gmr->body.ptr); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci return sizeof(*gmr); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic uint32_t vmw_sou_bo_populate_clip(struct vmw_du_update_plane *update, 49962306a36Sopenharmony_ci void *cmd, struct drm_rect *clip, 50062306a36Sopenharmony_ci uint32_t fb_x, uint32_t fb_y) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct vmw_kms_sou_bo_blit *blit = cmd; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 50562306a36Sopenharmony_ci blit->body.destScreenId = update->du->unit; 50662306a36Sopenharmony_ci blit->body.srcOrigin.x = fb_x; 50762306a36Sopenharmony_ci blit->body.srcOrigin.y = fb_y; 50862306a36Sopenharmony_ci blit->body.destRect.left = clip->x1; 50962306a36Sopenharmony_ci blit->body.destRect.top = clip->y1; 51062306a36Sopenharmony_ci blit->body.destRect.right = clip->x2; 51162306a36Sopenharmony_ci blit->body.destRect.bottom = clip->y2; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return sizeof(*blit); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic uint32_t vmw_stud_bo_post_clip(struct vmw_du_update_plane *update, 51762306a36Sopenharmony_ci void *cmd, struct drm_rect *bb) 51862306a36Sopenharmony_ci{ 51962306a36Sopenharmony_ci return 0; 52062306a36Sopenharmony_ci} 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci/** 52362306a36Sopenharmony_ci * vmw_sou_plane_update_bo - Update display unit for bo backed fb. 52462306a36Sopenharmony_ci * @dev_priv: Device private. 52562306a36Sopenharmony_ci * @plane: Plane state. 52662306a36Sopenharmony_ci * @old_state: Old plane state. 52762306a36Sopenharmony_ci * @vfb: Framebuffer which is blitted to display unit. 52862306a36Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 52962306a36Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 53062306a36Sopenharmony_ci * has already synchronized. 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_cistatic int vmw_sou_plane_update_bo(struct vmw_private *dev_priv, 53562306a36Sopenharmony_ci struct drm_plane *plane, 53662306a36Sopenharmony_ci struct drm_plane_state *old_state, 53762306a36Sopenharmony_ci struct vmw_framebuffer *vfb, 53862306a36Sopenharmony_ci struct vmw_fence_obj **out_fence) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct vmw_du_update_plane_buffer bo_update; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer)); 54362306a36Sopenharmony_ci bo_update.base.plane = plane; 54462306a36Sopenharmony_ci bo_update.base.old_state = old_state; 54562306a36Sopenharmony_ci bo_update.base.dev_priv = dev_priv; 54662306a36Sopenharmony_ci bo_update.base.du = vmw_crtc_to_du(plane->state->crtc); 54762306a36Sopenharmony_ci bo_update.base.vfb = vfb; 54862306a36Sopenharmony_ci bo_update.base.out_fence = out_fence; 54962306a36Sopenharmony_ci bo_update.base.mutex = NULL; 55062306a36Sopenharmony_ci bo_update.base.intr = true; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci bo_update.base.calc_fifo_size = vmw_sou_bo_fifo_size; 55362306a36Sopenharmony_ci bo_update.base.post_prepare = vmw_sou_bo_define_gmrfb; 55462306a36Sopenharmony_ci bo_update.base.clip = vmw_sou_bo_populate_clip; 55562306a36Sopenharmony_ci bo_update.base.post_clip = vmw_stud_bo_post_clip; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return vmw_du_helper_plane_update(&bo_update.base); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_cistatic uint32_t vmw_sou_surface_fifo_size(struct vmw_du_update_plane *update, 56162306a36Sopenharmony_ci uint32_t num_hits) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci return sizeof(struct vmw_kms_sou_dirty_cmd) + sizeof(SVGASignedRect) * 56462306a36Sopenharmony_ci num_hits; 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_cistatic uint32_t vmw_sou_surface_post_prepare(struct vmw_du_update_plane *update, 56862306a36Sopenharmony_ci void *cmd) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci struct vmw_du_update_plane_surface *srf_update; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci srf_update = container_of(update, typeof(*srf_update), base); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* 57562306a36Sopenharmony_ci * SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that 57662306a36Sopenharmony_ci * its bounding box is filled before iterating over all the clips. So 57762306a36Sopenharmony_ci * store the FIFO start address and revisit to fill the details. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci srf_update->cmd_start = cmd; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic uint32_t vmw_sou_surface_pre_clip(struct vmw_du_update_plane *update, 58562306a36Sopenharmony_ci void *cmd, uint32_t num_hits) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *blit = cmd; 58862306a36Sopenharmony_ci struct vmw_framebuffer_surface *vfbs; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci vfbs = container_of(update->vfb, typeof(*vfbs), base); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci blit->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; 59362306a36Sopenharmony_ci blit->header.size = sizeof(blit->body) + sizeof(SVGASignedRect) * 59462306a36Sopenharmony_ci num_hits; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci blit->body.srcImage.sid = vfbs->surface->res.id; 59762306a36Sopenharmony_ci blit->body.destScreenId = update->du->unit; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* Update the source and destination bounding box later in post_clip */ 60062306a36Sopenharmony_ci blit->body.srcRect.left = 0; 60162306a36Sopenharmony_ci blit->body.srcRect.top = 0; 60262306a36Sopenharmony_ci blit->body.srcRect.right = 0; 60362306a36Sopenharmony_ci blit->body.srcRect.bottom = 0; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci blit->body.destRect.left = 0; 60662306a36Sopenharmony_ci blit->body.destRect.top = 0; 60762306a36Sopenharmony_ci blit->body.destRect.right = 0; 60862306a36Sopenharmony_ci blit->body.destRect.bottom = 0; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return sizeof(*blit); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic uint32_t vmw_sou_surface_clip_rect(struct vmw_du_update_plane *update, 61462306a36Sopenharmony_ci void *cmd, struct drm_rect *clip, 61562306a36Sopenharmony_ci uint32_t src_x, uint32_t src_y) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci SVGASignedRect *rect = cmd; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci /* 62062306a36Sopenharmony_ci * rects are relative to dest bounding box rect on screen object, so 62162306a36Sopenharmony_ci * translate to it later in post_clip 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci rect->left = clip->x1; 62462306a36Sopenharmony_ci rect->top = clip->y1; 62562306a36Sopenharmony_ci rect->right = clip->x2; 62662306a36Sopenharmony_ci rect->bottom = clip->y2; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci return sizeof(*rect); 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic uint32_t vmw_sou_surface_post_clip(struct vmw_du_update_plane *update, 63262306a36Sopenharmony_ci void *cmd, struct drm_rect *bb) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct vmw_du_update_plane_surface *srf_update; 63562306a36Sopenharmony_ci struct drm_plane_state *state = update->plane->state; 63662306a36Sopenharmony_ci struct drm_rect src_bb; 63762306a36Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *blit; 63862306a36Sopenharmony_ci SVGASignedRect *rect; 63962306a36Sopenharmony_ci uint32_t num_hits; 64062306a36Sopenharmony_ci int translate_src_x; 64162306a36Sopenharmony_ci int translate_src_y; 64262306a36Sopenharmony_ci int i; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci srf_update = container_of(update, typeof(*srf_update), base); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci blit = srf_update->cmd_start; 64762306a36Sopenharmony_ci rect = (SVGASignedRect *)&blit[1]; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci num_hits = (blit->header.size - sizeof(blit->body))/ 65062306a36Sopenharmony_ci sizeof(SVGASignedRect); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci src_bb = *bb; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* To translate bb back to fb src coord */ 65562306a36Sopenharmony_ci translate_src_x = (state->src_x >> 16) - state->crtc_x; 65662306a36Sopenharmony_ci translate_src_y = (state->src_y >> 16) - state->crtc_y; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci drm_rect_translate(&src_bb, translate_src_x, translate_src_y); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci blit->body.srcRect.left = src_bb.x1; 66162306a36Sopenharmony_ci blit->body.srcRect.top = src_bb.y1; 66262306a36Sopenharmony_ci blit->body.srcRect.right = src_bb.x2; 66362306a36Sopenharmony_ci blit->body.srcRect.bottom = src_bb.y2; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci blit->body.destRect.left = bb->x1; 66662306a36Sopenharmony_ci blit->body.destRect.top = bb->y1; 66762306a36Sopenharmony_ci blit->body.destRect.right = bb->x2; 66862306a36Sopenharmony_ci blit->body.destRect.bottom = bb->y2; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* rects are relative to dest bb rect */ 67162306a36Sopenharmony_ci for (i = 0; i < num_hits; i++) { 67262306a36Sopenharmony_ci rect->left -= bb->x1; 67362306a36Sopenharmony_ci rect->top -= bb->y1; 67462306a36Sopenharmony_ci rect->right -= bb->x1; 67562306a36Sopenharmony_ci rect->bottom -= bb->y1; 67662306a36Sopenharmony_ci rect++; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return 0; 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci/** 68362306a36Sopenharmony_ci * vmw_sou_plane_update_surface - Update display unit for surface backed fb. 68462306a36Sopenharmony_ci * @dev_priv: Device private. 68562306a36Sopenharmony_ci * @plane: Plane state. 68662306a36Sopenharmony_ci * @old_state: Old plane state. 68762306a36Sopenharmony_ci * @vfb: Framebuffer which is blitted to display unit 68862306a36Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj. 68962306a36Sopenharmony_ci * The returned fence pointer may be NULL in which case the device 69062306a36Sopenharmony_ci * has already synchronized. 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * Return: 0 on success or a negative error code on failure. 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_cistatic int vmw_sou_plane_update_surface(struct vmw_private *dev_priv, 69562306a36Sopenharmony_ci struct drm_plane *plane, 69662306a36Sopenharmony_ci struct drm_plane_state *old_state, 69762306a36Sopenharmony_ci struct vmw_framebuffer *vfb, 69862306a36Sopenharmony_ci struct vmw_fence_obj **out_fence) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct vmw_du_update_plane_surface srf_update; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci memset(&srf_update, 0, sizeof(struct vmw_du_update_plane_surface)); 70362306a36Sopenharmony_ci srf_update.base.plane = plane; 70462306a36Sopenharmony_ci srf_update.base.old_state = old_state; 70562306a36Sopenharmony_ci srf_update.base.dev_priv = dev_priv; 70662306a36Sopenharmony_ci srf_update.base.du = vmw_crtc_to_du(plane->state->crtc); 70762306a36Sopenharmony_ci srf_update.base.vfb = vfb; 70862306a36Sopenharmony_ci srf_update.base.out_fence = out_fence; 70962306a36Sopenharmony_ci srf_update.base.mutex = &dev_priv->cmdbuf_mutex; 71062306a36Sopenharmony_ci srf_update.base.intr = true; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci srf_update.base.calc_fifo_size = vmw_sou_surface_fifo_size; 71362306a36Sopenharmony_ci srf_update.base.post_prepare = vmw_sou_surface_post_prepare; 71462306a36Sopenharmony_ci srf_update.base.pre_clip = vmw_sou_surface_pre_clip; 71562306a36Sopenharmony_ci srf_update.base.clip = vmw_sou_surface_clip_rect; 71662306a36Sopenharmony_ci srf_update.base.post_clip = vmw_sou_surface_post_clip; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return vmw_du_helper_plane_update(&srf_update.base); 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void 72262306a36Sopenharmony_civmw_sou_primary_plane_atomic_update(struct drm_plane *plane, 72362306a36Sopenharmony_ci struct drm_atomic_state *state) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane); 72662306a36Sopenharmony_ci struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane); 72762306a36Sopenharmony_ci struct drm_crtc *crtc = new_state->crtc; 72862306a36Sopenharmony_ci struct vmw_fence_obj *fence = NULL; 72962306a36Sopenharmony_ci int ret; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* In case of device error, maintain consistent atomic state */ 73262306a36Sopenharmony_ci if (crtc && new_state->fb) { 73362306a36Sopenharmony_ci struct vmw_private *dev_priv = vmw_priv(crtc->dev); 73462306a36Sopenharmony_ci struct vmw_framebuffer *vfb = 73562306a36Sopenharmony_ci vmw_framebuffer_to_vfb(new_state->fb); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (vfb->bo) 73862306a36Sopenharmony_ci ret = vmw_sou_plane_update_bo(dev_priv, plane, 73962306a36Sopenharmony_ci old_state, vfb, &fence); 74062306a36Sopenharmony_ci else 74162306a36Sopenharmony_ci ret = vmw_sou_plane_update_surface(dev_priv, plane, 74262306a36Sopenharmony_ci old_state, vfb, 74362306a36Sopenharmony_ci &fence); 74462306a36Sopenharmony_ci if (ret != 0) 74562306a36Sopenharmony_ci DRM_ERROR("Failed to update screen.\n"); 74662306a36Sopenharmony_ci } else { 74762306a36Sopenharmony_ci /* Do nothing when fb and crtc is NULL (blank crtc) */ 74862306a36Sopenharmony_ci return; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (fence) 75262306a36Sopenharmony_ci vmw_fence_obj_unreference(&fence); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic const struct drm_plane_funcs vmw_sou_plane_funcs = { 75762306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 75862306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 75962306a36Sopenharmony_ci .destroy = vmw_du_primary_plane_destroy, 76062306a36Sopenharmony_ci .reset = vmw_du_plane_reset, 76162306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 76262306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 76362306a36Sopenharmony_ci}; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic const struct drm_plane_funcs vmw_sou_cursor_funcs = { 76662306a36Sopenharmony_ci .update_plane = drm_atomic_helper_update_plane, 76762306a36Sopenharmony_ci .disable_plane = drm_atomic_helper_disable_plane, 76862306a36Sopenharmony_ci .destroy = vmw_du_cursor_plane_destroy, 76962306a36Sopenharmony_ci .reset = vmw_du_plane_reset, 77062306a36Sopenharmony_ci .atomic_duplicate_state = vmw_du_plane_duplicate_state, 77162306a36Sopenharmony_ci .atomic_destroy_state = vmw_du_plane_destroy_state, 77262306a36Sopenharmony_ci}; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci/* 77562306a36Sopenharmony_ci * Atomic Helpers 77662306a36Sopenharmony_ci */ 77762306a36Sopenharmony_cistatic const struct 77862306a36Sopenharmony_cidrm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = { 77962306a36Sopenharmony_ci .atomic_check = vmw_du_cursor_plane_atomic_check, 78062306a36Sopenharmony_ci .atomic_update = vmw_du_cursor_plane_atomic_update, 78162306a36Sopenharmony_ci .prepare_fb = vmw_du_cursor_plane_prepare_fb, 78262306a36Sopenharmony_ci .cleanup_fb = vmw_du_cursor_plane_cleanup_fb, 78362306a36Sopenharmony_ci}; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic const struct 78662306a36Sopenharmony_cidrm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = { 78762306a36Sopenharmony_ci .atomic_check = vmw_du_primary_plane_atomic_check, 78862306a36Sopenharmony_ci .atomic_update = vmw_sou_primary_plane_atomic_update, 78962306a36Sopenharmony_ci .prepare_fb = vmw_sou_primary_plane_prepare_fb, 79062306a36Sopenharmony_ci .cleanup_fb = vmw_sou_primary_plane_cleanup_fb, 79162306a36Sopenharmony_ci}; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = { 79462306a36Sopenharmony_ci .prepare = vmw_sou_crtc_helper_prepare, 79562306a36Sopenharmony_ci .mode_set_nofb = vmw_sou_crtc_mode_set_nofb, 79662306a36Sopenharmony_ci .atomic_check = vmw_du_crtc_atomic_check, 79762306a36Sopenharmony_ci .atomic_begin = vmw_du_crtc_atomic_begin, 79862306a36Sopenharmony_ci .atomic_flush = vmw_du_crtc_atomic_flush, 79962306a36Sopenharmony_ci .atomic_enable = vmw_sou_crtc_atomic_enable, 80062306a36Sopenharmony_ci .atomic_disable = vmw_sou_crtc_atomic_disable, 80162306a36Sopenharmony_ci}; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_cistatic int vmw_sou_init(struct vmw_private *dev_priv, unsigned unit) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci struct vmw_screen_object_unit *sou; 80762306a36Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 80862306a36Sopenharmony_ci struct drm_connector *connector; 80962306a36Sopenharmony_ci struct drm_encoder *encoder; 81062306a36Sopenharmony_ci struct drm_plane *primary; 81162306a36Sopenharmony_ci struct vmw_cursor_plane *cursor; 81262306a36Sopenharmony_ci struct drm_crtc *crtc; 81362306a36Sopenharmony_ci int ret; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci sou = kzalloc(sizeof(*sou), GFP_KERNEL); 81662306a36Sopenharmony_ci if (!sou) 81762306a36Sopenharmony_ci return -ENOMEM; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci sou->base.unit = unit; 82062306a36Sopenharmony_ci crtc = &sou->base.crtc; 82162306a36Sopenharmony_ci encoder = &sou->base.encoder; 82262306a36Sopenharmony_ci connector = &sou->base.connector; 82362306a36Sopenharmony_ci primary = &sou->base.primary; 82462306a36Sopenharmony_ci cursor = &sou->base.cursor; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci sou->base.pref_active = (unit == 0); 82762306a36Sopenharmony_ci sou->base.pref_width = dev_priv->initial_width; 82862306a36Sopenharmony_ci sou->base.pref_height = dev_priv->initial_height; 82962306a36Sopenharmony_ci sou->base.pref_mode = NULL; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* 83262306a36Sopenharmony_ci * Remove this after enabling atomic because property values can 83362306a36Sopenharmony_ci * only exist in a state object 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_ci sou->base.is_implicit = false; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci /* Initialize primary plane */ 83862306a36Sopenharmony_ci ret = drm_universal_plane_init(dev, primary, 83962306a36Sopenharmony_ci 0, &vmw_sou_plane_funcs, 84062306a36Sopenharmony_ci vmw_primary_plane_formats, 84162306a36Sopenharmony_ci ARRAY_SIZE(vmw_primary_plane_formats), 84262306a36Sopenharmony_ci NULL, DRM_PLANE_TYPE_PRIMARY, NULL); 84362306a36Sopenharmony_ci if (ret) { 84462306a36Sopenharmony_ci DRM_ERROR("Failed to initialize primary plane"); 84562306a36Sopenharmony_ci goto err_free; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci drm_plane_helper_add(primary, &vmw_sou_primary_plane_helper_funcs); 84962306a36Sopenharmony_ci drm_plane_enable_fb_damage_clips(primary); 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci /* Initialize cursor plane */ 85262306a36Sopenharmony_ci ret = drm_universal_plane_init(dev, &cursor->base, 85362306a36Sopenharmony_ci 0, &vmw_sou_cursor_funcs, 85462306a36Sopenharmony_ci vmw_cursor_plane_formats, 85562306a36Sopenharmony_ci ARRAY_SIZE(vmw_cursor_plane_formats), 85662306a36Sopenharmony_ci NULL, DRM_PLANE_TYPE_CURSOR, NULL); 85762306a36Sopenharmony_ci if (ret) { 85862306a36Sopenharmony_ci DRM_ERROR("Failed to initialize cursor plane"); 85962306a36Sopenharmony_ci drm_plane_cleanup(&sou->base.primary); 86062306a36Sopenharmony_ci goto err_free; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci drm_plane_helper_add(&cursor->base, &vmw_sou_cursor_plane_helper_funcs); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci ret = drm_connector_init(dev, connector, &vmw_sou_connector_funcs, 86662306a36Sopenharmony_ci DRM_MODE_CONNECTOR_VIRTUAL); 86762306a36Sopenharmony_ci if (ret) { 86862306a36Sopenharmony_ci DRM_ERROR("Failed to initialize connector\n"); 86962306a36Sopenharmony_ci goto err_free; 87062306a36Sopenharmony_ci } 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci drm_connector_helper_add(connector, &vmw_sou_connector_helper_funcs); 87362306a36Sopenharmony_ci connector->status = vmw_du_connector_detect(connector, true); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci ret = drm_encoder_init(dev, encoder, &vmw_screen_object_encoder_funcs, 87662306a36Sopenharmony_ci DRM_MODE_ENCODER_VIRTUAL, NULL); 87762306a36Sopenharmony_ci if (ret) { 87862306a36Sopenharmony_ci DRM_ERROR("Failed to initialize encoder\n"); 87962306a36Sopenharmony_ci goto err_free_connector; 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci (void) drm_connector_attach_encoder(connector, encoder); 88362306a36Sopenharmony_ci encoder->possible_crtcs = (1 << unit); 88462306a36Sopenharmony_ci encoder->possible_clones = 0; 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci ret = drm_connector_register(connector); 88762306a36Sopenharmony_ci if (ret) { 88862306a36Sopenharmony_ci DRM_ERROR("Failed to register connector\n"); 88962306a36Sopenharmony_ci goto err_free_encoder; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci ret = drm_crtc_init_with_planes(dev, crtc, primary, 89362306a36Sopenharmony_ci &cursor->base, 89462306a36Sopenharmony_ci &vmw_screen_object_crtc_funcs, NULL); 89562306a36Sopenharmony_ci if (ret) { 89662306a36Sopenharmony_ci DRM_ERROR("Failed to initialize CRTC\n"); 89762306a36Sopenharmony_ci goto err_free_unregister; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci drm_crtc_helper_add(crtc, &vmw_sou_crtc_helper_funcs); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci drm_mode_crtc_set_gamma_size(crtc, 256); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 90562306a36Sopenharmony_ci dev_priv->hotplug_mode_update_property, 1); 90662306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 90762306a36Sopenharmony_ci dev->mode_config.suggested_x_property, 0); 90862306a36Sopenharmony_ci drm_object_attach_property(&connector->base, 90962306a36Sopenharmony_ci dev->mode_config.suggested_y_property, 0); 91062306a36Sopenharmony_ci return 0; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_cierr_free_unregister: 91362306a36Sopenharmony_ci drm_connector_unregister(connector); 91462306a36Sopenharmony_cierr_free_encoder: 91562306a36Sopenharmony_ci drm_encoder_cleanup(encoder); 91662306a36Sopenharmony_cierr_free_connector: 91762306a36Sopenharmony_ci drm_connector_cleanup(connector); 91862306a36Sopenharmony_cierr_free: 91962306a36Sopenharmony_ci kfree(sou); 92062306a36Sopenharmony_ci return ret; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ciint vmw_kms_sou_init_display(struct vmw_private *dev_priv) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct drm_device *dev = &dev_priv->drm; 92662306a36Sopenharmony_ci int i; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* Screen objects won't work if GMR's aren't available */ 92962306a36Sopenharmony_ci if (!dev_priv->has_gmr) 93062306a36Sopenharmony_ci return -ENOSYS; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (!(dev_priv->capabilities & SVGA_CAP_SCREEN_OBJECT_2)) { 93362306a36Sopenharmony_ci return -ENOSYS; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) 93762306a36Sopenharmony_ci vmw_sou_init(dev_priv, i); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci dev_priv->active_display_unit = vmw_du_screen_object; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci drm_mode_config_reset(dev); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci return 0; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic int do_bo_define_gmrfb(struct vmw_private *dev_priv, 94762306a36Sopenharmony_ci struct vmw_framebuffer *framebuffer) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct vmw_bo *buf = 95062306a36Sopenharmony_ci container_of(framebuffer, struct vmw_framebuffer_bo, 95162306a36Sopenharmony_ci base)->buffer; 95262306a36Sopenharmony_ci int depth = framebuffer->base.format->depth; 95362306a36Sopenharmony_ci struct { 95462306a36Sopenharmony_ci uint32_t header; 95562306a36Sopenharmony_ci SVGAFifoCmdDefineGMRFB body; 95662306a36Sopenharmony_ci } *cmd; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* Emulate RGBA support, contrary to svga_reg.h this is not 95962306a36Sopenharmony_ci * supported by hosts. This is only a problem if we are reading 96062306a36Sopenharmony_ci * this value later and expecting what we uploaded back. 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci if (depth == 32) 96362306a36Sopenharmony_ci depth = 24; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd)); 96662306a36Sopenharmony_ci if (!cmd) 96762306a36Sopenharmony_ci return -ENOMEM; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci cmd->header = SVGA_CMD_DEFINE_GMRFB; 97062306a36Sopenharmony_ci cmd->body.format.bitsPerPixel = framebuffer->base.format->cpp[0] * 8; 97162306a36Sopenharmony_ci cmd->body.format.colorDepth = depth; 97262306a36Sopenharmony_ci cmd->body.format.reserved = 0; 97362306a36Sopenharmony_ci cmd->body.bytesPerLine = framebuffer->base.pitches[0]; 97462306a36Sopenharmony_ci /* Buffer is reserved in vram or GMR */ 97562306a36Sopenharmony_ci vmw_bo_get_guest_ptr(&buf->tbo, &cmd->body.ptr); 97662306a36Sopenharmony_ci vmw_cmd_commit(dev_priv, sizeof(*cmd)); 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci return 0; 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci/** 98262306a36Sopenharmony_ci * vmw_sou_surface_fifo_commit - Callback to fill in and submit a 98362306a36Sopenharmony_ci * blit surface to screen command. 98462306a36Sopenharmony_ci * 98562306a36Sopenharmony_ci * @dirty: The closure structure. 98662306a36Sopenharmony_ci * 98762306a36Sopenharmony_ci * Fills in the missing fields in the command, and translates the cliprects 98862306a36Sopenharmony_ci * to match the destination bounding box encoded. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_cistatic void vmw_sou_surface_fifo_commit(struct vmw_kms_dirty *dirty) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct vmw_kms_sou_surface_dirty *sdirty = 99362306a36Sopenharmony_ci container_of(dirty, typeof(*sdirty), base); 99462306a36Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; 99562306a36Sopenharmony_ci s32 trans_x = dirty->unit->crtc.x - sdirty->dst_x; 99662306a36Sopenharmony_ci s32 trans_y = dirty->unit->crtc.y - sdirty->dst_y; 99762306a36Sopenharmony_ci size_t region_size = dirty->num_hits * sizeof(SVGASignedRect); 99862306a36Sopenharmony_ci SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; 99962306a36Sopenharmony_ci int i; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (!dirty->num_hits) { 100262306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, 0); 100362306a36Sopenharmony_ci return; 100462306a36Sopenharmony_ci } 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci cmd->header.id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN; 100762306a36Sopenharmony_ci cmd->header.size = sizeof(cmd->body) + region_size; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* 101062306a36Sopenharmony_ci * Use the destination bounding box to specify destination - and 101162306a36Sopenharmony_ci * source bounding regions. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_ci cmd->body.destRect.left = sdirty->left; 101462306a36Sopenharmony_ci cmd->body.destRect.right = sdirty->right; 101562306a36Sopenharmony_ci cmd->body.destRect.top = sdirty->top; 101662306a36Sopenharmony_ci cmd->body.destRect.bottom = sdirty->bottom; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci cmd->body.srcRect.left = sdirty->left + trans_x; 101962306a36Sopenharmony_ci cmd->body.srcRect.right = sdirty->right + trans_x; 102062306a36Sopenharmony_ci cmd->body.srcRect.top = sdirty->top + trans_y; 102162306a36Sopenharmony_ci cmd->body.srcRect.bottom = sdirty->bottom + trans_y; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci cmd->body.srcImage.sid = sdirty->sid; 102462306a36Sopenharmony_ci cmd->body.destScreenId = dirty->unit->unit; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Blits are relative to the destination rect. Translate. */ 102762306a36Sopenharmony_ci for (i = 0; i < dirty->num_hits; ++i, ++blit) { 102862306a36Sopenharmony_ci blit->left -= sdirty->left; 102962306a36Sopenharmony_ci blit->right -= sdirty->left; 103062306a36Sopenharmony_ci blit->top -= sdirty->top; 103162306a36Sopenharmony_ci blit->bottom -= sdirty->top; 103262306a36Sopenharmony_ci } 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, region_size + sizeof(*cmd)); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci sdirty->left = sdirty->top = S32_MAX; 103762306a36Sopenharmony_ci sdirty->right = sdirty->bottom = S32_MIN; 103862306a36Sopenharmony_ci} 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci/** 104162306a36Sopenharmony_ci * vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect. 104262306a36Sopenharmony_ci * 104362306a36Sopenharmony_ci * @dirty: The closure structure 104462306a36Sopenharmony_ci * 104562306a36Sopenharmony_ci * Encodes a SVGASignedRect cliprect and updates the bounding box of the 104662306a36Sopenharmony_ci * BLIT_SURFACE_TO_SCREEN command. 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_cistatic void vmw_sou_surface_clip(struct vmw_kms_dirty *dirty) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci struct vmw_kms_sou_surface_dirty *sdirty = 105162306a36Sopenharmony_ci container_of(dirty, typeof(*sdirty), base); 105262306a36Sopenharmony_ci struct vmw_kms_sou_dirty_cmd *cmd = dirty->cmd; 105362306a36Sopenharmony_ci SVGASignedRect *blit = (SVGASignedRect *) &cmd[1]; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci /* Destination rect. */ 105662306a36Sopenharmony_ci blit += dirty->num_hits; 105762306a36Sopenharmony_ci blit->left = dirty->unit_x1; 105862306a36Sopenharmony_ci blit->top = dirty->unit_y1; 105962306a36Sopenharmony_ci blit->right = dirty->unit_x2; 106062306a36Sopenharmony_ci blit->bottom = dirty->unit_y2; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* Destination bounding box */ 106362306a36Sopenharmony_ci sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1); 106462306a36Sopenharmony_ci sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1); 106562306a36Sopenharmony_ci sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2); 106662306a36Sopenharmony_ci sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2); 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci dirty->num_hits++; 106962306a36Sopenharmony_ci} 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci/** 107262306a36Sopenharmony_ci * vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer 107362306a36Sopenharmony_ci * 107462306a36Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 107562306a36Sopenharmony_ci * @framebuffer: Pointer to the surface-buffer backed framebuffer. 107662306a36Sopenharmony_ci * @clips: Array of clip rects. Either @clips or @vclips must be NULL. 107762306a36Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 107862306a36Sopenharmony_ci * be NULL. 107962306a36Sopenharmony_ci * @srf: Pointer to surface to blit from. If NULL, the surface attached 108062306a36Sopenharmony_ci * to @framebuffer will be used. 108162306a36Sopenharmony_ci * @dest_x: X coordinate offset to align @srf with framebuffer coordinates. 108262306a36Sopenharmony_ci * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates. 108362306a36Sopenharmony_ci * @num_clips: Number of clip rects in @clips. 108462306a36Sopenharmony_ci * @inc: Increment to use when looping over @clips. 108562306a36Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to a 108662306a36Sopenharmony_ci * struct vmw_fence_obj. The returned fence pointer may be NULL in which 108762306a36Sopenharmony_ci * case the device has already synchronized. 108862306a36Sopenharmony_ci * @crtc: If crtc is passed, perform surface dirty on that crtc only. 108962306a36Sopenharmony_ci * 109062306a36Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 109162306a36Sopenharmony_ci * interrupted. 109262306a36Sopenharmony_ci */ 109362306a36Sopenharmony_ciint vmw_kms_sou_do_surface_dirty(struct vmw_private *dev_priv, 109462306a36Sopenharmony_ci struct vmw_framebuffer *framebuffer, 109562306a36Sopenharmony_ci struct drm_clip_rect *clips, 109662306a36Sopenharmony_ci struct drm_vmw_rect *vclips, 109762306a36Sopenharmony_ci struct vmw_resource *srf, 109862306a36Sopenharmony_ci s32 dest_x, 109962306a36Sopenharmony_ci s32 dest_y, 110062306a36Sopenharmony_ci unsigned num_clips, int inc, 110162306a36Sopenharmony_ci struct vmw_fence_obj **out_fence, 110262306a36Sopenharmony_ci struct drm_crtc *crtc) 110362306a36Sopenharmony_ci{ 110462306a36Sopenharmony_ci struct vmw_framebuffer_surface *vfbs = 110562306a36Sopenharmony_ci container_of(framebuffer, typeof(*vfbs), base); 110662306a36Sopenharmony_ci struct vmw_kms_sou_surface_dirty sdirty; 110762306a36Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 110862306a36Sopenharmony_ci int ret; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (!srf) 111162306a36Sopenharmony_ci srf = &vfbs->surface->res; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE, 111462306a36Sopenharmony_ci NULL, NULL); 111562306a36Sopenharmony_ci if (ret) 111662306a36Sopenharmony_ci return ret; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true); 111962306a36Sopenharmony_ci if (ret) 112062306a36Sopenharmony_ci goto out_unref; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci sdirty.base.fifo_commit = vmw_sou_surface_fifo_commit; 112362306a36Sopenharmony_ci sdirty.base.clip = vmw_sou_surface_clip; 112462306a36Sopenharmony_ci sdirty.base.dev_priv = dev_priv; 112562306a36Sopenharmony_ci sdirty.base.fifo_reserve_size = sizeof(struct vmw_kms_sou_dirty_cmd) + 112662306a36Sopenharmony_ci sizeof(SVGASignedRect) * num_clips; 112762306a36Sopenharmony_ci sdirty.base.crtc = crtc; 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci sdirty.sid = srf->id; 113062306a36Sopenharmony_ci sdirty.left = sdirty.top = S32_MAX; 113162306a36Sopenharmony_ci sdirty.right = sdirty.bottom = S32_MIN; 113262306a36Sopenharmony_ci sdirty.dst_x = dest_x; 113362306a36Sopenharmony_ci sdirty.dst_y = dest_y; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 113662306a36Sopenharmony_ci dest_x, dest_y, num_clips, inc, 113762306a36Sopenharmony_ci &sdirty.base); 113862306a36Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 113962306a36Sopenharmony_ci NULL); 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci return ret; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ciout_unref: 114462306a36Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 114562306a36Sopenharmony_ci return ret; 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci/** 114962306a36Sopenharmony_ci * vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips. 115062306a36Sopenharmony_ci * 115162306a36Sopenharmony_ci * @dirty: The closure structure. 115262306a36Sopenharmony_ci * 115362306a36Sopenharmony_ci * Commits a previously built command buffer of readback clips. 115462306a36Sopenharmony_ci */ 115562306a36Sopenharmony_cistatic void vmw_sou_bo_fifo_commit(struct vmw_kms_dirty *dirty) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci if (!dirty->num_hits) { 115862306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, 0); 115962306a36Sopenharmony_ci return; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, 116362306a36Sopenharmony_ci sizeof(struct vmw_kms_sou_bo_blit) * 116462306a36Sopenharmony_ci dirty->num_hits); 116562306a36Sopenharmony_ci} 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci/** 116862306a36Sopenharmony_ci * vmw_sou_bo_clip - Callback to encode a readback cliprect. 116962306a36Sopenharmony_ci * 117062306a36Sopenharmony_ci * @dirty: The closure structure 117162306a36Sopenharmony_ci * 117262306a36Sopenharmony_ci * Encodes a BLIT_GMRFB_TO_SCREEN cliprect. 117362306a36Sopenharmony_ci */ 117462306a36Sopenharmony_cistatic void vmw_sou_bo_clip(struct vmw_kms_dirty *dirty) 117562306a36Sopenharmony_ci{ 117662306a36Sopenharmony_ci struct vmw_kms_sou_bo_blit *blit = dirty->cmd; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci blit += dirty->num_hits; 117962306a36Sopenharmony_ci blit->header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN; 118062306a36Sopenharmony_ci blit->body.destScreenId = dirty->unit->unit; 118162306a36Sopenharmony_ci blit->body.srcOrigin.x = dirty->fb_x; 118262306a36Sopenharmony_ci blit->body.srcOrigin.y = dirty->fb_y; 118362306a36Sopenharmony_ci blit->body.destRect.left = dirty->unit_x1; 118462306a36Sopenharmony_ci blit->body.destRect.top = dirty->unit_y1; 118562306a36Sopenharmony_ci blit->body.destRect.right = dirty->unit_x2; 118662306a36Sopenharmony_ci blit->body.destRect.bottom = dirty->unit_y2; 118762306a36Sopenharmony_ci dirty->num_hits++; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci/** 119162306a36Sopenharmony_ci * vmw_kms_sou_do_bo_dirty - Dirty part of a buffer-object backed framebuffer 119262306a36Sopenharmony_ci * 119362306a36Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 119462306a36Sopenharmony_ci * @framebuffer: Pointer to the buffer-object backed framebuffer. 119562306a36Sopenharmony_ci * @clips: Array of clip rects. 119662306a36Sopenharmony_ci * @vclips: Alternate array of clip rects. Either @clips or @vclips must 119762306a36Sopenharmony_ci * be NULL. 119862306a36Sopenharmony_ci * @num_clips: Number of clip rects in @clips. 119962306a36Sopenharmony_ci * @increment: Increment to use when looping over @clips. 120062306a36Sopenharmony_ci * @interruptible: Whether to perform waits interruptible if possible. 120162306a36Sopenharmony_ci * @out_fence: If non-NULL, will return a ref-counted pointer to a 120262306a36Sopenharmony_ci * struct vmw_fence_obj. The returned fence pointer may be NULL in which 120362306a36Sopenharmony_ci * case the device has already synchronized. 120462306a36Sopenharmony_ci * @crtc: If crtc is passed, perform bo dirty on that crtc only. 120562306a36Sopenharmony_ci * 120662306a36Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 120762306a36Sopenharmony_ci * interrupted. 120862306a36Sopenharmony_ci */ 120962306a36Sopenharmony_ciint vmw_kms_sou_do_bo_dirty(struct vmw_private *dev_priv, 121062306a36Sopenharmony_ci struct vmw_framebuffer *framebuffer, 121162306a36Sopenharmony_ci struct drm_clip_rect *clips, 121262306a36Sopenharmony_ci struct drm_vmw_rect *vclips, 121362306a36Sopenharmony_ci unsigned num_clips, int increment, 121462306a36Sopenharmony_ci bool interruptible, 121562306a36Sopenharmony_ci struct vmw_fence_obj **out_fence, 121662306a36Sopenharmony_ci struct drm_crtc *crtc) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct vmw_bo *buf = 121962306a36Sopenharmony_ci container_of(framebuffer, struct vmw_framebuffer_bo, 122062306a36Sopenharmony_ci base)->buffer; 122162306a36Sopenharmony_ci struct vmw_kms_dirty dirty; 122262306a36Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 122362306a36Sopenharmony_ci int ret; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci vmw_bo_placement_set(buf, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM, 122662306a36Sopenharmony_ci VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM); 122762306a36Sopenharmony_ci ret = vmw_validation_add_bo(&val_ctx, buf); 122862306a36Sopenharmony_ci if (ret) 122962306a36Sopenharmony_ci return ret; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, NULL, interruptible); 123262306a36Sopenharmony_ci if (ret) 123362306a36Sopenharmony_ci goto out_unref; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci ret = do_bo_define_gmrfb(dev_priv, framebuffer); 123662306a36Sopenharmony_ci if (unlikely(ret != 0)) 123762306a36Sopenharmony_ci goto out_revert; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci dirty.crtc = crtc; 124062306a36Sopenharmony_ci dirty.fifo_commit = vmw_sou_bo_fifo_commit; 124162306a36Sopenharmony_ci dirty.clip = vmw_sou_bo_clip; 124262306a36Sopenharmony_ci dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_bo_blit) * 124362306a36Sopenharmony_ci num_clips; 124462306a36Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips, 124562306a36Sopenharmony_ci 0, 0, num_clips, increment, &dirty); 124662306a36Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence, 124762306a36Sopenharmony_ci NULL); 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return ret; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ciout_revert: 125262306a36Sopenharmony_ci vmw_validation_revert(&val_ctx); 125362306a36Sopenharmony_ciout_unref: 125462306a36Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci return ret; 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci/** 126162306a36Sopenharmony_ci * vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips. 126262306a36Sopenharmony_ci * 126362306a36Sopenharmony_ci * @dirty: The closure structure. 126462306a36Sopenharmony_ci * 126562306a36Sopenharmony_ci * Commits a previously built command buffer of readback clips. 126662306a36Sopenharmony_ci */ 126762306a36Sopenharmony_cistatic void vmw_sou_readback_fifo_commit(struct vmw_kms_dirty *dirty) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci if (!dirty->num_hits) { 127062306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, 0); 127162306a36Sopenharmony_ci return; 127262306a36Sopenharmony_ci } 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci vmw_cmd_commit(dirty->dev_priv, 127562306a36Sopenharmony_ci sizeof(struct vmw_kms_sou_readback_blit) * 127662306a36Sopenharmony_ci dirty->num_hits); 127762306a36Sopenharmony_ci} 127862306a36Sopenharmony_ci 127962306a36Sopenharmony_ci/** 128062306a36Sopenharmony_ci * vmw_sou_readback_clip - Callback to encode a readback cliprect. 128162306a36Sopenharmony_ci * 128262306a36Sopenharmony_ci * @dirty: The closure structure 128362306a36Sopenharmony_ci * 128462306a36Sopenharmony_ci * Encodes a BLIT_SCREEN_TO_GMRFB cliprect. 128562306a36Sopenharmony_ci */ 128662306a36Sopenharmony_cistatic void vmw_sou_readback_clip(struct vmw_kms_dirty *dirty) 128762306a36Sopenharmony_ci{ 128862306a36Sopenharmony_ci struct vmw_kms_sou_readback_blit *blit = dirty->cmd; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci blit += dirty->num_hits; 129162306a36Sopenharmony_ci blit->header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB; 129262306a36Sopenharmony_ci blit->body.srcScreenId = dirty->unit->unit; 129362306a36Sopenharmony_ci blit->body.destOrigin.x = dirty->fb_x; 129462306a36Sopenharmony_ci blit->body.destOrigin.y = dirty->fb_y; 129562306a36Sopenharmony_ci blit->body.srcRect.left = dirty->unit_x1; 129662306a36Sopenharmony_ci blit->body.srcRect.top = dirty->unit_y1; 129762306a36Sopenharmony_ci blit->body.srcRect.right = dirty->unit_x2; 129862306a36Sopenharmony_ci blit->body.srcRect.bottom = dirty->unit_y2; 129962306a36Sopenharmony_ci dirty->num_hits++; 130062306a36Sopenharmony_ci} 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci/** 130362306a36Sopenharmony_ci * vmw_kms_sou_readback - Perform a readback from the screen object system to 130462306a36Sopenharmony_ci * a buffer-object backed framebuffer. 130562306a36Sopenharmony_ci * 130662306a36Sopenharmony_ci * @dev_priv: Pointer to the device private structure. 130762306a36Sopenharmony_ci * @file_priv: Pointer to a struct drm_file identifying the caller. 130862306a36Sopenharmony_ci * Must be set to NULL if @user_fence_rep is NULL. 130962306a36Sopenharmony_ci * @vfb: Pointer to the buffer-object backed framebuffer. 131062306a36Sopenharmony_ci * @user_fence_rep: User-space provided structure for fence information. 131162306a36Sopenharmony_ci * Must be set to non-NULL if @file_priv is non-NULL. 131262306a36Sopenharmony_ci * @vclips: Array of clip rects. 131362306a36Sopenharmony_ci * @num_clips: Number of clip rects in @vclips. 131462306a36Sopenharmony_ci * @crtc: If crtc is passed, readback on that crtc only. 131562306a36Sopenharmony_ci * 131662306a36Sopenharmony_ci * Returns 0 on success, negative error code on failure. -ERESTARTSYS if 131762306a36Sopenharmony_ci * interrupted. 131862306a36Sopenharmony_ci */ 131962306a36Sopenharmony_ciint vmw_kms_sou_readback(struct vmw_private *dev_priv, 132062306a36Sopenharmony_ci struct drm_file *file_priv, 132162306a36Sopenharmony_ci struct vmw_framebuffer *vfb, 132262306a36Sopenharmony_ci struct drm_vmw_fence_rep __user *user_fence_rep, 132362306a36Sopenharmony_ci struct drm_vmw_rect *vclips, 132462306a36Sopenharmony_ci uint32_t num_clips, 132562306a36Sopenharmony_ci struct drm_crtc *crtc) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci struct vmw_bo *buf = 132862306a36Sopenharmony_ci container_of(vfb, struct vmw_framebuffer_bo, base)->buffer; 132962306a36Sopenharmony_ci struct vmw_kms_dirty dirty; 133062306a36Sopenharmony_ci DECLARE_VAL_CONTEXT(val_ctx, NULL, 0); 133162306a36Sopenharmony_ci int ret; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci vmw_bo_placement_set(buf, VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM, 133462306a36Sopenharmony_ci VMW_BO_DOMAIN_GMR | VMW_BO_DOMAIN_VRAM); 133562306a36Sopenharmony_ci ret = vmw_validation_add_bo(&val_ctx, buf); 133662306a36Sopenharmony_ci if (ret) 133762306a36Sopenharmony_ci return ret; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci ret = vmw_validation_prepare(&val_ctx, NULL, true); 134062306a36Sopenharmony_ci if (ret) 134162306a36Sopenharmony_ci goto out_unref; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci ret = do_bo_define_gmrfb(dev_priv, vfb); 134462306a36Sopenharmony_ci if (unlikely(ret != 0)) 134562306a36Sopenharmony_ci goto out_revert; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci dirty.crtc = crtc; 134862306a36Sopenharmony_ci dirty.fifo_commit = vmw_sou_readback_fifo_commit; 134962306a36Sopenharmony_ci dirty.clip = vmw_sou_readback_clip; 135062306a36Sopenharmony_ci dirty.fifo_reserve_size = sizeof(struct vmw_kms_sou_readback_blit) * 135162306a36Sopenharmony_ci num_clips; 135262306a36Sopenharmony_ci ret = vmw_kms_helper_dirty(dev_priv, vfb, NULL, vclips, 135362306a36Sopenharmony_ci 0, 0, num_clips, 1, &dirty); 135462306a36Sopenharmony_ci vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL, 135562306a36Sopenharmony_ci user_fence_rep); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci return ret; 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ciout_revert: 136062306a36Sopenharmony_ci vmw_validation_revert(&val_ctx); 136162306a36Sopenharmony_ciout_unref: 136262306a36Sopenharmony_ci vmw_validation_unref_lists(&val_ctx); 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci return ret; 136562306a36Sopenharmony_ci} 1366