diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c')
| -rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c | 102 | 
1 files changed, 86 insertions, 16 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a56e5d0ca3c6..a82fa9700370 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0 OR MIT  /**************************************************************************   * - * Copyright 2009-2022 VMware, Inc., Palo Alto, CA., USA + * Copyright 2009-2023 VMware, Inc., Palo Alto, CA., USA   *   * Permission is hereby granted, free of charge, to any person obtaining a   * copy of this software and associated documentation files (the @@ -25,11 +25,13 @@   *   **************************************************************************/ +#include "vmwgfx_bo.h" +#include "vmwgfx_kms.h" +  #include <drm/drm_atomic.h>  #include <drm/drm_atomic_helper.h>  #include <drm/drm_fourcc.h> -#include "vmwgfx_kms.h"  #define vmw_crtc_to_ldu(x) \  	container_of(x, struct vmw_legacy_display_unit, base.crtc) @@ -134,6 +136,47 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)  	return 0;  } +/* + * Pin the buffer in a location suitable for access by the + * display system. + */ +static int vmw_ldu_fb_pin(struct vmw_framebuffer *vfb) +{ +	struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); +	struct vmw_bo *buf; +	int ret; + +	buf = vfb->bo ?  vmw_framebuffer_to_vfbd(&vfb->base)->buffer : +		vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; + +	if (!buf) +		return 0; +	WARN_ON(dev_priv->active_display_unit != vmw_du_legacy); + +	if (dev_priv->active_display_unit == vmw_du_legacy) { +		vmw_overlay_pause_all(dev_priv); +		ret = vmw_bo_pin_in_start_of_vram(dev_priv, buf, false); +		vmw_overlay_resume_all(dev_priv); +	} else +		ret = -EINVAL; + +	return ret; +} + +static int vmw_ldu_fb_unpin(struct vmw_framebuffer *vfb) +{ +	struct vmw_private *dev_priv = vmw_priv(vfb->base.dev); +	struct vmw_bo *buf; + +	buf = vfb->bo ?  vmw_framebuffer_to_vfbd(&vfb->base)->buffer : +		vmw_framebuffer_to_vfbs(&vfb->base)->surface->res.guest_memory_bo; + +	if (WARN_ON(!buf)) +		return 0; + +	return vmw_bo_unpin(dev_priv, buf, false); +} +  static int vmw_ldu_del_active(struct vmw_private *vmw_priv,  			      struct vmw_legacy_display_unit *ldu)  { @@ -145,8 +188,7 @@ static int vmw_ldu_del_active(struct vmw_private *vmw_priv,  	list_del_init(&ldu->active);  	if (--(ld->num_active) == 0) {  		BUG_ON(!ld->fb); -		if (ld->fb->unpin) -			ld->fb->unpin(ld->fb); +		WARN_ON(vmw_ldu_fb_unpin(ld->fb));  		ld->fb = NULL;  	} @@ -163,11 +205,10 @@ static int vmw_ldu_add_active(struct vmw_private *vmw_priv,  	BUG_ON(!ld->num_active && ld->fb);  	if (vfb != ld->fb) { -		if (ld->fb && ld->fb->unpin) -			ld->fb->unpin(ld->fb); +		if (ld->fb) +			WARN_ON(vmw_ldu_fb_unpin(ld->fb));  		vmw_svga_enable(vmw_priv); -		if (vfb->pin) -			vfb->pin(vfb); +		WARN_ON(vmw_ldu_fb_pin(vfb));  		ld->fb = vfb;  	} @@ -234,6 +275,7 @@ static const struct drm_crtc_funcs vmw_legacy_crtc_funcs = {  	.atomic_duplicate_state = vmw_du_crtc_duplicate_state,  	.atomic_destroy_state = vmw_du_crtc_destroy_state,  	.set_config = drm_atomic_helper_set_config, +	.page_flip = drm_atomic_helper_page_flip,  }; @@ -273,6 +315,12 @@ static const struct  drm_connector_helper_funcs vmw_ldu_connector_helper_funcs = {  }; +static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, +				   struct vmw_framebuffer *framebuffer, +				   unsigned int flags, unsigned int color, +				   struct drm_mode_rect *clips, +				   unsigned int num_clips); +  /*   * Legacy Display Plane Functions   */ @@ -291,7 +339,6 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,  	struct drm_framebuffer *fb;  	struct drm_crtc *crtc = new_state->crtc ?: old_state->crtc; -  	ldu = vmw_crtc_to_ldu(crtc);  	dev_priv = vmw_priv(plane->dev);  	fb       = new_state->fb; @@ -304,8 +351,31 @@ vmw_ldu_primary_plane_atomic_update(struct drm_plane *plane,  		vmw_ldu_del_active(dev_priv, ldu);  	vmw_ldu_commit_list(dev_priv); -} +	if (vfb && vmw_cmd_supported(dev_priv)) { +		struct drm_mode_rect fb_rect = { +			.x1 = 0, +			.y1 = 0, +			.x2 = vfb->base.width, +			.y2 = vfb->base.height +		}; +		struct drm_mode_rect *damage_rects = drm_plane_get_damage_clips(new_state); +		u32 rect_count = drm_plane_get_damage_clips_count(new_state); +		int ret; + +		if (!damage_rects) { +			damage_rects = &fb_rect; +			rect_count = 1; +		} + +		ret = vmw_kms_ldu_do_bo_dirty(dev_priv, vfb, 0, 0, damage_rects, rect_count); + +		drm_WARN_ONCE(plane->dev, ret, +			"vmw_kms_ldu_do_bo_dirty failed with: ret=%d\n", ret); + +		vmw_cmd_flush(dev_priv, false); +	} +}  static const struct drm_plane_funcs vmw_ldu_plane_funcs = {  	.update_plane = drm_atomic_helper_update_plane, @@ -536,11 +606,11 @@ int vmw_kms_ldu_close_display(struct vmw_private *dev_priv)  } -int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, -			    struct vmw_framebuffer *framebuffer, -			    unsigned int flags, unsigned int color, -			    struct drm_clip_rect *clips, -			    unsigned int num_clips, int increment) +static int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv, +				   struct vmw_framebuffer *framebuffer, +				   unsigned int flags, unsigned int color, +				   struct drm_mode_rect *clips, +				   unsigned int num_clips)  {  	size_t fifo_size;  	int i; @@ -556,7 +626,7 @@ int vmw_kms_ldu_do_bo_dirty(struct vmw_private *dev_priv,  		return -ENOMEM;  	memset(cmd, 0, fifo_size); -	for (i = 0; i < num_clips; i++, clips += increment) { +	for (i = 0; i < num_clips; i++, clips++) {  		cmd[i].header = SVGA_CMD_UPDATE;  		cmd[i].body.x = clips->x1;  		cmd[i].body.y = clips->y1;  |