2018-05-07 01:16:26 +02:00
// SPDX-License-Identifier: GPL-2.0 OR MIT
2011-10-04 20:13:22 +02:00
/**************************************************************************
*
2018-05-07 01:16:26 +02:00
* Copyright 2011 - 2015 VMware , Inc . , Palo Alto , CA . , USA
2011-10-04 20:13:22 +02:00
*
* Permission is hereby granted , free of charge , to any person obtaining a
* copy of this software and associated documentation files ( the
* " Software " ) , to deal in the Software without restriction , including
* without limitation the rights to use , copy , modify , merge , publish ,
* distribute , sub license , and / or sell copies of the Software , and to
* permit persons to whom the Software is furnished to do so , subject to
* the following conditions :
*
* The above copyright notice and this permission notice ( including the
* next paragraph ) shall be included in all copies or substantial portions
* of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NON - INFRINGEMENT . IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS , AUTHORS AND / OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM ,
* DAMAGES OR OTHER LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR
* OTHERWISE , ARISING FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "vmwgfx_kms.h"
2014-10-29 10:03:57 +01:00
# include <drm/drm_plane_helper.h>
2017-03-23 11:48:44 -07:00
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
2018-08-08 15:41:56 -07:00
# include <drm/drm_damage_helper.h>
2011-10-04 20:13:22 +02:00
# define vmw_crtc_to_sou(x) \
container_of ( x , struct vmw_screen_object_unit , base . crtc )
# define vmw_encoder_to_sou(x) \
container_of ( x , struct vmw_screen_object_unit , base . encoder )
# define vmw_connector_to_sou(x) \
container_of ( x , struct vmw_screen_object_unit , base . connector )
2015-06-26 02:14:27 -07:00
/**
* struct vmw_kms_sou_surface_dirty - Closure structure for
* blit surface to screen command .
* @ base : The base type we derive from . Used by vmw_kms_helper_dirty ( ) .
* @ left : Left side of bounding box .
* @ right : Right side of bounding box .
* @ top : Top side of bounding box .
* @ bottom : Bottom side of bounding box .
* @ dst_x : Difference between source clip rects and framebuffer coordinates .
* @ dst_y : Difference between source clip rects and framebuffer coordinates .
* @ sid : Surface id of surface to copy from .
*/
struct vmw_kms_sou_surface_dirty {
struct vmw_kms_dirty base ;
s32 left , right , top , bottom ;
s32 dst_x , dst_y ;
u32 sid ;
} ;
/*
* SVGA commands that are used by this code . Please see the device headers
* for explanation .
*/
struct vmw_kms_sou_readback_blit {
uint32 header ;
SVGAFifoCmdBlitScreenToGMRFB body ;
} ;
2018-06-19 15:02:16 +02:00
struct vmw_kms_sou_bo_blit {
2015-06-26 02:14:27 -07:00
uint32 header ;
SVGAFifoCmdBlitGMRFBToScreen body ;
} ;
struct vmw_kms_sou_dirty_cmd {
SVGA3dCmdHeader header ;
SVGA3dCmdBlitSurfaceToScreen body ;
} ;
2018-08-08 15:02:48 -07:00
struct vmw_kms_sou_define_gmrfb {
uint32_t header ;
SVGAFifoCmdDefineGMRFB body ;
} ;
2011-10-04 20:13:22 +02:00
/**
* Display unit using screen objects .
*/
struct vmw_screen_object_unit {
struct vmw_display_unit base ;
unsigned long buffer_size ; /**< Size of allocated buffer */
2018-06-19 15:02:16 +02:00
struct vmw_buffer_object * buffer ; /**< Backing store buffer */
2011-10-04 20:13:22 +02:00
bool defined ;
} ;
static void vmw_sou_destroy ( struct vmw_screen_object_unit * sou )
{
2015-06-26 01:23:42 -07:00
vmw_du_cleanup ( & sou - > base ) ;
2011-10-04 20:13:22 +02:00
kfree ( sou ) ;
}
/*
* Screen Object Display Unit CRTC functions
*/
static void vmw_sou_crtc_destroy ( struct drm_crtc * crtc )
{
vmw_sou_destroy ( vmw_crtc_to_sou ( crtc ) ) ;
}
/**
* Send the fifo command to create a screen .
*/
static int vmw_sou_fifo_create ( struct vmw_private * dev_priv ,
struct vmw_screen_object_unit * sou ,
2018-06-20 11:34:26 +02:00
int x , int y ,
2011-10-04 20:13:22 +02:00
struct drm_display_mode * mode )
{
size_t fifo_size ;
struct {
struct {
uint32_t cmdType ;
} header ;
SVGAScreenObject obj ;
} * cmd ;
BUG_ON ( ! sou - > buffer ) ;
fifo_size = sizeof ( * cmd ) ;
cmd = vmw_fifo_reserve ( dev_priv , fifo_size ) ;
/* The hardware has hung, nothing we can do about it here. */
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Fifo reserve failed. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , fifo_size ) ;
cmd - > header . cmdType = SVGA_CMD_DEFINE_SCREEN ;
cmd - > obj . structSize = sizeof ( SVGAScreenObject ) ;
cmd - > obj . id = sou - > base . unit ;
cmd - > obj . flags = SVGA_SCREEN_HAS_ROOT |
( sou - > base . unit = = 0 ? SVGA_SCREEN_IS_PRIMARY : 0 ) ;
cmd - > obj . size . width = mode - > hdisplay ;
cmd - > obj . size . height = mode - > vdisplay ;
2018-06-20 11:34:26 +02:00
cmd - > obj . root . x = x ;
cmd - > obj . root . y = y ;
2016-02-12 09:57:15 +01:00
sou - > base . set_gui_x = cmd - > obj . root . x ;
sou - > base . set_gui_y = cmd - > obj . root . y ;
2011-10-04 20:13:22 +02:00
/* Ok to assume that buffer is pinned in vram */
2011-10-04 20:13:28 +02:00
vmw_bo_get_guest_ptr ( & sou - > buffer - > base , & cmd - > obj . backingStore . ptr ) ;
2011-10-04 20:13:22 +02:00
cmd - > obj . backingStore . pitch = mode - > hdisplay * 4 ;
vmw_fifo_commit ( dev_priv , fifo_size ) ;
sou - > defined = true ;
return 0 ;
}
/**
* Send the fifo command to destroy a screen .
*/
static int vmw_sou_fifo_destroy ( struct vmw_private * dev_priv ,
struct vmw_screen_object_unit * sou )
{
size_t fifo_size ;
int ret ;
struct {
struct {
uint32_t cmdType ;
} header ;
SVGAFifoCmdDestroyScreen body ;
} * cmd ;
/* no need to do anything */
if ( unlikely ( ! sou - > defined ) )
return 0 ;
fifo_size = sizeof ( * cmd ) ;
cmd = vmw_fifo_reserve ( dev_priv , fifo_size ) ;
/* the hardware has hung, nothing we can do about it here */
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Fifo reserve failed. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , fifo_size ) ;
cmd - > header . cmdType = SVGA_CMD_DESTROY_SCREEN ;
cmd - > body . screenId = sou - > base . unit ;
vmw_fifo_commit ( dev_priv , fifo_size ) ;
/* Force sync */
ret = vmw_fallback_wait ( dev_priv , false , true , 0 , false , 3 * HZ ) ;
if ( unlikely ( ret ! = 0 ) )
DRM_ERROR ( " Failed to sync with HW " ) ;
else
sou - > defined = false ;
return ret ;
}
2017-03-23 13:14:54 -07:00
/**
* vmw_sou_crtc_mode_set_nofb - Create new screen
*
* @ crtc : CRTC associated with the new screen
*
* This function creates / destroys a screen . This function cannot fail , so if
* somehow we run into a failure , just do the best we can to get out .
*/
static void vmw_sou_crtc_mode_set_nofb ( struct drm_crtc * crtc )
{
struct vmw_private * dev_priv ;
struct vmw_screen_object_unit * sou ;
struct vmw_framebuffer * vfb ;
struct drm_framebuffer * fb ;
struct drm_plane_state * ps ;
struct vmw_plane_state * vps ;
int ret ;
2018-06-20 11:34:26 +02:00
sou = vmw_crtc_to_sou ( crtc ) ;
2017-03-23 13:14:54 -07:00
dev_priv = vmw_priv ( crtc - > dev ) ;
2018-06-20 11:34:26 +02:00
ps = crtc - > primary - > state ;
fb = ps - > fb ;
vps = vmw_plane_state_to_vps ( ps ) ;
2017-03-23 13:14:54 -07:00
vfb = ( fb ) ? vmw_framebuffer_to_vfb ( fb ) : NULL ;
if ( sou - > defined ) {
ret = vmw_sou_fifo_destroy ( dev_priv , sou ) ;
if ( ret ) {
DRM_ERROR ( " Failed to destroy Screen Object \n " ) ;
return ;
}
}
if ( vfb ) {
2018-06-20 11:34:26 +02:00
struct drm_connector_state * conn_state ;
struct vmw_connector_state * vmw_conn_state ;
int x , y ;
2018-06-19 15:02:16 +02:00
sou - > buffer = vps - > bo ;
sou - > buffer_size = vps - > bo_size ;
2017-03-23 13:14:54 -07:00
2018-06-20 11:34:26 +02:00
if ( sou - > base . is_implicit ) {
x = crtc - > x ;
y = crtc - > y ;
} else {
conn_state = sou - > base . connector . state ;
vmw_conn_state = vmw_connector_state_to_vcs ( conn_state ) ;
x = vmw_conn_state - > gui_x ;
y = vmw_conn_state - > gui_y ;
}
2017-03-23 13:14:54 -07:00
2018-06-20 11:34:26 +02:00
ret = vmw_sou_fifo_create ( dev_priv , sou , x , y , & crtc - > mode ) ;
2017-03-23 13:14:54 -07:00
if ( ret )
DRM_ERROR ( " Failed to define Screen Object %dx%d \n " ,
crtc - > x , crtc - > y ) ;
vmw_kms_add_active ( dev_priv , & sou - > base , vfb ) ;
} else {
sou - > buffer = NULL ;
sou - > buffer_size = 0 ;
vmw_kms_del_active ( dev_priv , & sou - > base ) ;
}
}
/**
* vmw_sou_crtc_helper_prepare - Noop
*
* @ crtc : CRTC associated with the new screen
*
* Prepares the CRTC for a mode set , but we don ' t need to do anything here .
*/
static void vmw_sou_crtc_helper_prepare ( struct drm_crtc * crtc )
{
}
/**
2017-06-30 12:36:44 +03:00
* vmw_sou_crtc_atomic_enable - Noop
2017-03-23 13:14:54 -07:00
*
* @ crtc : CRTC associated with the new screen
*
* This is called after a mode set has been completed .
*/
2017-06-30 12:36:44 +03:00
static void vmw_sou_crtc_atomic_enable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
2017-03-23 13:14:54 -07:00
{
}
/**
2017-06-30 12:36:45 +03:00
* vmw_sou_crtc_atomic_disable - Turns off CRTC
2017-03-23 13:14:54 -07:00
*
* @ crtc : CRTC to be turned off
*/
2017-06-30 12:36:45 +03:00
static void vmw_sou_crtc_atomic_disable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
2017-03-23 13:14:54 -07:00
{
struct vmw_private * dev_priv ;
struct vmw_screen_object_unit * sou ;
int ret ;
if ( ! crtc ) {
DRM_ERROR ( " CRTC is NULL \n " ) ;
return ;
}
sou = vmw_crtc_to_sou ( crtc ) ;
dev_priv = vmw_priv ( crtc - > dev ) ;
if ( sou - > defined ) {
ret = vmw_sou_fifo_destroy ( dev_priv , sou ) ;
if ( ret )
DRM_ERROR ( " Failed to destroy Screen Object \n " ) ;
}
}
2015-06-26 01:23:42 -07:00
static int vmw_sou_crtc_page_flip ( struct drm_crtc * crtc ,
2017-03-23 14:38:18 -07:00
struct drm_framebuffer * new_fb ,
2015-06-26 01:23:42 -07:00
struct drm_pending_vblank_event * event ,
2017-03-22 22:50:50 +01:00
uint32_t flags ,
struct drm_modeset_acquire_ctx * ctx )
2015-06-26 01:23:42 -07:00
{
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
int ret ;
2016-02-12 09:00:26 +01:00
if ( ! vmw_kms_crtc_flippable ( dev_priv , crtc ) )
2015-06-26 01:23:42 -07:00
return - EINVAL ;
2018-01-16 08:31:04 +01:00
ret = drm_atomic_helper_page_flip ( crtc , new_fb , event , flags , ctx ) ;
2017-03-23 14:38:18 -07:00
if ( ret ) {
DRM_ERROR ( " Page flip error %d. \n " , ret ) ;
return ret ;
}
2015-06-26 01:23:42 -07:00
if ( vmw_crtc_to_du ( crtc ) - > is_implicit )
2016-02-12 09:00:26 +01:00
vmw_kms_update_implicit_fb ( dev_priv , crtc ) ;
2015-06-26 01:23:42 -07:00
return ret ;
}
2015-12-15 12:21:15 +01:00
static const struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
2011-10-04 20:13:22 +02:00
. gamma_set = vmw_du_crtc_gamma_set ,
. destroy = vmw_sou_crtc_destroy ,
2017-03-23 11:33:39 -07:00
. reset = vmw_du_crtc_reset ,
. atomic_duplicate_state = vmw_du_crtc_duplicate_state ,
. atomic_destroy_state = vmw_du_crtc_destroy_state ,
2017-03-23 14:38:18 -07:00
. set_config = vmw_kms_set_config ,
2015-06-26 01:23:42 -07:00
. page_flip = vmw_sou_crtc_page_flip ,
2011-10-04 20:13:22 +02:00
} ;
/*
* Screen Object Display Unit encoder functions
*/
static void vmw_sou_encoder_destroy ( struct drm_encoder * encoder )
{
vmw_sou_destroy ( vmw_encoder_to_sou ( encoder ) ) ;
}
2015-12-15 12:21:15 +01:00
static const struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
2011-10-04 20:13:22 +02:00
. destroy = vmw_sou_encoder_destroy ,
} ;
/*
* Screen Object Display Unit connector functions
*/
static void vmw_sou_connector_destroy ( struct drm_connector * connector )
{
vmw_sou_destroy ( vmw_connector_to_sou ( connector ) ) ;
}
2015-12-15 12:21:15 +01:00
static const struct drm_connector_funcs vmw_sou_connector_funcs = {
2011-10-04 20:13:22 +02:00
. dpms = vmw_du_connector_dpms ,
2016-03-07 18:06:01 +01:00
. detect = vmw_du_connector_detect ,
. fill_modes = vmw_du_connector_fill_modes ,
2011-10-04 20:13:22 +02:00
. set_property = vmw_du_connector_set_property ,
. destroy = vmw_sou_connector_destroy ,
2017-03-23 11:48:44 -07:00
. reset = vmw_du_connector_reset ,
2018-01-17 10:16:20 -05:00
. atomic_duplicate_state = vmw_du_connector_duplicate_state ,
. atomic_destroy_state = vmw_du_connector_destroy_state ,
2017-03-23 11:48:44 -07:00
. atomic_set_property = vmw_du_connector_atomic_set_property ,
. atomic_get_property = vmw_du_connector_atomic_get_property ,
2011-10-04 20:13:22 +02:00
} ;
2017-03-23 14:23:20 -07:00
static const struct
drm_connector_helper_funcs vmw_sou_connector_helper_funcs = {
} ;
2017-03-23 11:28:11 -07:00
/*
* Screen Object Display Plane Functions
*/
2017-03-23 14:18:32 -07:00
/**
* vmw_sou_primary_plane_cleanup_fb - Frees sou backing buffer
*
* @ plane : display plane
* @ old_state : Contains the FB to clean up
*
* Unpins the display surface
*
* Returns 0 on success
*/
static void
vmw_sou_primary_plane_cleanup_fb ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct vmw_plane_state * vps = vmw_plane_state_to_vps ( old_state ) ;
2018-03-22 10:35:18 +01:00
struct drm_crtc * crtc = plane - > state - > crtc ?
plane - > state - > crtc : old_state - > crtc ;
2017-03-23 14:18:32 -07:00
2018-06-19 15:02:16 +02:00
if ( vps - > bo )
vmw_bo_unpin ( vmw_priv ( crtc - > dev ) , vps - > bo , false ) ;
vmw_bo_unreference ( & vps - > bo ) ;
vps - > bo_size = 0 ;
2017-03-23 14:18:32 -07:00
vmw_du_plane_cleanup_fb ( plane , old_state ) ;
}
/**
* vmw_sou_primary_plane_prepare_fb - allocate backing buffer
*
* @ plane : display plane
* @ new_state : info on the new plane state , including the FB
*
* The SOU backing buffer is our equivalent of the display plane .
*
* Returns 0 on success
*/
static int
vmw_sou_primary_plane_prepare_fb ( struct drm_plane * plane ,
struct drm_plane_state * new_state )
{
struct drm_framebuffer * new_fb = new_state - > fb ;
struct drm_crtc * crtc = plane - > state - > crtc ? : new_state - > crtc ;
struct vmw_plane_state * vps = vmw_plane_state_to_vps ( new_state ) ;
struct vmw_private * dev_priv ;
size_t size ;
int ret ;
if ( ! new_fb ) {
2018-06-19 15:02:16 +02:00
vmw_bo_unreference ( & vps - > bo ) ;
vps - > bo_size = 0 ;
2017-03-23 14:18:32 -07:00
return 0 ;
}
size = new_state - > crtc_w * new_state - > crtc_h * 4 ;
2018-03-22 10:35:18 +01:00
dev_priv = vmw_priv ( crtc - > dev ) ;
2017-03-23 14:18:32 -07:00
2018-06-19 15:02:16 +02:00
if ( vps - > bo ) {
if ( vps - > bo_size = = size ) {
2018-03-22 10:35:18 +01:00
/*
* Note that this might temporarily up the pin - count
* to 2 , until cleanup_fb ( ) is called .
*/
2018-06-19 15:02:16 +02:00
return vmw_bo_pin_in_vram ( dev_priv , vps - > bo ,
2018-03-22 10:35:18 +01:00
true ) ;
}
2017-03-23 14:18:32 -07:00
2018-06-19 15:02:16 +02:00
vmw_bo_unreference ( & vps - > bo ) ;
vps - > bo_size = 0 ;
2017-03-23 14:18:32 -07:00
}
2018-06-19 15:02:16 +02:00
vps - > bo = kzalloc ( sizeof ( * vps - > bo ) , GFP_KERNEL ) ;
if ( ! vps - > bo )
2017-03-23 14:18:32 -07:00
return - ENOMEM ;
vmw_svga_enable ( dev_priv ) ;
/* After we have alloced the backing store might not be able to
* resume the overlays , this is preferred to failing to alloc .
*/
vmw_overlay_pause_all ( dev_priv ) ;
2018-06-19 15:02:16 +02:00
ret = vmw_bo_init ( dev_priv , vps - > bo , size ,
2017-03-23 14:18:32 -07:00
& vmw_vram_ne_placement ,
2018-06-19 15:02:16 +02:00
false , & vmw_bo_bo_free ) ;
2017-03-23 14:18:32 -07:00
vmw_overlay_resume_all ( dev_priv ) ;
2018-03-22 10:35:18 +01:00
if ( ret ) {
2018-06-19 15:02:16 +02:00
vps - > bo = NULL ; /* vmw_bo_init frees on error */
2018-03-22 10:35:18 +01:00
return ret ;
}
2017-03-23 14:18:32 -07:00
2018-06-19 15:02:16 +02:00
vps - > bo_size = size ;
2018-05-15 15:39:09 +02:00
2018-03-22 10:35:18 +01:00
/*
* TTM already thinks the buffer is pinned , but make sure the
* pin_count is upped .
*/
2018-06-19 15:02:16 +02:00
return vmw_bo_pin_in_vram ( dev_priv , vps - > bo , true ) ;
2017-03-23 14:18:32 -07:00
}
2018-08-08 15:02:48 -07:00
static uint32_t vmw_sou_bo_fifo_size ( struct vmw_du_update_plane * update ,
uint32_t num_hits )
{
return sizeof ( struct vmw_kms_sou_define_gmrfb ) +
sizeof ( struct vmw_kms_sou_bo_blit ) * num_hits ;
}
static uint32_t vmw_sou_bo_define_gmrfb ( struct vmw_du_update_plane * update ,
void * cmd )
{
struct vmw_framebuffer_bo * vfbbo =
container_of ( update - > vfb , typeof ( * vfbbo ) , base ) ;
struct vmw_kms_sou_define_gmrfb * gmr = cmd ;
int depth = update - > vfb - > base . format - > depth ;
/* Emulate RGBA support, contrary to svga_reg.h this is not
* supported by hosts . This is only a problem if we are reading
* this value later and expecting what we uploaded back .
*/
if ( depth = = 32 )
depth = 24 ;
gmr - > header = SVGA_CMD_DEFINE_GMRFB ;
gmr - > body . format . bitsPerPixel = update - > vfb - > base . format - > cpp [ 0 ] * 8 ;
gmr - > body . format . colorDepth = depth ;
gmr - > body . format . reserved = 0 ;
gmr - > body . bytesPerLine = update - > vfb - > base . pitches [ 0 ] ;
vmw_bo_get_guest_ptr ( & vfbbo - > buffer - > base , & gmr - > body . ptr ) ;
return sizeof ( * gmr ) ;
}
static uint32_t vmw_sou_bo_populate_clip ( struct vmw_du_update_plane * update ,
void * cmd , struct drm_rect * clip ,
uint32_t fb_x , uint32_t fb_y )
{
struct vmw_kms_sou_bo_blit * blit = cmd ;
blit - > header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN ;
blit - > body . destScreenId = update - > du - > unit ;
blit - > body . srcOrigin . x = fb_x ;
blit - > body . srcOrigin . y = fb_y ;
blit - > body . destRect . left = clip - > x1 ;
blit - > body . destRect . top = clip - > y1 ;
blit - > body . destRect . right = clip - > x2 ;
blit - > body . destRect . bottom = clip - > y2 ;
return sizeof ( * blit ) ;
}
static uint32_t vmw_stud_bo_post_clip ( struct vmw_du_update_plane * update ,
void * cmd , struct drm_rect * bb )
{
return 0 ;
}
/**
* vmw_sou_plane_update_bo - Update display unit for bo backed fb .
* @ dev_priv : Device private .
* @ plane : Plane state .
* @ old_state : Old plane state .
* @ vfb : Framebuffer which is blitted to display unit .
* @ out_fence : If non - NULL , will return a ref - counted pointer to vmw_fence_obj .
* The returned fence pointer may be NULL in which case the device
* has already synchronized .
*
* Return : 0 on success or a negative error code on failure .
*/
static int vmw_sou_plane_update_bo ( struct vmw_private * dev_priv ,
struct drm_plane * plane ,
struct drm_plane_state * old_state ,
struct vmw_framebuffer * vfb ,
struct vmw_fence_obj * * out_fence )
{
struct vmw_du_update_plane_buffer bo_update ;
memset ( & bo_update , 0 , sizeof ( struct vmw_du_update_plane_buffer ) ) ;
bo_update . base . plane = plane ;
bo_update . base . old_state = old_state ;
bo_update . base . dev_priv = dev_priv ;
bo_update . base . du = vmw_crtc_to_du ( plane - > state - > crtc ) ;
bo_update . base . vfb = vfb ;
bo_update . base . out_fence = out_fence ;
bo_update . base . mutex = NULL ;
bo_update . base . cpu_blit = false ;
bo_update . base . intr = true ;
bo_update . base . calc_fifo_size = vmw_sou_bo_fifo_size ;
bo_update . base . post_prepare = vmw_sou_bo_define_gmrfb ;
bo_update . base . clip = vmw_sou_bo_populate_clip ;
bo_update . base . post_clip = vmw_stud_bo_post_clip ;
return vmw_du_helper_plane_update ( & bo_update . base ) ;
}
2018-08-08 12:39:31 -07:00
static uint32_t vmw_sou_surface_fifo_size ( struct vmw_du_update_plane * update ,
uint32_t num_hits )
{
return sizeof ( struct vmw_kms_sou_dirty_cmd ) + sizeof ( SVGASignedRect ) *
num_hits ;
}
static uint32_t vmw_sou_surface_post_prepare ( struct vmw_du_update_plane * update ,
void * cmd )
{
struct vmw_du_update_plane_surface * srf_update ;
srf_update = container_of ( update , typeof ( * srf_update ) , base ) ;
/*
* SOU SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN is special in the sense that
* its bounding box is filled before iterating over all the clips . So
* store the FIFO start address and revisit to fill the details .
*/
srf_update - > cmd_start = cmd ;
return 0 ;
}
static uint32_t vmw_sou_surface_pre_clip ( struct vmw_du_update_plane * update ,
void * cmd , uint32_t num_hits )
{
struct vmw_kms_sou_dirty_cmd * blit = cmd ;
struct vmw_framebuffer_surface * vfbs ;
vfbs = container_of ( update - > vfb , typeof ( * vfbs ) , base ) ;
blit - > header . id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN ;
blit - > header . size = sizeof ( blit - > body ) + sizeof ( SVGASignedRect ) *
num_hits ;
blit - > body . srcImage . sid = vfbs - > surface - > res . id ;
blit - > body . destScreenId = update - > du - > unit ;
/* Update the source and destination bounding box later in post_clip */
blit - > body . srcRect . left = 0 ;
blit - > body . srcRect . top = 0 ;
blit - > body . srcRect . right = 0 ;
blit - > body . srcRect . bottom = 0 ;
blit - > body . destRect . left = 0 ;
blit - > body . destRect . top = 0 ;
blit - > body . destRect . right = 0 ;
blit - > body . destRect . bottom = 0 ;
return sizeof ( * blit ) ;
}
static uint32_t vmw_sou_surface_clip_rect ( struct vmw_du_update_plane * update ,
void * cmd , struct drm_rect * clip ,
uint32_t src_x , uint32_t src_y )
{
SVGASignedRect * rect = cmd ;
/*
* rects are relative to dest bounding box rect on screen object , so
* translate to it later in post_clip
*/
rect - > left = clip - > x1 ;
rect - > top = clip - > y1 ;
rect - > right = clip - > x2 ;
rect - > bottom = clip - > y2 ;
return sizeof ( * rect ) ;
}
static uint32_t vmw_sou_surface_post_clip ( struct vmw_du_update_plane * update ,
void * cmd , struct drm_rect * bb )
{
struct vmw_du_update_plane_surface * srf_update ;
struct drm_plane_state * state = update - > plane - > state ;
struct drm_rect src_bb ;
struct vmw_kms_sou_dirty_cmd * blit ;
SVGASignedRect * rect ;
uint32_t num_hits ;
int translate_src_x ;
int translate_src_y ;
int i ;
srf_update = container_of ( update , typeof ( * srf_update ) , base ) ;
blit = srf_update - > cmd_start ;
rect = ( SVGASignedRect * ) & blit [ 1 ] ;
num_hits = ( blit - > header . size - sizeof ( blit - > body ) ) /
sizeof ( SVGASignedRect ) ;
src_bb = * bb ;
/* To translate bb back to fb src coord */
translate_src_x = ( state - > src_x > > 16 ) - state - > crtc_x ;
translate_src_y = ( state - > src_y > > 16 ) - state - > crtc_y ;
drm_rect_translate ( & src_bb , translate_src_x , translate_src_y ) ;
blit - > body . srcRect . left = src_bb . x1 ;
blit - > body . srcRect . top = src_bb . y1 ;
blit - > body . srcRect . right = src_bb . x2 ;
blit - > body . srcRect . bottom = src_bb . y2 ;
blit - > body . destRect . left = bb - > x1 ;
blit - > body . destRect . top = bb - > y1 ;
blit - > body . destRect . right = bb - > x2 ;
blit - > body . destRect . bottom = bb - > y2 ;
/* rects are relative to dest bb rect */
for ( i = 0 ; i < num_hits ; i + + ) {
rect - > left - = bb - > x1 ;
rect - > top - = bb - > y1 ;
rect - > right - = bb - > x1 ;
rect - > bottom - = bb - > y1 ;
rect + + ;
}
return 0 ;
}
/**
* vmw_sou_plane_update_surface - Update display unit for surface backed fb .
* @ dev_priv : Device private .
* @ plane : Plane state .
* @ old_state : Old plane state .
* @ vfb : Framebuffer which is blitted to display unit
* @ out_fence : If non - NULL , will return a ref - counted pointer to vmw_fence_obj .
* The returned fence pointer may be NULL in which case the device
* has already synchronized .
*
* Return : 0 on success or a negative error code on failure .
*/
static int vmw_sou_plane_update_surface ( struct vmw_private * dev_priv ,
struct drm_plane * plane ,
struct drm_plane_state * old_state ,
struct vmw_framebuffer * vfb ,
struct vmw_fence_obj * * out_fence )
{
struct vmw_du_update_plane_surface srf_update ;
memset ( & srf_update , 0 , sizeof ( struct vmw_du_update_plane_surface ) ) ;
srf_update . base . plane = plane ;
srf_update . base . old_state = old_state ;
srf_update . base . dev_priv = dev_priv ;
srf_update . base . du = vmw_crtc_to_du ( plane - > state - > crtc ) ;
srf_update . base . vfb = vfb ;
srf_update . base . out_fence = out_fence ;
srf_update . base . mutex = & dev_priv - > cmdbuf_mutex ;
srf_update . base . cpu_blit = false ;
srf_update . base . intr = true ;
srf_update . base . calc_fifo_size = vmw_sou_surface_fifo_size ;
srf_update . base . post_prepare = vmw_sou_surface_post_prepare ;
srf_update . base . pre_clip = vmw_sou_surface_pre_clip ;
srf_update . base . clip = vmw_sou_surface_clip_rect ;
srf_update . base . post_clip = vmw_sou_surface_post_clip ;
return vmw_du_helper_plane_update ( & srf_update . base ) ;
}
2017-03-23 14:18:32 -07:00
static void
vmw_sou_primary_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
2017-03-23 14:38:18 -07:00
struct drm_crtc * crtc = plane - > state - > crtc ;
2018-01-16 08:31:04 +01:00
struct drm_pending_vblank_event * event = NULL ;
struct vmw_fence_obj * fence = NULL ;
int ret ;
2018-09-21 14:10:35 -07:00
/* In case of device error, maintain consistent atomic state */
2018-01-16 08:31:04 +01:00
if ( crtc & & plane - > state - > fb ) {
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
struct vmw_framebuffer * vfb =
vmw_framebuffer_to_vfb ( plane - > state - > fb ) ;
2018-06-19 15:02:16 +02:00
if ( vfb - > bo )
2018-09-21 14:07:33 -07:00
ret = vmw_sou_plane_update_bo ( dev_priv , plane ,
old_state , vfb , & fence ) ;
2018-01-16 08:31:04 +01:00
else
2018-09-21 14:07:33 -07:00
ret = vmw_sou_plane_update_surface ( dev_priv , plane ,
old_state , vfb ,
& fence ) ;
2018-01-16 08:31:04 +01:00
if ( ret ! = 0 )
DRM_ERROR ( " Failed to update screen. \n " ) ;
} else {
2018-09-21 14:10:35 -07:00
/* Do nothing when fb and crtc is NULL (blank crtc) */
2018-01-16 08:31:04 +01:00
return ;
}
2018-09-21 14:10:35 -07:00
/* For error case vblank event is send from vmw_du_crtc_atomic_flush */
2018-01-16 08:31:04 +01:00
event = crtc - > state - > event ;
if ( event & & fence ) {
struct drm_file * file_priv = event - > base . file_priv ;
ret = vmw_event_fence_action_queue ( file_priv ,
fence ,
& event - > base ,
& event - > event . vbl . tv_sec ,
& event - > event . vbl . tv_usec ,
true ) ;
if ( unlikely ( ret ! = 0 ) )
DRM_ERROR ( " Failed to queue event on fence. \n " ) ;
else
crtc - > state - > event = NULL ;
}
if ( fence )
vmw_fence_obj_unreference ( & fence ) ;
2017-03-23 14:18:32 -07:00
}
2017-03-23 11:28:11 -07:00
static const struct drm_plane_funcs vmw_sou_plane_funcs = {
2017-03-23 14:38:18 -07:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2017-03-23 11:28:11 -07:00
. destroy = vmw_du_primary_plane_destroy ,
2017-03-23 11:36:05 -07:00
. reset = vmw_du_plane_reset ,
. atomic_duplicate_state = vmw_du_plane_duplicate_state ,
. atomic_destroy_state = vmw_du_plane_destroy_state ,
2017-03-23 11:28:11 -07:00
} ;
static const struct drm_plane_funcs vmw_sou_cursor_funcs = {
2017-03-23 14:38:18 -07:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2017-03-23 11:28:11 -07:00
. destroy = vmw_du_cursor_plane_destroy ,
2017-03-23 11:36:05 -07:00
. reset = vmw_du_plane_reset ,
. atomic_duplicate_state = vmw_du_plane_duplicate_state ,
. atomic_destroy_state = vmw_du_plane_destroy_state ,
2017-03-23 11:28:11 -07:00
} ;
2017-03-23 13:14:54 -07:00
/*
* Atomic Helpers
*/
2017-03-23 14:18:32 -07:00
static const struct
drm_plane_helper_funcs vmw_sou_cursor_plane_helper_funcs = {
. atomic_check = vmw_du_cursor_plane_atomic_check ,
. atomic_update = vmw_du_cursor_plane_atomic_update ,
. prepare_fb = vmw_du_cursor_plane_prepare_fb ,
. cleanup_fb = vmw_du_plane_cleanup_fb ,
} ;
static const struct
drm_plane_helper_funcs vmw_sou_primary_plane_helper_funcs = {
. atomic_check = vmw_du_primary_plane_atomic_check ,
. atomic_update = vmw_sou_primary_plane_atomic_update ,
. prepare_fb = vmw_sou_primary_plane_prepare_fb ,
. cleanup_fb = vmw_sou_primary_plane_cleanup_fb ,
} ;
2017-03-23 13:14:54 -07:00
static const struct drm_crtc_helper_funcs vmw_sou_crtc_helper_funcs = {
. prepare = vmw_sou_crtc_helper_prepare ,
. mode_set_nofb = vmw_sou_crtc_mode_set_nofb ,
. atomic_check = vmw_du_crtc_atomic_check ,
. atomic_begin = vmw_du_crtc_atomic_begin ,
. atomic_flush = vmw_du_crtc_atomic_flush ,
2017-06-30 12:36:44 +03:00
. atomic_enable = vmw_sou_crtc_atomic_enable ,
2017-06-30 12:36:45 +03:00
. atomic_disable = vmw_sou_crtc_atomic_disable ,
2017-03-23 13:14:54 -07:00
} ;
2017-03-23 11:28:11 -07:00
2011-10-04 20:13:22 +02:00
static int vmw_sou_init ( struct vmw_private * dev_priv , unsigned unit )
{
struct vmw_screen_object_unit * sou ;
struct drm_device * dev = dev_priv - > dev ;
struct drm_connector * connector ;
struct drm_encoder * encoder ;
2017-03-23 11:36:05 -07:00
struct drm_plane * primary , * cursor ;
2011-10-04 20:13:22 +02:00
struct drm_crtc * crtc ;
2017-03-23 11:28:11 -07:00
int ret ;
2011-10-04 20:13:22 +02:00
sou = kzalloc ( sizeof ( * sou ) , GFP_KERNEL ) ;
if ( ! sou )
return - ENOMEM ;
sou - > base . unit = unit ;
crtc = & sou - > base . crtc ;
encoder = & sou - > base . encoder ;
connector = & sou - > base . connector ;
2017-03-23 11:36:05 -07:00
primary = & sou - > base . primary ;
cursor = & sou - > base . cursor ;
2011-10-04 20:13:22 +02:00
2016-02-12 09:00:26 +01:00
sou - > base . active_implicit = false ;
2011-10-04 20:13:22 +02:00
sou - > base . pref_active = ( unit = = 0 ) ;
2012-02-09 16:56:46 +01:00
sou - > base . pref_width = dev_priv - > initial_width ;
sou - > base . pref_height = dev_priv - > initial_height ;
2011-10-04 20:13:22 +02:00
sou - > base . pref_mode = NULL ;
2017-03-23 11:33:39 -07:00
/*
* Remove this after enabling atomic because property values can
* only exist in a state object
*/
2016-02-12 09:59:50 +01:00
sou - > base . is_implicit = false ;
2011-10-04 20:13:22 +02:00
2017-03-23 11:28:11 -07:00
/* Initialize primary plane */
2017-03-23 11:36:05 -07:00
vmw_du_plane_reset ( primary ) ;
2017-03-23 11:28:11 -07:00
ret = drm_universal_plane_init ( dev , & sou - > base . primary ,
0 , & vmw_sou_plane_funcs ,
vmw_primary_plane_formats ,
ARRAY_SIZE ( vmw_primary_plane_formats ) ,
2017-07-23 20:46:38 -07:00
NULL , DRM_PLANE_TYPE_PRIMARY , NULL ) ;
2017-03-23 11:28:11 -07:00
if ( ret ) {
DRM_ERROR ( " Failed to initialize primary plane " ) ;
goto err_free ;
}
2017-03-23 14:18:32 -07:00
drm_plane_helper_add ( primary , & vmw_sou_primary_plane_helper_funcs ) ;
2018-08-08 15:41:56 -07:00
drm_plane_enable_fb_damage_clips ( primary ) ;
2017-03-23 14:18:32 -07:00
2017-03-23 11:28:11 -07:00
/* Initialize cursor plane */
2017-03-23 11:36:05 -07:00
vmw_du_plane_reset ( cursor ) ;
2017-03-23 11:28:11 -07:00
ret = drm_universal_plane_init ( dev , & sou - > base . cursor ,
0 , & vmw_sou_cursor_funcs ,
vmw_cursor_plane_formats ,
ARRAY_SIZE ( vmw_cursor_plane_formats ) ,
2017-07-23 20:46:38 -07:00
NULL , DRM_PLANE_TYPE_CURSOR , NULL ) ;
2017-03-23 11:28:11 -07:00
if ( ret ) {
DRM_ERROR ( " Failed to initialize cursor plane " ) ;
drm_plane_cleanup ( & sou - > base . primary ) ;
goto err_free ;
}
2017-03-23 14:18:32 -07:00
drm_plane_helper_add ( cursor , & vmw_sou_cursor_plane_helper_funcs ) ;
vmw_du_connector_reset ( connector ) ;
2017-03-23 11:28:11 -07:00
ret = drm_connector_init ( dev , connector , & vmw_sou_connector_funcs ,
DRM_MODE_CONNECTOR_VIRTUAL ) ;
if ( ret ) {
DRM_ERROR ( " Failed to initialize connector \n " ) ;
goto err_free ;
}
2017-03-23 14:23:20 -07:00
drm_connector_helper_add ( connector , & vmw_sou_connector_helper_funcs ) ;
2011-10-04 20:13:22 +02:00
connector - > status = vmw_du_connector_detect ( connector , true ) ;
2017-03-23 11:48:44 -07:00
vmw_connector_state_to_vcs ( connector - > state ) - > is_implicit = false ;
2011-10-04 20:13:22 +02:00
2017-03-23 11:28:11 -07:00
ret = drm_encoder_init ( dev , encoder , & vmw_screen_object_encoder_funcs ,
DRM_MODE_ENCODER_VIRTUAL , NULL ) ;
if ( ret ) {
DRM_ERROR ( " Failed to initialize encoder \n " ) ;
goto err_free_connector ;
}
2018-07-09 10:40:07 +02:00
( void ) drm_connector_attach_encoder ( connector , encoder ) ;
2011-10-04 20:13:22 +02:00
encoder - > possible_crtcs = ( 1 < < unit ) ;
encoder - > possible_clones = 0 ;
2017-03-23 11:28:11 -07:00
ret = drm_connector_register ( connector ) ;
if ( ret ) {
DRM_ERROR ( " Failed to register connector \n " ) ;
goto err_free_encoder ;
}
2013-12-02 06:04:38 -08:00
2017-03-23 11:48:44 -07:00
vmw_du_crtc_reset ( crtc ) ;
2017-03-23 11:28:11 -07:00
ret = drm_crtc_init_with_planes ( dev , crtc , & sou - > base . primary ,
& sou - > base . cursor ,
& vmw_screen_object_crtc_funcs , NULL ) ;
if ( ret ) {
DRM_ERROR ( " Failed to initialize CRTC \n " ) ;
goto err_free_unregister ;
}
2011-10-04 20:13:22 +02:00
2017-03-23 13:14:54 -07:00
drm_crtc_helper_add ( crtc , & vmw_sou_crtc_helper_funcs ) ;
2011-10-04 20:13:22 +02:00
drm_mode_crtc_set_gamma_size ( crtc , 256 ) ;
2016-02-12 09:45:42 +01:00
drm_object_attach_property ( & connector - > base ,
dev_priv - > hotplug_mode_update_property , 1 ) ;
drm_object_attach_property ( & connector - > base ,
dev - > mode_config . suggested_x_property , 0 ) ;
drm_object_attach_property ( & connector - > base ,
dev - > mode_config . suggested_y_property , 0 ) ;
2016-02-12 09:55:45 +01:00
if ( dev_priv - > implicit_placement_property )
drm_object_attach_property
( & connector - > base ,
dev_priv - > implicit_placement_property ,
sou - > base . is_implicit ) ;
2011-10-04 20:13:22 +02:00
return 0 ;
2017-03-23 11:28:11 -07:00
err_free_unregister :
drm_connector_unregister ( connector ) ;
err_free_encoder :
drm_encoder_cleanup ( encoder ) ;
err_free_connector :
drm_connector_cleanup ( connector ) ;
err_free :
kfree ( sou ) ;
return ret ;
2011-10-04 20:13:22 +02:00
}
2015-06-26 01:23:42 -07:00
int vmw_kms_sou_init_display ( struct vmw_private * dev_priv )
2011-10-04 20:13:22 +02:00
{
struct drm_device * dev = dev_priv - > dev ;
2011-10-17 11:59:44 +02:00
int i , ret ;
2011-10-04 20:13:22 +02:00
2012-11-09 12:26:13 +00:00
if ( ! ( dev_priv - > capabilities & SVGA_CAP_SCREEN_OBJECT_2 ) ) {
2011-10-04 20:13:22 +02:00
DRM_INFO ( " Not using screen objects, "
" missing cap SCREEN_OBJECT_2 \n " ) ;
return - ENOSYS ;
}
ret = - ENOMEM ;
2016-02-12 09:00:26 +01:00
dev_priv - > num_implicit = 0 ;
dev_priv - > implicit_fb = NULL ;
2011-10-04 20:13:22 +02:00
ret = drm_vblank_init ( dev , VMWGFX_NUM_DISPLAY_UNITS ) ;
if ( unlikely ( ret ! = 0 ) )
2016-02-12 09:00:26 +01:00
return ret ;
2011-10-04 20:13:22 +02:00
2016-02-12 09:55:45 +01:00
vmw_kms_create_implicit_placement_property ( dev_priv , false ) ;
2011-10-04 20:13:22 +02:00
for ( i = 0 ; i < VMWGFX_NUM_DISPLAY_UNITS ; + + i )
vmw_sou_init ( dev_priv , i ) ;
2015-06-26 01:23:42 -07:00
dev_priv - > active_display_unit = vmw_du_screen_object ;
DRM_INFO ( " Screen Objects Display Unit initialized \n " ) ;
2011-10-04 20:13:22 +02:00
return 0 ;
}
2018-06-19 15:02:16 +02:00
static int do_bo_define_gmrfb ( struct vmw_private * dev_priv ,
2015-06-26 01:23:42 -07:00
struct vmw_framebuffer * framebuffer )
2012-02-09 16:56:45 +01:00
{
2018-06-19 15:02:16 +02:00
struct vmw_buffer_object * buf =
container_of ( framebuffer , struct vmw_framebuffer_bo ,
2015-06-26 02:14:27 -07:00
base ) - > buffer ;
2016-12-14 23:31:35 +02:00
int depth = framebuffer - > base . format - > depth ;
2015-06-26 01:23:42 -07:00
struct {
uint32_t header ;
SVGAFifoCmdDefineGMRFB body ;
} * cmd ;
2012-02-09 16:56:45 +01:00
2015-06-26 01:23:42 -07:00
/* Emulate RGBA support, contrary to svga_reg.h this is not
* supported by hosts . This is only a problem if we are reading
* this value later and expecting what we uploaded back .
*/
if ( depth = = 32 )
depth = 24 ;
2012-02-09 16:56:45 +01:00
2015-06-26 02:14:27 -07:00
cmd = vmw_fifo_reserve ( dev_priv , sizeof ( * cmd ) ) ;
if ( ! cmd ) {
DRM_ERROR ( " Out of fifo space for dirty framebuffer command. \n " ) ;
2015-06-26 01:23:42 -07:00
return - ENOMEM ;
}
cmd - > header = SVGA_CMD_DEFINE_GMRFB ;
2016-12-14 23:32:20 +02:00
cmd - > body . format . bitsPerPixel = framebuffer - > base . format - > cpp [ 0 ] * 8 ;
2015-06-26 01:23:42 -07:00
cmd - > body . format . colorDepth = depth ;
cmd - > body . format . reserved = 0 ;
cmd - > body . bytesPerLine = framebuffer - > base . pitches [ 0 ] ;
2015-06-26 02:14:27 -07:00
/* Buffer is reserved in vram or GMR */
vmw_bo_get_guest_ptr ( & buf - > base , & cmd - > body . ptr ) ;
vmw_fifo_commit ( dev_priv , sizeof ( * cmd ) ) ;
return 0 ;
}
/**
* vmw_sou_surface_fifo_commit - Callback to fill in and submit a
* blit surface to screen command .
*
* @ dirty : The closure structure .
*
* Fills in the missing fields in the command , and translates the cliprects
* to match the destination bounding box encoded .
*/
static void vmw_sou_surface_fifo_commit ( struct vmw_kms_dirty * dirty )
{
struct vmw_kms_sou_surface_dirty * sdirty =
container_of ( dirty , typeof ( * sdirty ) , base ) ;
struct vmw_kms_sou_dirty_cmd * cmd = dirty - > cmd ;
s32 trans_x = dirty - > unit - > crtc . x - sdirty - > dst_x ;
s32 trans_y = dirty - > unit - > crtc . y - sdirty - > dst_y ;
size_t region_size = dirty - > num_hits * sizeof ( SVGASignedRect ) ;
SVGASignedRect * blit = ( SVGASignedRect * ) & cmd [ 1 ] ;
int i ;
2016-02-12 08:26:37 +01:00
if ( ! dirty - > num_hits ) {
vmw_fifo_commit ( dirty - > dev_priv , 0 ) ;
return ;
}
2015-06-26 02:14:27 -07:00
cmd - > header . id = SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN ;
cmd - > header . size = sizeof ( cmd - > body ) + region_size ;
/*
* Use the destination bounding box to specify destination - and
* source bounding regions .
*/
cmd - > body . destRect . left = sdirty - > left ;
cmd - > body . destRect . right = sdirty - > right ;
cmd - > body . destRect . top = sdirty - > top ;
cmd - > body . destRect . bottom = sdirty - > bottom ;
cmd - > body . srcRect . left = sdirty - > left + trans_x ;
cmd - > body . srcRect . right = sdirty - > right + trans_x ;
cmd - > body . srcRect . top = sdirty - > top + trans_y ;
cmd - > body . srcRect . bottom = sdirty - > bottom + trans_y ;
cmd - > body . srcImage . sid = sdirty - > sid ;
cmd - > body . destScreenId = dirty - > unit - > unit ;
/* Blits are relative to the destination rect. Translate. */
for ( i = 0 ; i < dirty - > num_hits ; + + i , + + blit ) {
blit - > left - = sdirty - > left ;
blit - > right - = sdirty - > left ;
blit - > top - = sdirty - > top ;
blit - > bottom - = sdirty - > top ;
}
vmw_fifo_commit ( dirty - > dev_priv , region_size + sizeof ( * cmd ) ) ;
sdirty - > left = sdirty - > top = S32_MAX ;
sdirty - > right = sdirty - > bottom = S32_MIN ;
}
/**
* vmw_sou_surface_clip - Callback to encode a blit surface to screen cliprect .
*
* @ dirty : The closure structure
*
* Encodes a SVGASignedRect cliprect and updates the bounding box of the
* BLIT_SURFACE_TO_SCREEN command .
*/
static void vmw_sou_surface_clip ( struct vmw_kms_dirty * dirty )
{
struct vmw_kms_sou_surface_dirty * sdirty =
container_of ( dirty , typeof ( * sdirty ) , base ) ;
struct vmw_kms_sou_dirty_cmd * cmd = dirty - > cmd ;
SVGASignedRect * blit = ( SVGASignedRect * ) & cmd [ 1 ] ;
/* Destination rect. */
blit + = dirty - > num_hits ;
blit - > left = dirty - > unit_x1 ;
blit - > top = dirty - > unit_y1 ;
blit - > right = dirty - > unit_x2 ;
blit - > bottom = dirty - > unit_y2 ;
/* Destination bounding box */
sdirty - > left = min_t ( s32 , sdirty - > left , dirty - > unit_x1 ) ;
sdirty - > top = min_t ( s32 , sdirty - > top , dirty - > unit_y1 ) ;
sdirty - > right = max_t ( s32 , sdirty - > right , dirty - > unit_x2 ) ;
sdirty - > bottom = max_t ( s32 , sdirty - > bottom , dirty - > unit_y2 ) ;
dirty - > num_hits + + ;
}
/**
* vmw_kms_sou_do_surface_dirty - Dirty part of a surface backed framebuffer
*
* @ dev_priv : Pointer to the device private structure .
* @ framebuffer : Pointer to the surface - buffer backed framebuffer .
* @ clips : Array of clip rects . Either @ clips or @ vclips must be NULL .
* @ vclips : Alternate array of clip rects . Either @ clips or @ vclips must
* be NULL .
* @ srf : Pointer to surface to blit from . If NULL , the surface attached
* to @ framebuffer will be used .
* @ dest_x : X coordinate offset to align @ srf with framebuffer coordinates .
* @ dest_y : Y coordinate offset to align @ srf with framebuffer coordinates .
* @ num_clips : Number of clip rects in @ clips .
* @ inc : Increment to use when looping over @ clips .
* @ out_fence : If non - NULL , will return a ref - counted pointer to a
* struct vmw_fence_obj . The returned fence pointer may be NULL in which
* case the device has already synchronized .
2018-01-16 08:24:17 +01:00
* @ crtc : If crtc is passed , perform surface dirty on that crtc only .
2015-06-26 02:14:27 -07:00
*
* Returns 0 on success , negative error code on failure . - ERESTARTSYS if
* interrupted .
*/
int vmw_kms_sou_do_surface_dirty ( struct vmw_private * dev_priv ,
struct vmw_framebuffer * framebuffer ,
struct drm_clip_rect * clips ,
struct drm_vmw_rect * vclips ,
struct vmw_resource * srf ,
s32 dest_x ,
s32 dest_y ,
unsigned num_clips , int inc ,
2018-01-16 08:24:17 +01:00
struct vmw_fence_obj * * out_fence ,
struct drm_crtc * crtc )
2015-06-26 02:14:27 -07:00
{
struct vmw_framebuffer_surface * vfbs =
container_of ( framebuffer , typeof ( * vfbs ) , base ) ;
struct vmw_kms_sou_surface_dirty sdirty ;
2018-09-26 15:34:50 +02:00
DECLARE_VAL_CONTEXT ( val_ctx , NULL , 0 ) ;
2015-06-26 02:14:27 -07:00
int ret ;
if ( ! srf )
srf = & vfbs - > surface - > res ;
2018-09-26 15:34:50 +02:00
ret = vmw_validation_add_resource ( & val_ctx , srf , 0 , NULL , NULL ) ;
2015-06-26 02:14:27 -07:00
if ( ret )
return ret ;
2018-09-26 15:34:50 +02:00
ret = vmw_validation_prepare ( & val_ctx , & dev_priv - > cmdbuf_mutex , true ) ;
if ( ret )
goto out_unref ;
2015-06-26 02:14:27 -07:00
sdirty . base . fifo_commit = vmw_sou_surface_fifo_commit ;
sdirty . base . clip = vmw_sou_surface_clip ;
sdirty . base . dev_priv = dev_priv ;
sdirty . base . fifo_reserve_size = sizeof ( struct vmw_kms_sou_dirty_cmd ) +
sizeof ( SVGASignedRect ) * num_clips ;
2018-01-16 08:24:17 +01:00
sdirty . base . crtc = crtc ;
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
sdirty . sid = srf - > id ;
sdirty . left = sdirty . top = S32_MAX ;
sdirty . right = sdirty . bottom = S32_MIN ;
sdirty . dst_x = dest_x ;
sdirty . dst_y = dest_y ;
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
ret = vmw_kms_helper_dirty ( dev_priv , framebuffer , clips , vclips ,
dest_x , dest_y , num_clips , inc ,
& sdirty . base ) ;
2018-09-26 15:34:50 +02:00
vmw_kms_helper_validation_finish ( dev_priv , NULL , & val_ctx , out_fence ,
NULL ) ;
2015-06-26 01:23:42 -07:00
return ret ;
2018-09-26 15:34:50 +02:00
out_unref :
vmw_validation_unref_lists ( & val_ctx ) ;
return ret ;
2012-02-09 16:56:45 +01:00
}
2015-06-26 02:14:27 -07:00
/**
2018-06-19 15:02:16 +02:00
* vmw_sou_bo_fifo_commit - Callback to submit a set of readback clips .
2015-06-26 02:14:27 -07:00
*
* @ dirty : The closure structure .
*
* Commits a previously built command buffer of readback clips .
*/
2018-06-19 15:02:16 +02:00
static void vmw_sou_bo_fifo_commit ( struct vmw_kms_dirty * dirty )
2015-06-26 02:14:27 -07:00
{
2016-02-12 08:26:37 +01:00
if ( ! dirty - > num_hits ) {
vmw_fifo_commit ( dirty - > dev_priv , 0 ) ;
return ;
}
2015-06-26 02:14:27 -07:00
vmw_fifo_commit ( dirty - > dev_priv ,
2018-06-19 15:02:16 +02:00
sizeof ( struct vmw_kms_sou_bo_blit ) *
2015-06-26 02:14:27 -07:00
dirty - > num_hits ) ;
}
/**
2018-06-19 15:02:16 +02:00
* vmw_sou_bo_clip - Callback to encode a readback cliprect .
2015-06-26 02:14:27 -07:00
*
* @ dirty : The closure structure
*
* Encodes a BLIT_GMRFB_TO_SCREEN cliprect .
*/
2018-06-19 15:02:16 +02:00
static void vmw_sou_bo_clip ( struct vmw_kms_dirty * dirty )
2015-06-26 02:14:27 -07:00
{
2018-06-19 15:02:16 +02:00
struct vmw_kms_sou_bo_blit * blit = dirty - > cmd ;
2015-06-26 02:14:27 -07:00
blit + = dirty - > num_hits ;
blit - > header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN ;
blit - > body . destScreenId = dirty - > unit - > unit ;
blit - > body . srcOrigin . x = dirty - > fb_x ;
blit - > body . srcOrigin . y = dirty - > fb_y ;
blit - > body . destRect . left = dirty - > unit_x1 ;
blit - > body . destRect . top = dirty - > unit_y1 ;
blit - > body . destRect . right = dirty - > unit_x2 ;
blit - > body . destRect . bottom = dirty - > unit_y2 ;
dirty - > num_hits + + ;
}
/**
2018-06-19 15:02:16 +02:00
* vmw_kms_do_bo_dirty - Dirty part of a buffer - object backed framebuffer
2015-06-26 02:14:27 -07:00
*
* @ dev_priv : Pointer to the device private structure .
2018-06-19 15:02:16 +02:00
* @ framebuffer : Pointer to the buffer - object backed framebuffer .
2015-06-26 02:14:27 -07:00
* @ clips : Array of clip rects .
2016-02-12 08:32:08 +01:00
* @ vclips : Alternate array of clip rects . Either @ clips or @ vclips must
* be NULL .
2015-06-26 02:14:27 -07:00
* @ num_clips : Number of clip rects in @ clips .
* @ increment : Increment to use when looping over @ clips .
* @ interruptible : Whether to perform waits interruptible if possible .
* @ out_fence : If non - NULL , will return a ref - counted pointer to a
* struct vmw_fence_obj . The returned fence pointer may be NULL in which
* case the device has already synchronized .
2018-06-19 15:02:16 +02:00
* @ crtc : If crtc is passed , perform bo dirty on that crtc only .
2015-06-26 02:14:27 -07:00
*
* Returns 0 on success , negative error code on failure . - ERESTARTSYS if
* interrupted .
*/
2018-06-19 15:02:16 +02:00
int vmw_kms_sou_do_bo_dirty ( struct vmw_private * dev_priv ,
2015-06-26 01:23:42 -07:00
struct vmw_framebuffer * framebuffer ,
struct drm_clip_rect * clips ,
2016-02-12 08:32:08 +01:00
struct drm_vmw_rect * vclips ,
2015-06-26 01:23:42 -07:00
unsigned num_clips , int increment ,
2015-06-26 02:14:27 -07:00
bool interruptible ,
2018-01-16 08:24:17 +01:00
struct vmw_fence_obj * * out_fence ,
struct drm_crtc * crtc )
2012-02-09 16:56:45 +01:00
{
2018-06-19 15:02:16 +02:00
struct vmw_buffer_object * buf =
container_of ( framebuffer , struct vmw_framebuffer_bo ,
2015-06-26 02:14:27 -07:00
base ) - > buffer ;
struct vmw_kms_dirty dirty ;
2018-09-26 15:34:50 +02:00
DECLARE_VAL_CONTEXT ( val_ctx , NULL , 0 ) ;
2015-06-26 02:14:27 -07:00
int ret ;
2012-02-09 16:56:45 +01:00
2018-09-26 15:34:50 +02:00
ret = vmw_validation_add_bo ( & val_ctx , buf , false , false ) ;
2015-06-26 02:14:27 -07:00
if ( ret )
return ret ;
2012-02-09 16:56:45 +01:00
2018-09-26 15:34:50 +02:00
ret = vmw_validation_prepare ( & val_ctx , NULL , interruptible ) ;
if ( ret )
goto out_unref ;
2018-06-19 15:02:16 +02:00
ret = do_bo_define_gmrfb ( dev_priv , framebuffer ) ;
2015-06-26 01:23:42 -07:00
if ( unlikely ( ret ! = 0 ) )
2015-06-26 02:14:27 -07:00
goto out_revert ;
2015-06-26 01:23:42 -07:00
2018-01-16 08:24:17 +01:00
dirty . crtc = crtc ;
2018-06-19 15:02:16 +02:00
dirty . fifo_commit = vmw_sou_bo_fifo_commit ;
dirty . clip = vmw_sou_bo_clip ;
dirty . fifo_reserve_size = sizeof ( struct vmw_kms_sou_bo_blit ) *
2015-06-26 02:14:27 -07:00
num_clips ;
2016-02-12 08:32:08 +01:00
ret = vmw_kms_helper_dirty ( dev_priv , framebuffer , clips , vclips ,
2015-06-26 02:14:27 -07:00
0 , 0 , num_clips , increment , & dirty ) ;
2018-09-26 15:34:50 +02:00
vmw_kms_helper_validation_finish ( dev_priv , NULL , & val_ctx , out_fence ,
NULL ) ;
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
return ret ;
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
out_revert :
2018-09-26 15:34:50 +02:00
vmw_validation_revert ( & val_ctx ) ;
out_unref :
vmw_validation_unref_lists ( & val_ctx ) ;
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
return ret ;
}
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
/**
* vmw_sou_readback_fifo_commit - Callback to submit a set of readback clips .
*
* @ dirty : The closure structure .
*
* Commits a previously built command buffer of readback clips .
*/
static void vmw_sou_readback_fifo_commit ( struct vmw_kms_dirty * dirty )
{
2016-02-12 08:26:37 +01:00
if ( ! dirty - > num_hits ) {
vmw_fifo_commit ( dirty - > dev_priv , 0 ) ;
return ;
}
2015-06-26 02:14:27 -07:00
vmw_fifo_commit ( dirty - > dev_priv ,
sizeof ( struct vmw_kms_sou_readback_blit ) *
dirty - > num_hits ) ;
2012-02-09 16:56:45 +01:00
}
2015-06-26 01:23:42 -07:00
2015-06-26 02:14:27 -07:00
/**
* vmw_sou_readback_clip - Callback to encode a readback cliprect .
*
* @ dirty : The closure structure
*
* Encodes a BLIT_SCREEN_TO_GMRFB cliprect .
*/
static void vmw_sou_readback_clip ( struct vmw_kms_dirty * dirty )
{
struct vmw_kms_sou_readback_blit * blit = dirty - > cmd ;
blit + = dirty - > num_hits ;
blit - > header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB ;
blit - > body . srcScreenId = dirty - > unit - > unit ;
blit - > body . destOrigin . x = dirty - > fb_x ;
blit - > body . destOrigin . y = dirty - > fb_y ;
blit - > body . srcRect . left = dirty - > unit_x1 ;
blit - > body . srcRect . top = dirty - > unit_y1 ;
blit - > body . srcRect . right = dirty - > unit_x2 ;
blit - > body . srcRect . bottom = dirty - > unit_y2 ;
dirty - > num_hits + + ;
}
/**
* vmw_kms_sou_readback - Perform a readback from the screen object system to
2018-06-19 15:02:16 +02:00
* a buffer - object backed framebuffer .
2015-06-26 02:14:27 -07:00
*
* @ dev_priv : Pointer to the device private structure .
* @ file_priv : Pointer to a struct drm_file identifying the caller .
* Must be set to NULL if @ user_fence_rep is NULL .
2018-06-19 15:02:16 +02:00
* @ vfb : Pointer to the buffer - object backed framebuffer .
2015-06-26 02:14:27 -07:00
* @ user_fence_rep : User - space provided structure for fence information .
* Must be set to non - NULL if @ file_priv is non - NULL .
* @ vclips : Array of clip rects .
* @ num_clips : Number of clip rects in @ vclips .
2018-01-16 08:24:17 +01:00
* @ crtc : If crtc is passed , readback on that crtc only .
2015-06-26 02:14:27 -07:00
*
* Returns 0 on success , negative error code on failure . - ERESTARTSYS if
* interrupted .
*/
int vmw_kms_sou_readback ( struct vmw_private * dev_priv ,
struct drm_file * file_priv ,
struct vmw_framebuffer * vfb ,
struct drm_vmw_fence_rep __user * user_fence_rep ,
struct drm_vmw_rect * vclips ,
2018-01-16 08:24:17 +01:00
uint32_t num_clips ,
struct drm_crtc * crtc )
2015-06-26 02:14:27 -07:00
{
2018-06-19 15:02:16 +02:00
struct vmw_buffer_object * buf =
container_of ( vfb , struct vmw_framebuffer_bo , base ) - > buffer ;
2015-06-26 02:14:27 -07:00
struct vmw_kms_dirty dirty ;
2018-09-26 15:34:50 +02:00
DECLARE_VAL_CONTEXT ( val_ctx , NULL , 0 ) ;
2015-06-26 02:14:27 -07:00
int ret ;
2018-09-26 15:34:50 +02:00
ret = vmw_validation_add_bo ( & val_ctx , buf , false , false ) ;
2015-06-26 02:14:27 -07:00
if ( ret )
return ret ;
2018-09-26 15:34:50 +02:00
ret = vmw_validation_prepare ( & val_ctx , NULL , true ) ;
if ( ret )
goto out_unref ;
2018-06-19 15:02:16 +02:00
ret = do_bo_define_gmrfb ( dev_priv , vfb ) ;
2015-06-26 02:14:27 -07:00
if ( unlikely ( ret ! = 0 ) )
goto out_revert ;
2018-01-16 08:24:17 +01:00
dirty . crtc = crtc ;
2015-06-26 02:14:27 -07:00
dirty . fifo_commit = vmw_sou_readback_fifo_commit ;
dirty . clip = vmw_sou_readback_clip ;
dirty . fifo_reserve_size = sizeof ( struct vmw_kms_sou_readback_blit ) *
num_clips ;
ret = vmw_kms_helper_dirty ( dev_priv , vfb , NULL , vclips ,
0 , 0 , num_clips , 1 , & dirty ) ;
2018-09-26 15:34:50 +02:00
vmw_kms_helper_validation_finish ( dev_priv , file_priv , & val_ctx , NULL ,
user_fence_rep ) ;
2015-06-26 02:14:27 -07:00
return ret ;
out_revert :
2018-09-26 15:34:50 +02:00
vmw_validation_revert ( & val_ctx ) ;
out_unref :
vmw_validation_unref_lists ( & val_ctx ) ;
2015-06-26 02:14:27 -07:00
return ret ;
}