Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/******************************************************************************
   3 *
   4 * Copyright (c) 2014-2024 Broadcom. All Rights Reserved. The term
   5 * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a
   8 * copy of this software and associated documentation files (the
   9 * "Software"), to deal in the Software without restriction, including
  10 * without limitation the rights to use, copy, modify, merge, publish,
  11 * distribute, sub license, and/or sell copies of the Software, and to
  12 * permit persons to whom the Software is furnished to do so, subject to
  13 * the following conditions:
  14 *
  15 * The above copyright notice and this permission notice (including the
  16 * next paragraph) shall be included in all copies or substantial portions
  17 * of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
  26 *
  27 ******************************************************************************/
  28
  29#include "vmwgfx_bo.h"
  30#include "vmwgfx_kms.h"
  31#include "vmwgfx_vkms.h"
  32#include "vmw_surface_cache.h"
  33#include <linux/fsnotify.h>
  34
  35#include <drm/drm_atomic.h>
  36#include <drm/drm_atomic_helper.h>
  37#include <drm/drm_damage_helper.h>
  38#include <drm/drm_fourcc.h>
  39#include <drm/drm_vblank.h>
  40
  41#define vmw_crtc_to_stdu(x) \
  42	container_of(x, struct vmw_screen_target_display_unit, base.crtc)
  43#define vmw_encoder_to_stdu(x) \
  44	container_of(x, struct vmw_screen_target_display_unit, base.encoder)
  45#define vmw_connector_to_stdu(x) \
  46	container_of(x, struct vmw_screen_target_display_unit, base.connector)
  47
  48/*
  49 * Some renderers such as llvmpipe will align the width and height of their
  50 * buffers to match their tile size. We need to keep this in mind when exposing
  51 * modes to userspace so that this possible over-allocation will not exceed
  52 * graphics memory. 64x64 pixels seems to be a reasonable upper bound for the
  53 * tile size of current renderers.
  54 */
  55#define GPU_TILE_SIZE 64
  56
  57enum stdu_content_type {
  58	SAME_AS_DISPLAY = 0,
  59	SEPARATE_SURFACE,
  60	SEPARATE_BO
  61};
  62
  63/**
  64 * struct vmw_stdu_dirty - closure structure for the update functions
  65 *
  66 * @base: The base type we derive from. Used by vmw_kms_helper_dirty().
  67 * @left: Left side of bounding box.
  68 * @right: Right side of bounding box.
  69 * @top: Top side of bounding box.
  70 * @bottom: Bottom side of bounding box.
  71 * @fb_left: Left side of the framebuffer/content bounding box
  72 * @fb_top: Top of the framebuffer/content bounding box
  73 * @pitch: framebuffer pitch (stride)
  74 * @buf: buffer object when DMA-ing between buffer and screen targets.
  75 * @sid: Surface ID when copying between surface and screen targets.
  76 */
  77struct vmw_stdu_dirty {
  78	struct vmw_kms_dirty base;
  79	s32 left, right, top, bottom;
  80	s32 fb_left, fb_top;
  81	u32 pitch;
  82	union {
  83		struct vmw_bo *buf;
  84		u32 sid;
  85	};
  86};
  87
  88/*
  89 * SVGA commands that are used by this code. Please see the device headers
  90 * for explanation.
  91 */
  92struct vmw_stdu_update {
  93	SVGA3dCmdHeader header;
  94	SVGA3dCmdUpdateGBScreenTarget body;
  95};
  96
  97struct vmw_stdu_surface_copy {
  98	SVGA3dCmdHeader      header;
  99	SVGA3dCmdSurfaceCopy body;
 100};
 101
 102struct vmw_stdu_update_gb_image {
 103	SVGA3dCmdHeader header;
 104	SVGA3dCmdUpdateGBImage body;
 105};
 106
 107/**
 108 * struct vmw_screen_target_display_unit - conglomerated STDU structure
 109 *
 110 * @base: VMW specific DU structure
 111 * @display_srf: surface to be displayed.  The dimension of this will always
 112 *               match the display mode.  If the display mode matches
 113 *               content_vfbs dimensions, then this is a pointer into the
 114 *               corresponding field in content_vfbs.  If not, then this
 115 *               is a separate buffer to which content_vfbs will blit to.
 116 * @content_fb_type: content_fb type
 117 * @display_width:  display width
 118 * @display_height: display height
 119 * @defined:     true if the current display unit has been initialized
 120 * @cpp:         Bytes per pixel
 121 */
 122struct vmw_screen_target_display_unit {
 123	struct vmw_display_unit base;
 124	struct vmw_surface *display_srf;
 125	enum stdu_content_type content_fb_type;
 126	s32 display_width, display_height;
 127
 128	bool defined;
 129
 130	/* For CPU Blit */
 131	unsigned int cpp;
 132};
 133
 134
 135
 136static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu);
 137
 138
 139
 140/******************************************************************************
 141 * Screen Target Display Unit CRTC Functions
 142 *****************************************************************************/
 143
 144/**
 145 * vmw_stdu_crtc_destroy - cleans up the STDU
 146 *
 147 * @crtc: used to get a reference to the containing STDU
 148 */
 149static void vmw_stdu_crtc_destroy(struct drm_crtc *crtc)
 150{
 151	vmw_stdu_destroy(vmw_crtc_to_stdu(crtc));
 152}
 153
 154/**
 155 * vmw_stdu_define_st - Defines a Screen Target
 156 *
 157 * @dev_priv:  VMW DRM device
 158 * @stdu: display unit to create a Screen Target for
 159 * @mode: The mode to set.
 160 * @crtc_x: X coordinate of screen target relative to framebuffer origin.
 161 * @crtc_y: Y coordinate of screen target relative to framebuffer origin.
 162 *
 163 * Creates a STDU that we can used later.  This function is called whenever the
 164 * framebuffer size changes.
 165 *
 166 * RETURNs:
 167 * 0 on success, error code on failure
 168 */
 169static int vmw_stdu_define_st(struct vmw_private *dev_priv,
 170			      struct vmw_screen_target_display_unit *stdu,
 171			      struct drm_display_mode *mode,
 172			      int crtc_x, int crtc_y)
 173{
 174	struct {
 175		SVGA3dCmdHeader header;
 176		SVGA3dCmdDefineGBScreenTarget body;
 177	} *cmd;
 178
 179	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 180	if (unlikely(cmd == NULL))
 181		return -ENOMEM;
 182
 183	cmd->header.id   = SVGA_3D_CMD_DEFINE_GB_SCREENTARGET;
 184	cmd->header.size = sizeof(cmd->body);
 185
 186	cmd->body.stid   = stdu->base.unit;
 187	cmd->body.width  = mode->hdisplay;
 188	cmd->body.height = mode->vdisplay;
 189	cmd->body.flags  = (0 == cmd->body.stid) ? SVGA_STFLAG_PRIMARY : 0;
 190	cmd->body.dpi    = 0;
 191	cmd->body.xRoot  = crtc_x;
 192	cmd->body.yRoot  = crtc_y;
 193
 194	stdu->base.set_gui_x = cmd->body.xRoot;
 195	stdu->base.set_gui_y = cmd->body.yRoot;
 196
 197	vmw_cmd_commit(dev_priv, sizeof(*cmd));
 198
 199	stdu->defined = true;
 200	stdu->display_width  = mode->hdisplay;
 201	stdu->display_height = mode->vdisplay;
 202
 203	return 0;
 204}
 205
 206
 207
 208/**
 209 * vmw_stdu_bind_st - Binds a surface to a Screen Target
 210 *
 211 * @dev_priv: VMW DRM device
 212 * @stdu: display unit affected
 213 * @res: Buffer to bind to the screen target.  Set to NULL to blank screen.
 214 *
 215 * Binding a surface to a Screen Target the same as flipping
 216 *
 217 * Returns: %0 on success or -errno code on failure
 218 */
 219static int vmw_stdu_bind_st(struct vmw_private *dev_priv,
 220			    struct vmw_screen_target_display_unit *stdu,
 221			    const struct vmw_resource *res)
 222{
 223	SVGA3dSurfaceImageId image;
 224
 225	struct {
 226		SVGA3dCmdHeader header;
 227		SVGA3dCmdBindGBScreenTarget body;
 228	} *cmd;
 229
 230
 231	if (!stdu->defined) {
 232		DRM_ERROR("No screen target defined\n");
 233		return -EINVAL;
 234	}
 235
 236	/* Set up image using information in vfb */
 237	memset(&image, 0, sizeof(image));
 238	image.sid = res ? res->id : SVGA3D_INVALID_ID;
 239
 240	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 241	if (unlikely(cmd == NULL))
 242		return -ENOMEM;
 243
 244	cmd->header.id   = SVGA_3D_CMD_BIND_GB_SCREENTARGET;
 245	cmd->header.size = sizeof(cmd->body);
 246
 247	cmd->body.stid   = stdu->base.unit;
 248	cmd->body.image  = image;
 249
 250	vmw_cmd_commit(dev_priv, sizeof(*cmd));
 251
 252	return 0;
 253}
 254
 255/**
 256 * vmw_stdu_populate_update - populate an UPDATE_GB_SCREENTARGET command with a
 257 * bounding box.
 258 *
 259 * @cmd: Pointer to command stream.
 260 * @unit: Screen target unit.
 261 * @left: Left side of bounding box.
 262 * @right: Right side of bounding box.
 263 * @top: Top side of bounding box.
 264 * @bottom: Bottom side of bounding box.
 265 */
 266static void vmw_stdu_populate_update(void *cmd, int unit,
 267				     s32 left, s32 right, s32 top, s32 bottom)
 268{
 269	struct vmw_stdu_update *update = cmd;
 270
 271	update->header.id   = SVGA_3D_CMD_UPDATE_GB_SCREENTARGET;
 272	update->header.size = sizeof(update->body);
 273
 274	update->body.stid   = unit;
 275	update->body.rect.x = left;
 276	update->body.rect.y = top;
 277	update->body.rect.w = right - left;
 278	update->body.rect.h = bottom - top;
 279}
 280
 281/**
 282 * vmw_stdu_update_st - Full update of a Screen Target
 283 *
 284 * @dev_priv: VMW DRM device
 285 * @stdu: display unit affected
 286 *
 287 * This function needs to be called whenever the content of a screen
 288 * target has changed completely. Typically as a result of a backing
 289 * surface change.
 290 *
 291 * RETURNS:
 292 * 0 on success, error code on failure
 293 */
 294static int vmw_stdu_update_st(struct vmw_private *dev_priv,
 295			      struct vmw_screen_target_display_unit *stdu)
 296{
 297	struct vmw_stdu_update *cmd;
 298
 299	if (!stdu->defined) {
 300		DRM_ERROR("No screen target defined");
 301		return -EINVAL;
 302	}
 303
 304	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 305	if (unlikely(cmd == NULL))
 306		return -ENOMEM;
 307
 308	vmw_stdu_populate_update(cmd, stdu->base.unit,
 309				 0, stdu->display_width,
 310				 0, stdu->display_height);
 311
 312	vmw_cmd_commit(dev_priv, sizeof(*cmd));
 313
 314	return 0;
 315}
 316
 317
 318
 319/**
 320 * vmw_stdu_destroy_st - Destroy a Screen Target
 321 *
 322 * @dev_priv:  VMW DRM device
 323 * @stdu: display unit to destroy
 324 *
 325 * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
 326 * interrupted.
 327 */
 328static int vmw_stdu_destroy_st(struct vmw_private *dev_priv,
 329			       struct vmw_screen_target_display_unit *stdu)
 330{
 331	int    ret;
 332
 333	struct {
 334		SVGA3dCmdHeader header;
 335		SVGA3dCmdDestroyGBScreenTarget body;
 336	} *cmd;
 337
 338
 339	/* Nothing to do if not successfully defined */
 340	if (unlikely(!stdu->defined))
 341		return 0;
 342
 343	cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
 344	if (unlikely(cmd == NULL))
 345		return -ENOMEM;
 346
 347	cmd->header.id   = SVGA_3D_CMD_DESTROY_GB_SCREENTARGET;
 348	cmd->header.size = sizeof(cmd->body);
 349
 350	cmd->body.stid   = stdu->base.unit;
 351
 352	vmw_cmd_commit(dev_priv, sizeof(*cmd));
 353
 354	/* Force sync */
 355	ret = vmw_fallback_wait(dev_priv, false, true, 0, false, 3*HZ);
 356	if (unlikely(ret != 0))
 357		DRM_ERROR("Failed to sync with HW");
 358
 359	stdu->defined = false;
 360	stdu->display_width  = 0;
 361	stdu->display_height = 0;
 362
 363	return ret;
 364}
 365
 366
 367/**
 368 * vmw_stdu_crtc_mode_set_nofb - Updates screen target size
 369 *
 370 * @crtc: CRTC associated with the screen target
 371 *
 372 * This function defines/destroys a screen target
 373 *
 374 */
 375static void vmw_stdu_crtc_mode_set_nofb(struct drm_crtc *crtc)
 376{
 377	struct vmw_private *dev_priv;
 378	struct vmw_screen_target_display_unit *stdu;
 379	struct drm_connector_state *conn_state;
 380	struct vmw_connector_state *vmw_conn_state;
 381	int x, y, ret;
 382
 383	stdu = vmw_crtc_to_stdu(crtc);
 384	dev_priv = vmw_priv(crtc->dev);
 385	conn_state = stdu->base.connector.state;
 386	vmw_conn_state = vmw_connector_state_to_vcs(conn_state);
 387
 388	if (stdu->defined) {
 389		ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
 390		if (ret)
 391			DRM_ERROR("Failed to blank CRTC\n");
 392
 393		(void) vmw_stdu_update_st(dev_priv, stdu);
 394
 395		ret = vmw_stdu_destroy_st(dev_priv, stdu);
 396		if (ret)
 397			DRM_ERROR("Failed to destroy Screen Target\n");
 398
 399		stdu->content_fb_type = SAME_AS_DISPLAY;
 400	}
 401
 402	if (!crtc->state->enable)
 403		return;
 404
 405	x = vmw_conn_state->gui_x;
 406	y = vmw_conn_state->gui_y;
 407
 408	vmw_svga_enable(dev_priv);
 409	ret = vmw_stdu_define_st(dev_priv, stdu, &crtc->mode, x, y);
 410
 411	if (ret)
 412		DRM_ERROR("Failed to define Screen Target of size %dx%d\n",
 413			  crtc->x, crtc->y);
 414}
 415
 416static void vmw_stdu_crtc_atomic_disable(struct drm_crtc *crtc,
 417					 struct drm_atomic_state *state)
 418{
 419	struct vmw_private *dev_priv;
 420	struct vmw_screen_target_display_unit *stdu;
 421	struct drm_crtc_state *new_crtc_state;
 422	int ret;
 423
 424	if (!crtc) {
 425		DRM_ERROR("CRTC is NULL\n");
 426		return;
 427	}
 428
 429	stdu     = vmw_crtc_to_stdu(crtc);
 430	dev_priv = vmw_priv(crtc->dev);
 431	new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
 432
 433	if (dev_priv->vkms_enabled)
 434		drm_crtc_vblank_off(crtc);
 435
 436	if (stdu->defined) {
 437		ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
 438		if (ret)
 439			DRM_ERROR("Failed to blank CRTC\n");
 440
 441		(void) vmw_stdu_update_st(dev_priv, stdu);
 442
 443		/* Don't destroy the Screen Target if we are only setting the
 444		 * display as inactive
 445		 */
 446		if (new_crtc_state->enable &&
 447		    !new_crtc_state->active &&
 448		    !new_crtc_state->mode_changed)
 449			return;
 450
 451		ret = vmw_stdu_destroy_st(dev_priv, stdu);
 452		if (ret)
 453			DRM_ERROR("Failed to destroy Screen Target\n");
 454
 455		stdu->content_fb_type = SAME_AS_DISPLAY;
 456	}
 457}
 458
 459/**
 460 * vmw_stdu_bo_cpu_clip - Callback to encode a CPU blit
 461 *
 462 * @dirty: The closure structure.
 463 *
 464 * This function calculates the bounding box for all the incoming clips.
 465 */
 466static void vmw_stdu_bo_cpu_clip(struct vmw_kms_dirty *dirty)
 467{
 468	struct vmw_stdu_dirty *ddirty =
 469		container_of(dirty, struct vmw_stdu_dirty, base);
 470
 471	dirty->num_hits = 1;
 472
 473	/* Calculate destination bounding box */
 474	ddirty->left = min_t(s32, ddirty->left, dirty->unit_x1);
 475	ddirty->top = min_t(s32, ddirty->top, dirty->unit_y1);
 476	ddirty->right = max_t(s32, ddirty->right, dirty->unit_x2);
 477	ddirty->bottom = max_t(s32, ddirty->bottom, dirty->unit_y2);
 478
 479	/*
 480	 * Calculate content bounding box.  We only need the top-left
 481	 * coordinate because width and height will be the same as the
 482	 * destination bounding box above
 483	 */
 484	ddirty->fb_left = min_t(s32, ddirty->fb_left, dirty->fb_x);
 485	ddirty->fb_top  = min_t(s32, ddirty->fb_top, dirty->fb_y);
 486}
 487
 488
 489/**
 490 * vmw_stdu_bo_cpu_commit - Callback to do a CPU blit from buffer object
 491 *
 492 * @dirty: The closure structure.
 493 *
 494 * For the special case when we cannot create a proxy surface in a
 495 * 2D VM, we have to do a CPU blit ourselves.
 496 */
 497static void vmw_stdu_bo_cpu_commit(struct vmw_kms_dirty *dirty)
 498{
 499	struct vmw_stdu_dirty *ddirty =
 500		container_of(dirty, struct vmw_stdu_dirty, base);
 501	struct vmw_screen_target_display_unit *stdu =
 502		container_of(dirty->unit, typeof(*stdu), base);
 503	s32 width, height;
 504	s32 src_pitch, dst_pitch;
 505	struct vmw_bo *src_bo, *dst_bo;
 506	u32 src_offset, dst_offset;
 507	struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(stdu->cpp);
 508
 509	if (!dirty->num_hits)
 510		return;
 511
 512	width = ddirty->right - ddirty->left;
 513	height = ddirty->bottom - ddirty->top;
 514
 515	if (width == 0 || height == 0)
 516		return;
 517
 518	/* Assume we are blitting from Guest (bo) to Host (display_srf) */
 519	src_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp;
 520	src_bo = stdu->display_srf->res.guest_memory_bo;
 521	src_offset = ddirty->top * src_pitch + ddirty->left * stdu->cpp;
 522
 523	dst_pitch = ddirty->pitch;
 524	dst_bo = ddirty->buf;
 525	dst_offset = ddirty->fb_top * dst_pitch + ddirty->fb_left * stdu->cpp;
 526
 527	(void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch,
 528			       src_bo, src_offset, src_pitch,
 529			       width * stdu->cpp, height, &diff);
 530}
 531
 532/**
 533 * vmw_kms_stdu_readback - Perform a readback from a buffer-object backed
 534 * framebuffer and the screen target system.
 535 *
 536 * @dev_priv: Pointer to the device private structure.
 537 * @file_priv: Pointer to a struct drm-file identifying the caller. May be
 538 * set to NULL, but then @user_fence_rep must also be set to NULL.
 539 * @vfb: Pointer to the buffer-object backed framebuffer.
 540 * @user_fence_rep: User-space provided structure for fence information.
 541 * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
 542 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
 543 * be NULL.
 544 * @num_clips: Number of clip rects in @clips or @vclips.
 545 * @increment: Increment to use when looping over @clips or @vclips.
 546 * @crtc: If crtc is passed, perform stdu dma on that crtc only.
 547 *
 548 * If DMA-ing till the screen target system, the function will also notify
 549 * the screen target system that a bounding box of the cliprects has been
 550 * updated.
 551 *
 552 * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
 553 * interrupted.
 554 */
 555int vmw_kms_stdu_readback(struct vmw_private *dev_priv,
 556			  struct drm_file *file_priv,
 557			  struct vmw_framebuffer *vfb,
 558			  struct drm_vmw_fence_rep __user *user_fence_rep,
 559			  struct drm_clip_rect *clips,
 560			  struct drm_vmw_rect *vclips,
 561			  uint32_t num_clips,
 562			  int increment,
 563			  struct drm_crtc *crtc)
 564{
 565	struct vmw_bo *buf =
 566		container_of(vfb, struct vmw_framebuffer_bo, base)->buffer;
 567	struct vmw_stdu_dirty ddirty;
 568	int ret;
 569	DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
 570
 571	/*
 572	 * The GMR domain might seem confusing because it might seem like it should
 573	 * never happen with screen targets but e.g. the xorg vmware driver issues
 574	 * CMD_SURFACE_DMA for various pixmap updates which might transition our bo to
 575	 * a GMR. Instead of forcing another transition we can optimize the readback
 576	 * by reading directly from the GMR.
 577	 */
 578	vmw_bo_placement_set(buf,
 579			     VMW_BO_DOMAIN_MOB | VMW_BO_DOMAIN_SYS | VMW_BO_DOMAIN_GMR,
 580			     VMW_BO_DOMAIN_MOB | VMW_BO_DOMAIN_SYS | VMW_BO_DOMAIN_GMR);
 581	ret = vmw_validation_add_bo(&val_ctx, buf);
 582	if (ret)
 583		return ret;
 584
 585	ret = vmw_validation_prepare(&val_ctx, NULL, true);
 586	if (ret)
 587		goto out_unref;
 588
 589	ddirty.left = ddirty.top = S32_MAX;
 590	ddirty.right = ddirty.bottom = S32_MIN;
 591	ddirty.fb_left = ddirty.fb_top = S32_MAX;
 592	ddirty.pitch = vfb->base.pitches[0];
 593	ddirty.buf = buf;
 594
 595	ddirty.base.fifo_commit = vmw_stdu_bo_cpu_commit;
 596	ddirty.base.clip = vmw_stdu_bo_cpu_clip;
 597	ddirty.base.fifo_reserve_size = 0;
 598
 599	ddirty.base.crtc = crtc;
 600
 601	ret = vmw_kms_helper_dirty(dev_priv, vfb, clips, vclips,
 602				   0, 0, num_clips, increment, &ddirty.base);
 603
 604	vmw_kms_helper_validation_finish(dev_priv, file_priv, &val_ctx, NULL,
 605					 user_fence_rep);
 606	return ret;
 607
 608out_unref:
 609	vmw_validation_unref_lists(&val_ctx);
 610	return ret;
 611}
 612
 613/**
 614 * vmw_kms_stdu_surface_clip - Callback to encode a surface copy command cliprect
 615 *
 616 * @dirty: The closure structure.
 617 *
 618 * Encodes a surface copy command cliprect and updates the bounding box
 619 * for the copy.
 620 */
 621static void vmw_kms_stdu_surface_clip(struct vmw_kms_dirty *dirty)
 622{
 623	struct vmw_stdu_dirty *sdirty =
 624		container_of(dirty, struct vmw_stdu_dirty, base);
 625	struct vmw_stdu_surface_copy *cmd = dirty->cmd;
 626	struct vmw_screen_target_display_unit *stdu =
 627		container_of(dirty->unit, typeof(*stdu), base);
 628
 629	if (sdirty->sid != stdu->display_srf->res.id) {
 630		struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
 631
 632		blit += dirty->num_hits;
 633		blit->srcx = dirty->fb_x;
 634		blit->srcy = dirty->fb_y;
 635		blit->x = dirty->unit_x1;
 636		blit->y = dirty->unit_y1;
 637		blit->d = 1;
 638		blit->w = dirty->unit_x2 - dirty->unit_x1;
 639		blit->h = dirty->unit_y2 - dirty->unit_y1;
 640	}
 641
 642	dirty->num_hits++;
 643
 644	/* Destination bounding box */
 645	sdirty->left = min_t(s32, sdirty->left, dirty->unit_x1);
 646	sdirty->top = min_t(s32, sdirty->top, dirty->unit_y1);
 647	sdirty->right = max_t(s32, sdirty->right, dirty->unit_x2);
 648	sdirty->bottom = max_t(s32, sdirty->bottom, dirty->unit_y2);
 649}
 650
 651/**
 652 * vmw_kms_stdu_surface_fifo_commit - Callback to fill in and submit a surface
 653 * copy command.
 654 *
 655 * @dirty: The closure structure.
 656 *
 657 * Fills in the missing fields in a surface copy command, and encodes a screen
 658 * target update command.
 659 */
 660static void vmw_kms_stdu_surface_fifo_commit(struct vmw_kms_dirty *dirty)
 661{
 662	struct vmw_stdu_dirty *sdirty =
 663		container_of(dirty, struct vmw_stdu_dirty, base);
 664	struct vmw_screen_target_display_unit *stdu =
 665		container_of(dirty->unit, typeof(*stdu), base);
 666	struct vmw_stdu_surface_copy *cmd = dirty->cmd;
 667	struct vmw_stdu_update *update;
 668	size_t blit_size = sizeof(SVGA3dCopyBox) * dirty->num_hits;
 669	size_t commit_size;
 670
 671	if (!dirty->num_hits) {
 672		vmw_cmd_commit(dirty->dev_priv, 0);
 673		return;
 674	}
 675
 676	if (sdirty->sid != stdu->display_srf->res.id) {
 677		struct SVGA3dCopyBox *blit = (struct SVGA3dCopyBox *) &cmd[1];
 678
 679		cmd->header.id = SVGA_3D_CMD_SURFACE_COPY;
 680		cmd->header.size = sizeof(cmd->body) + blit_size;
 681		cmd->body.src.sid = sdirty->sid;
 682		cmd->body.dest.sid = stdu->display_srf->res.id;
 683		update = (struct vmw_stdu_update *) &blit[dirty->num_hits];
 684		commit_size = sizeof(*cmd) + blit_size + sizeof(*update);
 685		stdu->display_srf->res.res_dirty = true;
 686	} else {
 687		update = dirty->cmd;
 688		commit_size = sizeof(*update);
 689	}
 690
 691	vmw_stdu_populate_update(update, stdu->base.unit, sdirty->left,
 692				 sdirty->right, sdirty->top, sdirty->bottom);
 693
 694	vmw_cmd_commit(dirty->dev_priv, commit_size);
 695
 696	sdirty->left = sdirty->top = S32_MAX;
 697	sdirty->right = sdirty->bottom = S32_MIN;
 698}
 699
 700/**
 701 * vmw_kms_stdu_surface_dirty - Dirty part of a surface backed framebuffer
 702 *
 703 * @dev_priv: Pointer to the device private structure.
 704 * @framebuffer: Pointer to the surface-buffer backed framebuffer.
 705 * @clips: Array of clip rects. Either @clips or @vclips must be NULL.
 706 * @vclips: Alternate array of clip rects. Either @clips or @vclips must
 707 * be NULL.
 708 * @srf: Pointer to surface to blit from. If NULL, the surface attached
 709 * to @framebuffer will be used.
 710 * @dest_x: X coordinate offset to align @srf with framebuffer coordinates.
 711 * @dest_y: Y coordinate offset to align @srf with framebuffer coordinates.
 712 * @num_clips: Number of clip rects in @clips.
 713 * @inc: Increment to use when looping over @clips.
 714 * @out_fence: If non-NULL, will return a ref-counted pointer to a
 715 * struct vmw_fence_obj. The returned fence pointer may be NULL in which
 716 * case the device has already synchronized.
 717 * @crtc: If crtc is passed, perform surface dirty on that crtc only.
 718 *
 719 * Returns: %0 on success, negative error code on failure. -ERESTARTSYS if
 720 * interrupted.
 721 */
 722int vmw_kms_stdu_surface_dirty(struct vmw_private *dev_priv,
 723			       struct vmw_framebuffer *framebuffer,
 724			       struct drm_clip_rect *clips,
 725			       struct drm_vmw_rect *vclips,
 726			       struct vmw_resource *srf,
 727			       s32 dest_x,
 728			       s32 dest_y,
 729			       unsigned num_clips, int inc,
 730			       struct vmw_fence_obj **out_fence,
 731			       struct drm_crtc *crtc)
 732{
 733	struct vmw_framebuffer_surface *vfbs =
 734		container_of(framebuffer, typeof(*vfbs), base);
 735	struct vmw_stdu_dirty sdirty;
 736	DECLARE_VAL_CONTEXT(val_ctx, NULL, 0);
 737	int ret;
 738
 739	if (!srf)
 740		srf = &vmw_user_object_surface(&vfbs->uo)->res;
 741
 742	ret = vmw_validation_add_resource(&val_ctx, srf, 0, VMW_RES_DIRTY_NONE,
 743					  NULL, NULL);
 744	if (ret)
 745		return ret;
 746
 747	ret = vmw_validation_prepare(&val_ctx, &dev_priv->cmdbuf_mutex, true);
 748	if (ret)
 749		goto out_unref;
 750
 751	sdirty.base.fifo_commit = vmw_kms_stdu_surface_fifo_commit;
 752	sdirty.base.clip = vmw_kms_stdu_surface_clip;
 753	sdirty.base.fifo_reserve_size = sizeof(struct vmw_stdu_surface_copy) +
 754		sizeof(SVGA3dCopyBox) * num_clips +
 755		sizeof(struct vmw_stdu_update);
 756	sdirty.base.crtc = crtc;
 757	sdirty.sid = srf->id;
 758	sdirty.left = sdirty.top = S32_MAX;
 759	sdirty.right = sdirty.bottom = S32_MIN;
 760
 761	ret = vmw_kms_helper_dirty(dev_priv, framebuffer, clips, vclips,
 762				   dest_x, dest_y, num_clips, inc,
 763				   &sdirty.base);
 764
 765	vmw_kms_helper_validation_finish(dev_priv, NULL, &val_ctx, out_fence,
 766					 NULL);
 767
 768	return ret;
 769
 770out_unref:
 771	vmw_validation_unref_lists(&val_ctx);
 772	return ret;
 773}
 774
 775/*
 776 *  Screen Target CRTC dispatch table
 777 */
 778static const struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
 779	.gamma_set = vmw_du_crtc_gamma_set,
 780	.destroy = vmw_stdu_crtc_destroy,
 781	.reset = vmw_du_crtc_reset,
 782	.atomic_duplicate_state = vmw_du_crtc_duplicate_state,
 783	.atomic_destroy_state = vmw_du_crtc_destroy_state,
 784	.set_config = drm_atomic_helper_set_config,
 785	.page_flip = drm_atomic_helper_page_flip,
 786	.enable_vblank		= vmw_vkms_enable_vblank,
 787	.disable_vblank		= vmw_vkms_disable_vblank,
 788	.get_vblank_timestamp	= vmw_vkms_get_vblank_timestamp,
 789	.get_crc_sources	= vmw_vkms_get_crc_sources,
 790	.set_crc_source		= vmw_vkms_set_crc_source,
 791	.verify_crc_source	= vmw_vkms_verify_crc_source,
 792};
 793
 794
 795
 796/******************************************************************************
 797 * Screen Target Display Unit Encoder Functions
 798 *****************************************************************************/
 799
 800/**
 801 * vmw_stdu_encoder_destroy - cleans up the STDU
 802 *
 803 * @encoder: used the get the containing STDU
 804 *
 805 * vmwgfx cleans up crtc/encoder/connector all at the same time so technically
 806 * this can be a no-op.  Nevertheless, it doesn't hurt of have this in case
 807 * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't
 808 * get called.
 809 */
 810static void vmw_stdu_encoder_destroy(struct drm_encoder *encoder)
 811{
 812	vmw_stdu_destroy(vmw_encoder_to_stdu(encoder));
 813}
 814
 815static const struct drm_encoder_funcs vmw_stdu_encoder_funcs = {
 816	.destroy = vmw_stdu_encoder_destroy,
 817};
 818
 819
 820
 821/******************************************************************************
 822 * Screen Target Display Unit Connector Functions
 823 *****************************************************************************/
 824
 825/**
 826 * vmw_stdu_connector_destroy - cleans up the STDU
 827 *
 828 * @connector: used to get the containing STDU
 829 *
 830 * vmwgfx cleans up crtc/encoder/connector all at the same time so technically
 831 * this can be a no-op.  Nevertheless, it doesn't hurt of have this in case
 832 * the common KMS code changes and somehow vmw_stdu_crtc_destroy() doesn't
 833 * get called.
 834 */
 835static void vmw_stdu_connector_destroy(struct drm_connector *connector)
 836{
 837	vmw_stdu_destroy(vmw_connector_to_stdu(connector));
 838}
 839
 840static enum drm_mode_status
 841vmw_stdu_connector_mode_valid(struct drm_connector *connector,
 842			      struct drm_display_mode *mode)
 843{
 844	enum drm_mode_status ret;
 845	struct drm_device *dev = connector->dev;
 846	struct vmw_private *dev_priv = vmw_priv(dev);
 847	u64 assumed_cpp = dev_priv->assume_16bpp ? 2 : 4;
 848	/* Align width and height to account for GPU tile over-alignment */
 849	u64 required_mem = ALIGN(mode->hdisplay, GPU_TILE_SIZE) *
 850			   ALIGN(mode->vdisplay, GPU_TILE_SIZE) *
 851			   assumed_cpp;
 852	required_mem = ALIGN(required_mem, PAGE_SIZE);
 853
 854	ret = drm_mode_validate_size(mode, dev_priv->stdu_max_width,
 855				     dev_priv->stdu_max_height);
 856	if (ret != MODE_OK)
 857		return ret;
 858
 859	ret = drm_mode_validate_size(mode, dev_priv->texture_max_width,
 860				     dev_priv->texture_max_height);
 861	if (ret != MODE_OK)
 862		return ret;
 863
 864	if (required_mem > dev_priv->max_primary_mem)
 865		return MODE_MEM;
 866
 867	if (required_mem > dev_priv->max_mob_pages * PAGE_SIZE)
 868		return MODE_MEM;
 869
 870	if (required_mem > dev_priv->max_mob_size)
 871		return MODE_MEM;
 872
 873	return MODE_OK;
 874}
 875
 876/*
 877 * Trigger a modeset if the X,Y position of the Screen Target changes.
 878 * This is needed when multi-mon is cycled. The original Screen Target will have
 879 * the same mode but its relative X,Y position in the topology will change.
 880 */
 881static int vmw_stdu_connector_atomic_check(struct drm_connector *conn,
 882					   struct drm_atomic_state *state)
 883{
 884	struct drm_connector_state *conn_state;
 885	struct vmw_screen_target_display_unit *du;
 886	struct drm_crtc_state *new_crtc_state;
 887
 888	conn_state = drm_atomic_get_connector_state(state, conn);
 889
 890	if (IS_ERR(conn_state))
 891		return PTR_ERR(conn_state);
 892
 893	du = vmw_connector_to_stdu(conn);
 894
 895	if (!conn_state->crtc)
 896		return 0;
 897
 898	new_crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
 899	if (du->base.gui_x != du->base.set_gui_x ||
 900	    du->base.gui_y != du->base.set_gui_y)
 901		new_crtc_state->mode_changed = true;
 902
 903	return 0;
 904}
 905
 906static const struct drm_connector_funcs vmw_stdu_connector_funcs = {
 907	.dpms = vmw_du_connector_dpms,
 908	.detect = vmw_du_connector_detect,
 909	.fill_modes = drm_helper_probe_single_connector_modes,
 910	.destroy = vmw_stdu_connector_destroy,
 911	.reset = vmw_du_connector_reset,
 912	.atomic_duplicate_state = vmw_du_connector_duplicate_state,
 913	.atomic_destroy_state = vmw_du_connector_destroy_state,
 914};
 915
 916
 917static const struct
 918drm_connector_helper_funcs vmw_stdu_connector_helper_funcs = {
 919	.get_modes = vmw_connector_get_modes,
 920	.mode_valid = vmw_stdu_connector_mode_valid,
 921	.atomic_check = vmw_stdu_connector_atomic_check,
 922};
 923
 924
 925
 926/******************************************************************************
 927 * Screen Target Display Plane Functions
 928 *****************************************************************************/
 929
 930
 931
 932/**
 933 * vmw_stdu_primary_plane_cleanup_fb - Unpins the display surface
 934 *
 935 * @plane:  display plane
 936 * @old_state: Contains the FB to clean up
 937 *
 938 * Unpins the display surface
 939 *
 940 * Returns 0 on success
 941 */
 942static void
 943vmw_stdu_primary_plane_cleanup_fb(struct drm_plane *plane,
 944				  struct drm_plane_state *old_state)
 945{
 946	struct vmw_plane_state *vps = vmw_plane_state_to_vps(old_state);
 947
 948	if (vmw_user_object_surface(&vps->uo))
 949		WARN_ON(!vps->pinned);
 950	vmw_du_plane_cleanup_fb(plane, old_state);
 951
 952	vps->content_fb_type = SAME_AS_DISPLAY;
 953	vps->cpp = 0;
 954}
 955
 956
 957/**
 958 * vmw_stdu_primary_plane_prepare_fb - Readies the display surface
 959 *
 960 * @plane:  display plane
 961 * @new_state: info on the new plane state, including the FB
 962 *
 963 * This function allocates a new display surface if the content is
 964 * backed by a buffer object.  The display surface is pinned here, and it'll
 965 * be unpinned in .cleanup_fb()
 966 *
 967 * Returns: %0 on success
 968 */
 969static int
 970vmw_stdu_primary_plane_prepare_fb(struct drm_plane *plane,
 971				  struct drm_plane_state *new_state)
 972{
 973	struct vmw_private *dev_priv = vmw_priv(plane->dev);
 974	struct drm_framebuffer *new_fb = new_state->fb;
 975	struct vmw_framebuffer *vfb;
 976	struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
 977	enum stdu_content_type new_content_type;
 978	struct vmw_framebuffer_surface *new_vfbs;
 979	uint32_t hdisplay = new_state->crtc_w, vdisplay = new_state->crtc_h;
 980	struct drm_plane_state *old_state = plane->state;
 981	struct drm_rect rect;
 982	int ret;
 983
 984	/* No FB to prepare */
 985	if (!new_fb) {
 986		if (vmw_user_object_surface(&vps->uo)) {
 987			WARN_ON(vps->pinned != 0);
 988			vmw_user_object_unref(&vps->uo);
 989		}
 990
 991		return 0;
 992	}
 993
 994	vfb = vmw_framebuffer_to_vfb(new_fb);
 995	new_vfbs = (vfb->bo) ? NULL : vmw_framebuffer_to_vfbs(new_fb);
 996
 997	if (new_vfbs &&
 998	    vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.width == hdisplay &&
 999	    vmw_user_object_surface(&new_vfbs->uo)->metadata.base_size.height == vdisplay)
1000		new_content_type = SAME_AS_DISPLAY;
1001	else if (vfb->bo)
1002		new_content_type = SEPARATE_BO;
1003	else
1004		new_content_type = SEPARATE_SURFACE;
1005
1006	if (new_content_type != SAME_AS_DISPLAY) {
1007		struct vmw_surface_metadata metadata = {0};
1008
1009		/*
1010		 * If content buffer is a buffer object, then we have to
1011		 * construct surface info
1012		 */
1013		if (new_content_type == SEPARATE_BO) {
1014
1015			switch (new_fb->format->cpp[0]*8) {
1016			case 32:
1017				metadata.format = SVGA3D_X8R8G8B8;
1018				break;
1019
1020			case 16:
1021				metadata.format = SVGA3D_R5G6B5;
1022				break;
1023
1024			case 8:
1025				metadata.format = SVGA3D_P8;
1026				break;
1027
1028			default:
1029				DRM_ERROR("Invalid format\n");
1030				return -EINVAL;
1031			}
1032
1033			metadata.mip_levels[0] = 1;
1034			metadata.num_sizes = 1;
1035			metadata.scanout = true;
1036		} else {
1037			metadata = vmw_user_object_surface(&new_vfbs->uo)->metadata;
1038		}
1039
1040		metadata.base_size.width = hdisplay;
1041		metadata.base_size.height = vdisplay;
1042		metadata.base_size.depth = 1;
1043
1044		if (vmw_user_object_surface(&vps->uo)) {
1045			struct drm_vmw_size cur_base_size =
1046				vmw_user_object_surface(&vps->uo)->metadata.base_size;
1047
1048			if (cur_base_size.width != metadata.base_size.width ||
1049			    cur_base_size.height != metadata.base_size.height ||
1050			    vmw_user_object_surface(&vps->uo)->metadata.format != metadata.format) {
1051				WARN_ON(vps->pinned != 0);
1052				vmw_user_object_unref(&vps->uo);
1053			}
1054
1055		}
1056
1057		if (!vmw_user_object_surface(&vps->uo)) {
1058			ret = vmw_gb_surface_define(dev_priv, &metadata,
1059						    &vps->uo.surface);
1060			if (ret != 0) {
1061				DRM_ERROR("Couldn't allocate STDU surface.\n");
1062				return ret;
1063			}
1064		}
1065	} else {
1066		/*
1067		 * prepare_fb and clean_fb should only take care of pinning
1068		 * and unpinning.  References are tracked by state objects.
1069		 * The only time we add a reference in prepare_fb is if the
1070		 * state object doesn't have a reference to begin with
1071		 */
1072		if (vmw_user_object_surface(&vps->uo)) {
1073			WARN_ON(vps->pinned != 0);
1074			vmw_user_object_unref(&vps->uo);
1075		}
1076
1077		memcpy(&vps->uo, &new_vfbs->uo, sizeof(vps->uo));
1078		vmw_user_object_ref(&vps->uo);
1079	}
1080
1081	if (vmw_user_object_surface(&vps->uo)) {
1082
1083		/* Pin new surface before flipping */
1084		ret = vmw_resource_pin(&vmw_user_object_surface(&vps->uo)->res, false);
1085		if (ret)
1086			goto out_srf_unref;
1087
1088		vps->pinned++;
1089	}
1090
1091	vps->content_fb_type = new_content_type;
1092
1093	/*
1094	 * The drm fb code will do blit's via the vmap interface, which doesn't
1095	 * trigger vmw_bo page dirty tracking due to being kernel side (and thus
1096	 * doesn't require mmap'ing) so we have to update the surface's dirty
1097	 * regions by hand but we want to be careful to not overwrite the
1098	 * resource if it has been written to by the gpu (res_dirty).
1099	 */
1100	if (vps->uo.buffer && vps->uo.buffer->is_dumb) {
1101		struct vmw_surface *surf = vmw_user_object_surface(&vps->uo);
1102		struct vmw_resource *res = &surf->res;
1103
1104		if (!res->res_dirty && drm_atomic_helper_damage_merged(old_state,
1105								       new_state,
1106								       &rect)) {
1107			/*
1108			 * At some point it might be useful to actually translate
1109			 * (rect.x1, rect.y1) => start, and (rect.x2, rect.y2) => end,
1110			 * but currently the fb code will just report the entire fb
1111			 * dirty so in practice it doesn't matter.
1112			 */
1113			pgoff_t start = res->guest_memory_offset >> PAGE_SHIFT;
1114			pgoff_t end = __KERNEL_DIV_ROUND_UP(res->guest_memory_offset +
1115							    res->guest_memory_size,
1116							    PAGE_SIZE);
1117			vmw_resource_dirty_update(res, start, end);
1118		}
1119	}
1120
1121	/*
1122	 * This should only happen if the buffer object is too large to create a
1123	 * proxy surface for.
1124	 */
1125	if (vps->content_fb_type == SEPARATE_BO)
1126		vps->cpp = new_fb->pitches[0] / new_fb->width;
1127
1128	return 0;
1129
1130out_srf_unref:
1131	vmw_user_object_unref(&vps->uo);
1132	return ret;
1133}
1134
1135static uint32_t vmw_stdu_bo_fifo_size_cpu(struct vmw_du_update_plane *update,
1136					  uint32_t num_hits)
1137{
1138	return sizeof(struct vmw_stdu_update_gb_image) +
1139		sizeof(struct vmw_stdu_update);
1140}
1141
1142static uint32_t vmw_stdu_bo_pre_clip_cpu(struct vmw_du_update_plane  *update,
1143					 void *cmd, uint32_t num_hits)
1144{
1145	struct vmw_du_update_plane_buffer *bo_update =
1146		container_of(update, typeof(*bo_update), base);
1147
1148	bo_update->fb_left = INT_MAX;
1149	bo_update->fb_top = INT_MAX;
1150
1151	return 0;
1152}
1153
1154static uint32_t vmw_stdu_bo_clip_cpu(struct vmw_du_update_plane  *update,
1155				     void *cmd, struct drm_rect *clip,
1156				     uint32_t fb_x, uint32_t fb_y)
1157{
1158	struct vmw_du_update_plane_buffer *bo_update =
1159		container_of(update, typeof(*bo_update), base);
1160
1161	bo_update->fb_left = min_t(int, bo_update->fb_left, fb_x);
1162	bo_update->fb_top = min_t(int, bo_update->fb_top, fb_y);
1163
1164	return 0;
1165}
1166
1167static uint32_t
1168vmw_stdu_bo_populate_update_cpu(struct vmw_du_update_plane  *update, void *cmd,
1169				struct drm_rect *bb)
1170{
1171	struct vmw_du_update_plane_buffer *bo_update;
1172	struct vmw_screen_target_display_unit *stdu;
1173	struct vmw_framebuffer_bo *vfbbo;
1174	struct vmw_diff_cpy diff = VMW_CPU_BLIT_DIFF_INITIALIZER(0);
1175	struct vmw_stdu_update_gb_image *cmd_img = cmd;
1176	struct vmw_stdu_update *cmd_update;
1177	struct vmw_bo *src_bo, *dst_bo;
1178	u32 src_offset, dst_offset;
1179	s32 src_pitch, dst_pitch;
1180	s32 width, height;
1181
1182	bo_update = container_of(update, typeof(*bo_update), base);
1183	stdu = container_of(update->du, typeof(*stdu), base);
1184	vfbbo = container_of(update->vfb, typeof(*vfbbo), base);
1185
1186	width = bb->x2 - bb->x1;
1187	height = bb->y2 - bb->y1;
1188
1189	diff.cpp = stdu->cpp;
1190
1191	dst_bo = stdu->display_srf->res.guest_memory_bo;
1192	dst_pitch = stdu->display_srf->metadata.base_size.width * stdu->cpp;
1193	dst_offset = bb->y1 * dst_pitch + bb->x1 * stdu->cpp;
1194
1195	src_bo = vfbbo->buffer;
1196	src_pitch = update->vfb->base.pitches[0];
1197	src_offset = bo_update->fb_top * src_pitch + bo_update->fb_left *
1198		stdu->cpp;
1199
1200	(void) vmw_bo_cpu_blit(dst_bo, dst_offset, dst_pitch, src_bo,
1201			       src_offset, src_pitch, width * stdu->cpp, height,
1202			       &diff);
1203
1204	if (drm_rect_visible(&diff.rect)) {
1205		SVGA3dBox *box = &cmd_img->body.box;
1206
1207		cmd_img->header.id = SVGA_3D_CMD_UPDATE_GB_IMAGE;
1208		cmd_img->header.size = sizeof(cmd_img->body);
1209		cmd_img->body.image.sid = stdu->display_srf->res.id;
1210		cmd_img->body.image.face = 0;
1211		cmd_img->body.image.mipmap = 0;
1212
1213		box->x = diff.rect.x1;
1214		box->y = diff.rect.y1;
1215		box->z = 0;
1216		box->w = drm_rect_width(&diff.rect);
1217		box->h = drm_rect_height(&diff.rect);
1218		box->d = 1;
1219
1220		cmd_update = (struct vmw_stdu_update *)&cmd_img[1];
1221		vmw_stdu_populate_update(cmd_update, stdu->base.unit,
1222					 diff.rect.x1, diff.rect.x2,
1223					 diff.rect.y1, diff.rect.y2);
1224
1225		return sizeof(*cmd_img) + sizeof(*cmd_update);
1226	}
1227
1228	return 0;
1229}
1230
1231/**
1232 * vmw_stdu_plane_update_bo - Update display unit for bo backed fb.
1233 * @dev_priv: device private.
1234 * @plane: plane state.
1235 * @old_state: old plane state.
1236 * @vfb: framebuffer which is blitted to display unit.
1237 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
1238 *             The returned fence pointer may be NULL in which case the device
1239 *             has already synchronized.
1240 *
1241 * Return: 0 on success or a negative error code on failure.
1242 */
1243static int vmw_stdu_plane_update_bo(struct vmw_private *dev_priv,
1244				    struct drm_plane *plane,
1245				    struct drm_plane_state *old_state,
1246				    struct vmw_framebuffer *vfb,
1247				    struct vmw_fence_obj **out_fence)
1248{
1249	struct vmw_du_update_plane_buffer bo_update;
1250
1251	memset(&bo_update, 0, sizeof(struct vmw_du_update_plane_buffer));
1252	bo_update.base.plane = plane;
1253	bo_update.base.old_state = old_state;
1254	bo_update.base.dev_priv = dev_priv;
1255	bo_update.base.du = vmw_crtc_to_du(plane->state->crtc);
1256	bo_update.base.vfb = vfb;
1257	bo_update.base.out_fence = out_fence;
1258	bo_update.base.mutex = NULL;
1259	bo_update.base.intr = false;
1260
1261	bo_update.base.calc_fifo_size = vmw_stdu_bo_fifo_size_cpu;
1262	bo_update.base.pre_clip = vmw_stdu_bo_pre_clip_cpu;
1263	bo_update.base.clip = vmw_stdu_bo_clip_cpu;
1264	bo_update.base.post_clip = vmw_stdu_bo_populate_update_cpu;
1265
1266	return vmw_du_helper_plane_update(&bo_update.base);
1267}
1268
1269static uint32_t
1270vmw_stdu_surface_fifo_size_same_display(struct vmw_du_update_plane *update,
1271					uint32_t num_hits)
1272{
1273	uint32_t size = 0;
1274
1275	size += sizeof(struct vmw_stdu_update);
1276
1277	return size;
1278}
1279
1280static uint32_t vmw_stdu_surface_fifo_size(struct vmw_du_update_plane *update,
1281					   uint32_t num_hits)
1282{
1283	uint32_t size = 0;
1284
1285	size += sizeof(struct vmw_stdu_surface_copy) + sizeof(SVGA3dCopyBox) *
1286		num_hits + sizeof(struct vmw_stdu_update);
1287
1288	return size;
1289}
1290
1291static uint32_t
1292vmw_stdu_surface_populate_copy(struct vmw_du_update_plane  *update, void *cmd,
1293			       uint32_t num_hits)
1294{
1295	struct vmw_screen_target_display_unit *stdu;
1296	struct vmw_framebuffer_surface *vfbs;
1297	struct vmw_stdu_surface_copy *cmd_copy = cmd;
1298
1299	stdu = container_of(update->du, typeof(*stdu), base);
1300	vfbs = container_of(update->vfb, typeof(*vfbs), base);
1301
1302	cmd_copy->header.id = SVGA_3D_CMD_SURFACE_COPY;
1303	cmd_copy->header.size = sizeof(cmd_copy->body) + sizeof(SVGA3dCopyBox) *
1304		num_hits;
1305	cmd_copy->body.src.sid = vmw_user_object_surface(&vfbs->uo)->res.id;
1306	cmd_copy->body.dest.sid = stdu->display_srf->res.id;
1307
1308	return sizeof(*cmd_copy);
1309}
1310
1311static uint32_t
1312vmw_stdu_surface_populate_clip(struct vmw_du_update_plane  *update, void *cmd,
1313			       struct drm_rect *clip, uint32_t fb_x,
1314			       uint32_t fb_y)
1315{
1316	struct SVGA3dCopyBox *box = cmd;
1317
1318	box->srcx = fb_x;
1319	box->srcy = fb_y;
1320	box->srcz = 0;
1321	box->x = clip->x1;
1322	box->y = clip->y1;
1323	box->z = 0;
1324	box->w = drm_rect_width(clip);
1325	box->h = drm_rect_height(clip);
1326	box->d = 1;
1327
1328	return sizeof(*box);
1329}
1330
1331static uint32_t
1332vmw_stdu_surface_populate_update(struct vmw_du_update_plane  *update, void *cmd,
1333				 struct drm_rect *bb)
1334{
1335	vmw_stdu_populate_update(cmd, update->du->unit, bb->x1, bb->x2, bb->y1,
1336				 bb->y2);
1337
1338	return sizeof(struct vmw_stdu_update);
1339}
1340
1341/**
1342 * vmw_stdu_plane_update_surface - Update display unit for surface backed fb
1343 * @dev_priv: Device private
1344 * @plane: Plane state
1345 * @old_state: Old plane state
1346 * @vfb: Framebuffer which is blitted to display unit
1347 * @out_fence: If non-NULL, will return a ref-counted pointer to vmw_fence_obj.
1348 *             The returned fence pointer may be NULL in which case the device
1349 *             has already synchronized.
1350 *
1351 * Return: 0 on success or a negative error code on failure.
1352 */
1353static int vmw_stdu_plane_update_surface(struct vmw_private *dev_priv,
1354					 struct drm_plane *plane,
1355					 struct drm_plane_state *old_state,
1356					 struct vmw_framebuffer *vfb,
1357					 struct vmw_fence_obj **out_fence)
1358{
1359	struct vmw_du_update_plane srf_update;
1360	struct vmw_screen_target_display_unit *stdu;
1361	struct vmw_framebuffer_surface *vfbs;
1362
1363	stdu = vmw_crtc_to_stdu(plane->state->crtc);
1364	vfbs = container_of(vfb, typeof(*vfbs), base);
1365
1366	memset(&srf_update, 0, sizeof(struct vmw_du_update_plane));
1367	srf_update.plane = plane;
1368	srf_update.old_state = old_state;
1369	srf_update.dev_priv = dev_priv;
1370	srf_update.du = vmw_crtc_to_du(plane->state->crtc);
1371	srf_update.vfb = vfb;
1372	srf_update.out_fence = out_fence;
1373	srf_update.mutex = &dev_priv->cmdbuf_mutex;
1374	srf_update.intr = true;
1375
1376	if (vmw_user_object_surface(&vfbs->uo)->res.id != stdu->display_srf->res.id) {
1377		srf_update.calc_fifo_size = vmw_stdu_surface_fifo_size;
1378		srf_update.pre_clip = vmw_stdu_surface_populate_copy;
1379		srf_update.clip = vmw_stdu_surface_populate_clip;
1380	} else {
1381		srf_update.calc_fifo_size =
1382			vmw_stdu_surface_fifo_size_same_display;
1383	}
1384
1385	srf_update.post_clip = vmw_stdu_surface_populate_update;
1386
1387	return vmw_du_helper_plane_update(&srf_update);
1388}
1389
1390/**
1391 * vmw_stdu_primary_plane_atomic_update - formally switches STDU to new plane
1392 * @plane: display plane
1393 * @state: Only used to get crtc info
1394 *
1395 * Formally update stdu->display_srf to the new plane, and bind the new
1396 * plane STDU.  This function is called during the commit phase when
1397 * all the preparation have been done and all the configurations have
1398 * been checked.
1399 */
1400static void
1401vmw_stdu_primary_plane_atomic_update(struct drm_plane *plane,
1402				     struct drm_atomic_state *state)
1403{
1404	struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
1405	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state, plane);
1406	struct vmw_plane_state *vps = vmw_plane_state_to_vps(new_state);
1407	struct drm_crtc *crtc = new_state->crtc;
1408	struct vmw_screen_target_display_unit *stdu;
1409	struct vmw_fence_obj *fence = NULL;
1410	struct vmw_private *dev_priv;
1411	int ret;
1412
1413	/* If case of device error, maintain consistent atomic state */
1414	if (crtc && new_state->fb) {
1415		struct vmw_framebuffer *vfb =
1416			vmw_framebuffer_to_vfb(new_state->fb);
1417		stdu = vmw_crtc_to_stdu(crtc);
1418		dev_priv = vmw_priv(crtc->dev);
1419
1420		stdu->display_srf = vmw_user_object_surface(&vps->uo);
1421		stdu->content_fb_type = vps->content_fb_type;
1422		stdu->cpp = vps->cpp;
1423
1424		ret = vmw_stdu_bind_st(dev_priv, stdu, &stdu->display_srf->res);
1425		if (ret)
1426			DRM_ERROR("Failed to bind surface to STDU.\n");
1427
1428		if (vfb->bo)
1429			ret = vmw_stdu_plane_update_bo(dev_priv, plane,
1430						       old_state, vfb, &fence);
1431		else
1432			ret = vmw_stdu_plane_update_surface(dev_priv, plane,
1433							    old_state, vfb,
1434							    &fence);
1435		if (ret)
1436			DRM_ERROR("Failed to update STDU.\n");
1437	} else {
1438		crtc = old_state->crtc;
1439		stdu = vmw_crtc_to_stdu(crtc);
1440		dev_priv = vmw_priv(crtc->dev);
1441
1442		/* Blank STDU when fb and crtc are NULL */
1443		if (!stdu->defined)
1444			return;
1445
1446		ret = vmw_stdu_bind_st(dev_priv, stdu, NULL);
1447		if (ret)
1448			DRM_ERROR("Failed to blank STDU\n");
1449
1450		ret = vmw_stdu_update_st(dev_priv, stdu);
1451		if (ret)
1452			DRM_ERROR("Failed to update STDU.\n");
1453
1454		return;
1455	}
1456
1457	if (fence)
1458		vmw_fence_obj_unreference(&fence);
1459}
1460
1461static void
1462vmw_stdu_crtc_atomic_flush(struct drm_crtc *crtc,
1463			   struct drm_atomic_state *state)
1464{
1465	struct vmw_private *vmw = vmw_priv(crtc->dev);
1466	struct vmw_screen_target_display_unit *stdu = vmw_crtc_to_stdu(crtc);
1467
1468	if (vmw->vkms_enabled)
1469		vmw_vkms_set_crc_surface(crtc, stdu->display_srf);
1470	vmw_vkms_crtc_atomic_flush(crtc, state);
1471}
1472
1473static const struct drm_plane_funcs vmw_stdu_plane_funcs = {
1474	.update_plane = drm_atomic_helper_update_plane,
1475	.disable_plane = drm_atomic_helper_disable_plane,
1476	.destroy = vmw_du_primary_plane_destroy,
1477	.reset = vmw_du_plane_reset,
1478	.atomic_duplicate_state = vmw_du_plane_duplicate_state,
1479	.atomic_destroy_state = vmw_du_plane_destroy_state,
1480};
1481
1482static const struct drm_plane_funcs vmw_stdu_cursor_funcs = {
1483	.update_plane = drm_atomic_helper_update_plane,
1484	.disable_plane = drm_atomic_helper_disable_plane,
1485	.destroy = vmw_du_cursor_plane_destroy,
1486	.reset = vmw_du_plane_reset,
1487	.atomic_duplicate_state = vmw_du_plane_duplicate_state,
1488	.atomic_destroy_state = vmw_du_plane_destroy_state,
1489};
1490
1491
1492/*
1493 * Atomic Helpers
1494 */
1495static const struct
1496drm_plane_helper_funcs vmw_stdu_cursor_plane_helper_funcs = {
1497	.atomic_check = vmw_du_cursor_plane_atomic_check,
1498	.atomic_update = vmw_du_cursor_plane_atomic_update,
1499	.prepare_fb = vmw_du_cursor_plane_prepare_fb,
1500	.cleanup_fb = vmw_du_cursor_plane_cleanup_fb,
1501};
1502
1503static const struct
1504drm_plane_helper_funcs vmw_stdu_primary_plane_helper_funcs = {
1505	.atomic_check = vmw_du_primary_plane_atomic_check,
1506	.atomic_update = vmw_stdu_primary_plane_atomic_update,
1507	.prepare_fb = vmw_stdu_primary_plane_prepare_fb,
1508	.cleanup_fb = vmw_stdu_primary_plane_cleanup_fb,
1509};
1510
1511static const struct drm_crtc_helper_funcs vmw_stdu_crtc_helper_funcs = {
1512	.mode_set_nofb = vmw_stdu_crtc_mode_set_nofb,
1513	.atomic_check = vmw_du_crtc_atomic_check,
1514	.atomic_begin = vmw_du_crtc_atomic_begin,
1515	.atomic_flush = vmw_stdu_crtc_atomic_flush,
1516	.atomic_enable = vmw_vkms_crtc_atomic_enable,
1517	.atomic_disable = vmw_stdu_crtc_atomic_disable,
1518};
1519
1520
1521/**
1522 * vmw_stdu_init - Sets up a Screen Target Display Unit
1523 *
1524 * @dev_priv: VMW DRM device
1525 * @unit: unit number range from 0 to VMWGFX_NUM_DISPLAY_UNITS
1526 *
1527 * This function is called once per CRTC, and allocates one Screen Target
1528 * display unit to represent that CRTC.  Since the SVGA device does not separate
1529 * out encoder and connector, they are represented as part of the STDU as well.
1530 *
1531 * Returns: %0 on success or -errno code on failure
1532 */
1533static int vmw_stdu_init(struct vmw_private *dev_priv, unsigned unit)
1534{
1535	struct vmw_screen_target_display_unit *stdu;
1536	struct drm_device *dev = &dev_priv->drm;
1537	struct drm_connector *connector;
1538	struct drm_encoder *encoder;
1539	struct drm_plane *primary;
1540	struct vmw_cursor_plane *cursor;
1541	struct drm_crtc *crtc;
1542	int    ret;
1543
1544	stdu = kzalloc(sizeof(*stdu), GFP_KERNEL);
1545	if (!stdu)
1546		return -ENOMEM;
1547
1548	stdu->base.unit = unit;
1549	crtc = &stdu->base.crtc;
1550	encoder = &stdu->base.encoder;
1551	connector = &stdu->base.connector;
1552	primary = &stdu->base.primary;
1553	cursor = &stdu->base.cursor;
1554
1555	stdu->base.pref_active = (unit == 0);
1556	stdu->base.pref_width  = dev_priv->initial_width;
1557	stdu->base.pref_height = dev_priv->initial_height;
1558	stdu->base.is_implicit = false;
1559
1560	/* Initialize primary plane */
1561	ret = drm_universal_plane_init(dev, primary,
1562				       0, &vmw_stdu_plane_funcs,
1563				       vmw_primary_plane_formats,
1564				       ARRAY_SIZE(vmw_primary_plane_formats),
1565				       NULL, DRM_PLANE_TYPE_PRIMARY, NULL);
1566	if (ret) {
1567		DRM_ERROR("Failed to initialize primary plane");
1568		goto err_free;
1569	}
1570
1571	drm_plane_helper_add(primary, &vmw_stdu_primary_plane_helper_funcs);
1572	drm_plane_enable_fb_damage_clips(primary);
1573
1574	/* Initialize cursor plane */
1575	ret = drm_universal_plane_init(dev, &cursor->base,
1576			0, &vmw_stdu_cursor_funcs,
1577			vmw_cursor_plane_formats,
1578			ARRAY_SIZE(vmw_cursor_plane_formats),
1579			NULL, DRM_PLANE_TYPE_CURSOR, NULL);
1580	if (ret) {
1581		DRM_ERROR("Failed to initialize cursor plane");
1582		drm_plane_cleanup(&stdu->base.primary);
1583		goto err_free;
1584	}
1585
1586	drm_plane_helper_add(&cursor->base, &vmw_stdu_cursor_plane_helper_funcs);
1587
1588	ret = drm_connector_init(dev, connector, &vmw_stdu_connector_funcs,
1589				 DRM_MODE_CONNECTOR_VIRTUAL);
1590	if (ret) {
1591		DRM_ERROR("Failed to initialize connector\n");
1592		goto err_free;
1593	}
1594
1595	drm_connector_helper_add(connector, &vmw_stdu_connector_helper_funcs);
1596	connector->status = vmw_du_connector_detect(connector, false);
1597
1598	ret = drm_encoder_init(dev, encoder, &vmw_stdu_encoder_funcs,
1599			       DRM_MODE_ENCODER_VIRTUAL, NULL);
1600	if (ret) {
1601		DRM_ERROR("Failed to initialize encoder\n");
1602		goto err_free_connector;
1603	}
1604
1605	(void) drm_connector_attach_encoder(connector, encoder);
1606	encoder->possible_crtcs = (1 << unit);
1607	encoder->possible_clones = 0;
1608
1609	ret = drm_connector_register(connector);
1610	if (ret) {
1611		DRM_ERROR("Failed to register connector\n");
1612		goto err_free_encoder;
1613	}
1614
1615	ret = drm_crtc_init_with_planes(dev, crtc, primary,
1616					&cursor->base,
1617					&vmw_stdu_crtc_funcs, NULL);
1618	if (ret) {
1619		DRM_ERROR("Failed to initialize CRTC\n");
1620		goto err_free_unregister;
1621	}
1622
1623	drm_crtc_helper_add(crtc, &vmw_stdu_crtc_helper_funcs);
1624
1625	drm_mode_crtc_set_gamma_size(crtc, 256);
1626
1627	drm_object_attach_property(&connector->base,
1628				   dev_priv->hotplug_mode_update_property, 1);
1629	drm_object_attach_property(&connector->base,
1630				   dev->mode_config.suggested_x_property, 0);
1631	drm_object_attach_property(&connector->base,
1632				   dev->mode_config.suggested_y_property, 0);
1633
1634	vmw_du_init(&stdu->base);
1635
1636	return 0;
1637
1638err_free_unregister:
1639	drm_connector_unregister(connector);
1640err_free_encoder:
1641	drm_encoder_cleanup(encoder);
1642err_free_connector:
1643	drm_connector_cleanup(connector);
1644err_free:
1645	kfree(stdu);
1646	return ret;
1647}
1648
1649
1650
1651/**
1652 *  vmw_stdu_destroy - Cleans up a vmw_screen_target_display_unit
1653 *
1654 *  @stdu:  Screen Target Display Unit to be destroyed
1655 *
1656 *  Clean up after vmw_stdu_init
1657 */
1658static void vmw_stdu_destroy(struct vmw_screen_target_display_unit *stdu)
1659{
1660	vmw_du_cleanup(&stdu->base);
1661	kfree(stdu);
1662}
1663
1664
1665
1666/******************************************************************************
1667 * Screen Target Display KMS Functions
1668 *
1669 * These functions are called by the common KMS code in vmwgfx_kms.c
1670 *****************************************************************************/
1671
1672/**
1673 * vmw_kms_stdu_init_display - Initializes a Screen Target based display
1674 *
1675 * @dev_priv: VMW DRM device
1676 *
1677 * This function initialize a Screen Target based display device.  It checks
1678 * the capability bits to make sure the underlying hardware can support
1679 * screen targets, and then creates the maximum number of CRTCs, a.k.a Display
1680 * Units, as supported by the display hardware.
1681 *
1682 * RETURNS:
1683 * 0 on success, error code otherwise
1684 */
1685int vmw_kms_stdu_init_display(struct vmw_private *dev_priv)
1686{
1687	struct drm_device *dev = &dev_priv->drm;
1688	int i, ret;
1689
1690
1691	/* Do nothing if there's no support for MOBs */
1692	if (!dev_priv->has_mob)
1693		return -ENOSYS;
1694
1695	if (!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS))
1696		return -ENOSYS;
1697
1698	dev_priv->active_display_unit = vmw_du_screen_target;
1699
1700	for (i = 0; i < VMWGFX_NUM_DISPLAY_UNITS; ++i) {
1701		ret = vmw_stdu_init(dev_priv, i);
1702
1703		if (unlikely(ret != 0)) {
1704			drm_err(&dev_priv->drm,
1705				"Failed to initialize STDU %d", i);
1706			return ret;
1707		}
1708	}
1709
1710	drm_mode_config_reset(dev);
1711
1712	return 0;
1713}