2011-10-04 20:13:22 +02:00
/**************************************************************************
*
2015-07-29 12:38:02 -07:00
* Copyright © 2011 - 2015 VMware , Inc . , Palo Alto , CA . , USA
2011-10-04 20:13:22 +02:00
* All Rights Reserved .
*
* 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>
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 ;
} ;
struct vmw_kms_sou_dmabuf_blit {
uint32 header ;
SVGAFifoCmdBlitGMRFBToScreen body ;
} ;
struct vmw_kms_sou_dirty_cmd {
SVGA3dCmdHeader header ;
SVGA3dCmdBlitSurfaceToScreen body ;
} ;
/*
* Other structs .
*/
2011-10-04 20:13:22 +02:00
struct vmw_screen_object_display {
2011-11-02 09:43:11 +01:00
unsigned num_implicit ;
2011-10-04 20:13:22 +02:00
2011-11-02 09:43:11 +01:00
struct vmw_framebuffer * implicit_fb ;
2015-06-26 02:14:27 -07:00
SVGAFifoCmdDefineGMRFB cur ;
struct vmw_dma_buffer * pinned_gmrfb ;
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 */
struct vmw_dma_buffer * buffer ; /**< Backing store buffer */
bool defined ;
2011-11-02 09:43:11 +01:00
bool active_implicit ;
2011-10-04 20:13:22 +02:00
} ;
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 ) ) ;
}
2011-11-02 09:43:09 +01:00
static void vmw_sou_del_active ( struct vmw_private * vmw_priv ,
2015-06-26 01:23:42 -07:00
struct vmw_screen_object_unit * sou )
2011-10-04 20:13:22 +02:00
{
struct vmw_screen_object_display * ld = vmw_priv - > sou_priv ;
2011-11-02 09:43:11 +01:00
if ( sou - > active_implicit ) {
if ( - - ( ld - > num_implicit ) = = 0 )
ld - > implicit_fb = NULL ;
sou - > active_implicit = false ;
2011-11-02 09:43:09 +01:00
}
2011-10-04 20:13:22 +02:00
}
2011-11-02 09:43:09 +01:00
static void vmw_sou_add_active ( struct vmw_private * vmw_priv ,
2015-06-26 01:23:42 -07:00
struct vmw_screen_object_unit * sou ,
struct vmw_framebuffer * vfb )
2011-10-04 20:13:22 +02:00
{
struct vmw_screen_object_display * ld = vmw_priv - > sou_priv ;
2011-11-02 09:43:11 +01:00
BUG_ON ( ! ld - > num_implicit & & ld - > implicit_fb ) ;
2011-10-04 20:13:22 +02:00
2011-11-02 09:43:11 +01:00
if ( ! sou - > active_implicit & & sou - > base . is_implicit ) {
ld - > implicit_fb = vfb ;
sou - > active_implicit = true ;
ld - > num_implicit + + ;
2011-10-04 20:13:22 +02:00
}
}
/**
* 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 ,
uint32_t x , uint32_t y ,
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 ;
2011-11-02 09:43:11 +01:00
if ( sou - > base . is_implicit ) {
cmd - > obj . root . x = x ;
cmd - > obj . root . y = y ;
} else {
cmd - > obj . root . x = sou - > base . gui_x ;
cmd - > obj . root . y = sou - > base . gui_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 ;
}
/**
* Free the backing store .
*/
static void vmw_sou_backing_free ( struct vmw_private * dev_priv ,
struct vmw_screen_object_unit * sou )
{
2015-06-26 02:14:27 -07:00
vmw_dmabuf_unreference ( & sou - > buffer ) ;
2011-10-04 20:13:22 +02:00
sou - > buffer_size = 0 ;
}
/**
* Allocate the backing store for the buffer .
*/
static int vmw_sou_backing_alloc ( struct vmw_private * dev_priv ,
struct vmw_screen_object_unit * sou ,
unsigned long size )
{
int ret ;
if ( sou - > buffer_size = = size )
return 0 ;
if ( sou - > buffer )
vmw_sou_backing_free ( dev_priv , sou ) ;
sou - > buffer = kzalloc ( sizeof ( * sou - > buffer ) , GFP_KERNEL ) ;
if ( unlikely ( sou - > buffer = = NULL ) )
return - ENOMEM ;
/* 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 ) ;
ret = vmw_dmabuf_init ( dev_priv , sou - > buffer , size ,
& vmw_vram_ne_placement ,
false , & vmw_dmabuf_bo_free ) ;
vmw_overlay_resume_all ( dev_priv ) ;
if ( unlikely ( ret ! = 0 ) )
sou - > buffer = NULL ; /* vmw_dmabuf_init frees on error */
else
sou - > buffer_size = size ;
return ret ;
}
static int vmw_sou_crtc_set_config ( struct drm_mode_set * set )
{
struct vmw_private * dev_priv ;
struct vmw_screen_object_unit * sou ;
struct drm_connector * connector ;
struct drm_display_mode * mode ;
struct drm_encoder * encoder ;
struct vmw_framebuffer * vfb ;
struct drm_framebuffer * fb ;
struct drm_crtc * crtc ;
int ret = 0 ;
if ( ! set )
return - EINVAL ;
if ( ! set - > crtc )
return - EINVAL ;
/* get the sou */
crtc = set - > crtc ;
sou = vmw_crtc_to_sou ( crtc ) ;
vfb = set - > fb ? vmw_framebuffer_to_vfb ( set - > fb ) : NULL ;
dev_priv = vmw_priv ( crtc - > dev ) ;
if ( set - > num_connectors > 1 ) {
2015-06-26 01:23:42 -07:00
DRM_ERROR ( " Too many connectors \n " ) ;
2011-10-04 20:13:22 +02:00
return - EINVAL ;
}
if ( set - > num_connectors = = 1 & &
set - > connectors [ 0 ] ! = & sou - > base . connector ) {
2015-06-26 01:23:42 -07:00
DRM_ERROR ( " Connector doesn't match %p %p \n " ,
2011-10-04 20:13:22 +02:00
set - > connectors [ 0 ] , & sou - > base . connector ) ;
return - EINVAL ;
}
/* sou only supports one fb active at the time */
2011-11-02 09:43:11 +01:00
if ( sou - > base . is_implicit & &
dev_priv - > sou_priv - > implicit_fb & & vfb & &
! ( dev_priv - > sou_priv - > num_implicit = = 1 & &
sou - > active_implicit ) & &
dev_priv - > sou_priv - > implicit_fb ! = vfb ) {
2011-10-04 20:13:22 +02:00
DRM_ERROR ( " Multiple framebuffers not supported \n " ) ;
return - EINVAL ;
}
/* since they always map one to one these are safe */
connector = & sou - > base . connector ;
encoder = & sou - > base . encoder ;
/* should we turn the crtc off */
if ( set - > num_connectors = = 0 | | ! set - > mode | | ! set - > fb ) {
ret = vmw_sou_fifo_destroy ( dev_priv , sou ) ;
/* the hardware has hung don't do anything more */
if ( unlikely ( ret ! = 0 ) )
return ret ;
connector - > encoder = NULL ;
encoder - > crtc = NULL ;
2014-04-01 15:22:40 -07:00
crtc - > primary - > fb = NULL ;
2011-10-04 20:13:22 +02:00
crtc - > x = 0 ;
crtc - > y = 0 ;
2013-11-14 03:11:10 -08:00
crtc - > enabled = false ;
2011-10-04 20:13:22 +02:00
vmw_sou_del_active ( dev_priv , sou ) ;
vmw_sou_backing_free ( dev_priv , sou ) ;
return 0 ;
}
/* we now know we want to set a mode */
mode = set - > mode ;
fb = set - > fb ;
if ( set - > x + mode - > hdisplay > fb - > width | |
set - > y + mode - > vdisplay > fb - > height ) {
DRM_ERROR ( " set outside of framebuffer \n " ) ;
return - EINVAL ;
}
2015-06-25 10:47:43 -07:00
vmw_svga_enable ( dev_priv ) ;
2011-10-04 20:13:22 +02:00
if ( mode - > hdisplay ! = crtc - > mode . hdisplay | |
mode - > vdisplay ! = crtc - > mode . vdisplay ) {
/* no need to check if depth is different, because backing
* store depth is forced to 4 by the device .
*/
ret = vmw_sou_fifo_destroy ( dev_priv , sou ) ;
/* the hardware has hung don't do anything more */
if ( unlikely ( ret ! = 0 ) )
return ret ;
vmw_sou_backing_free ( dev_priv , sou ) ;
}
if ( ! sou - > buffer ) {
/* forced to depth 4 by the device */
size_t size = mode - > hdisplay * mode - > vdisplay * 4 ;
ret = vmw_sou_backing_alloc ( dev_priv , sou , size ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ;
}
ret = vmw_sou_fifo_create ( dev_priv , sou , set - > x , set - > y , mode ) ;
if ( unlikely ( ret ! = 0 ) ) {
/*
* We are in a bit of a situation here , the hardware has
* hung and we may or may not have a buffer hanging of
* the screen object , best thing to do is not do anything
* if we where defined , if not just turn the crtc of .
* Not what userspace wants but it needs to htfu .
*/
if ( sou - > defined )
return ret ;
connector - > encoder = NULL ;
encoder - > crtc = NULL ;
2014-04-01 15:22:40 -07:00
crtc - > primary - > fb = NULL ;
2011-10-04 20:13:22 +02:00
crtc - > x = 0 ;
crtc - > y = 0 ;
2013-11-14 03:11:10 -08:00
crtc - > enabled = false ;
2011-10-04 20:13:22 +02:00
return ret ;
}
vmw_sou_add_active ( dev_priv , sou , vfb ) ;
connector - > encoder = encoder ;
encoder - > crtc = crtc ;
crtc - > mode = * mode ;
2014-04-01 15:22:40 -07:00
crtc - > primary - > fb = fb ;
2011-10-04 20:13:22 +02:00
crtc - > x = set - > x ;
crtc - > y = set - > y ;
2013-11-14 03:11:10 -08:00
crtc - > enabled = true ;
2011-10-04 20:13:22 +02:00
return 0 ;
}
2015-06-26 01:23:42 -07:00
/**
* Returns if this unit can be page flipped .
* Must be called with the mode_config mutex held .
*/
static bool vmw_sou_screen_object_flippable ( struct vmw_private * dev_priv ,
struct drm_crtc * crtc )
{
struct vmw_screen_object_unit * sou = vmw_crtc_to_sou ( crtc ) ;
if ( ! sou - > base . is_implicit )
return true ;
if ( dev_priv - > sou_priv - > num_implicit ! = 1 )
return false ;
return true ;
}
/**
* Update the implicit fb to the current fb of this crtc .
* Must be called with the mode_config mutex held .
*/
2015-04-02 02:39:45 -07:00
static void vmw_sou_update_implicit_fb ( struct vmw_private * dev_priv ,
struct drm_crtc * crtc )
2015-06-26 01:23:42 -07:00
{
struct vmw_screen_object_unit * sou = vmw_crtc_to_sou ( crtc ) ;
BUG_ON ( ! sou - > base . is_implicit ) ;
dev_priv - > sou_priv - > implicit_fb =
vmw_framebuffer_to_vfb ( sou - > base . crtc . primary - > fb ) ;
}
static int vmw_sou_crtc_page_flip ( struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
struct drm_pending_vblank_event * event ,
uint32_t flags )
{
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
struct drm_framebuffer * old_fb = crtc - > primary - > fb ;
struct vmw_framebuffer * vfb = vmw_framebuffer_to_vfb ( fb ) ;
struct vmw_fence_obj * fence = NULL ;
struct drm_clip_rect clips ;
int ret ;
/* require ScreenObject support for page flipping */
if ( ! dev_priv - > sou_priv )
return - ENOSYS ;
if ( ! vmw_sou_screen_object_flippable ( dev_priv , crtc ) )
return - EINVAL ;
crtc - > primary - > fb = fb ;
/* do a full screen dirty update */
clips . x1 = clips . y1 = 0 ;
clips . x2 = fb - > width ;
clips . y2 = fb - > height ;
if ( vfb - > dmabuf )
2015-06-26 02:14:27 -07:00
ret = vmw_kms_sou_do_dmabuf_dirty ( dev_priv , vfb ,
& clips , 1 , 1 ,
true , & fence ) ;
2015-06-26 01:23:42 -07:00
else
2015-06-26 02:14:27 -07:00
ret = vmw_kms_sou_do_surface_dirty ( dev_priv , vfb ,
& clips , NULL , NULL ,
0 , 0 , 1 , 1 , & fence ) ;
2015-06-26 01:23:42 -07:00
if ( ret ! = 0 )
goto out_no_fence ;
if ( ! fence ) {
ret = - EINVAL ;
goto out_no_fence ;
}
2015-06-26 02:14:27 -07:00
if ( event ) {
struct drm_file * file_priv = event - > base . file_priv ;
ret = vmw_event_fence_action_queue ( file_priv , fence ,
& event - > base ,
& event - > event . tv_sec ,
& event - > event . tv_usec ,
true ) ;
}
2015-06-26 01:23:42 -07:00
/*
* No need to hold on to this now . The only cleanup
* we need to do if we fail is unref the fence .
*/
vmw_fence_obj_unreference ( & fence ) ;
if ( vmw_crtc_to_du ( crtc ) - > is_implicit )
vmw_sou_update_implicit_fb ( dev_priv , crtc ) ;
return ret ;
out_no_fence :
crtc - > primary - > fb = old_fb ;
return ret ;
}
2011-10-04 20:13:22 +02:00
static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
. cursor_set = vmw_du_crtc_cursor_set ,
. cursor_move = vmw_du_crtc_cursor_move ,
. gamma_set = vmw_du_crtc_gamma_set ,
. destroy = vmw_sou_crtc_destroy ,
. set_config = vmw_sou_crtc_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 ) ) ;
}
static struct drm_encoder_funcs vmw_screen_object_encoder_funcs = {
. 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-06-26 01:23:42 -07:00
static struct drm_connector_funcs vmw_sou_connector_funcs = {
2011-10-04 20:13:22 +02:00
. dpms = vmw_du_connector_dpms ,
. set_property = vmw_du_connector_set_property ,
. destroy = vmw_sou_connector_destroy ,
} ;
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 ;
struct drm_crtc * crtc ;
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 ;
2011-11-02 09:43:11 +01:00
sou - > 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 ;
2011-11-02 09:43:11 +01:00
sou - > base . is_implicit = true ;
2011-10-04 20:13:22 +02:00
2015-06-26 01:23:42 -07:00
drm_connector_init ( dev , connector , & vmw_sou_connector_funcs ,
2011-10-22 10:36:20 +02:00
DRM_MODE_CONNECTOR_VIRTUAL ) ;
2011-10-04 20:13:22 +02:00
connector - > status = vmw_du_connector_detect ( connector , true ) ;
drm_encoder_init ( dev , encoder , & vmw_screen_object_encoder_funcs ,
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
DRM_MODE_ENCODER_VIRTUAL , NULL ) ;
2011-10-04 20:13:22 +02:00
drm_mode_connector_attach_encoder ( connector , encoder ) ;
encoder - > possible_crtcs = ( 1 < < unit ) ;
encoder - > possible_clones = 0 ;
2014-05-29 16:57:41 +01:00
( void ) drm_connector_register ( connector ) ;
2013-12-02 06:04:38 -08:00
2011-10-04 20:13:22 +02:00
drm_crtc_init ( dev , crtc , & vmw_screen_object_crtc_funcs ) ;
drm_mode_crtc_set_gamma_size ( crtc , 256 ) ;
2012-10-11 20:47:14 -05:00
drm_object_attach_property ( & connector - > base ,
2011-10-04 20:13:22 +02:00
dev - > mode_config . dirty_info_property ,
1 ) ;
return 0 ;
}
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
if ( dev_priv - > sou_priv ) {
DRM_INFO ( " sou system already on \n " ) ;
return - EINVAL ;
}
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 ;
dev_priv - > sou_priv = kmalloc ( sizeof ( * dev_priv - > sou_priv ) , GFP_KERNEL ) ;
if ( unlikely ( ! dev_priv - > sou_priv ) )
goto err_no_mem ;
2011-11-02 09:43:11 +01:00
dev_priv - > sou_priv - > num_implicit = 0 ;
dev_priv - > sou_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 ) )
goto err_free ;
2011-10-17 11:59:44 +02:00
ret = drm_mode_create_dirty_info_property ( dev ) ;
2011-10-04 20:13:22 +02:00
if ( unlikely ( ret ! = 0 ) )
goto err_vblank_cleanup ;
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 ;
err_vblank_cleanup :
drm_vblank_cleanup ( dev ) ;
err_free :
kfree ( dev_priv - > sou_priv ) ;
2011-10-17 11:59:43 +02:00
dev_priv - > sou_priv = NULL ;
2011-10-04 20:13:22 +02:00
err_no_mem :
return ret ;
}
2015-06-26 01:23:42 -07:00
int vmw_kms_sou_close_display ( struct vmw_private * dev_priv )
2011-10-04 20:13:22 +02:00
{
struct drm_device * dev = dev_priv - > dev ;
if ( ! dev_priv - > sou_priv )
return - ENOSYS ;
2011-10-17 11:59:43 +02:00
drm_vblank_cleanup ( dev ) ;
2011-10-04 20:13:22 +02:00
kfree ( dev_priv - > sou_priv ) ;
return 0 ;
}
2012-02-09 16:56:45 +01:00
2015-06-26 02:14:27 -07:00
static int do_dmabuf_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
{
2015-06-26 02:14:27 -07:00
struct vmw_dma_buffer * buf =
container_of ( framebuffer , struct vmw_framebuffer_dmabuf ,
base ) - > buffer ;
2015-06-26 01:23:42 -07:00
int depth = framebuffer - > base . depth ;
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 ;
cmd - > body . format . bitsPerPixel = framebuffer - > base . bits_per_pixel ;
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 ;
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 .
*
* 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 ,
struct vmw_fence_obj * * out_fence )
{
struct vmw_framebuffer_surface * vfbs =
container_of ( framebuffer , typeof ( * vfbs ) , base ) ;
struct vmw_kms_sou_surface_dirty sdirty ;
int ret ;
if ( ! srf )
srf = & vfbs - > surface - > res ;
ret = vmw_kms_helper_resource_prepare ( srf , true ) ;
if ( ret )
return ret ;
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 ;
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 ) ;
vmw_kms_helper_resource_finish ( srf , out_fence ) ;
2015-06-26 01:23:42 -07:00
return ret ;
2012-02-09 16:56:45 +01:00
}
2015-06-26 02:14:27 -07:00
/**
* vmw_sou_dmabuf_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_dmabuf_fifo_commit ( struct vmw_kms_dirty * dirty )
{
vmw_fifo_commit ( dirty - > dev_priv ,
sizeof ( struct vmw_kms_sou_dmabuf_blit ) *
dirty - > num_hits ) ;
}
/**
* vmw_sou_dmabuf_clip - Callback to encode a readback cliprect .
*
* @ dirty : The closure structure
*
* Encodes a BLIT_GMRFB_TO_SCREEN cliprect .
*/
static void vmw_sou_dmabuf_clip ( struct vmw_kms_dirty * dirty )
{
struct vmw_kms_sou_dmabuf_blit * blit = dirty - > cmd ;
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 + + ;
}
/**
* vmw_kms_do_dmabuf_dirty - Dirty part of a dma - buffer backed framebuffer
*
* @ dev_priv : Pointer to the device private structure .
* @ framebuffer : Pointer to the dma - buffer backed framebuffer .
* @ clips : Array of clip rects .
* @ 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 .
*
* Returns 0 on success , negative error code on failure . - ERESTARTSYS if
* interrupted .
*/
int vmw_kms_sou_do_dmabuf_dirty ( struct vmw_private * dev_priv ,
2015-06-26 01:23:42 -07:00
struct vmw_framebuffer * framebuffer ,
struct drm_clip_rect * clips ,
unsigned num_clips , int increment ,
2015-06-26 02:14:27 -07:00
bool interruptible ,
2015-06-26 01:23:42 -07:00
struct vmw_fence_obj * * out_fence )
2012-02-09 16:56:45 +01:00
{
2015-06-26 02:14:27 -07:00
struct vmw_dma_buffer * buf =
container_of ( framebuffer , struct vmw_framebuffer_dmabuf ,
base ) - > buffer ;
struct vmw_kms_dirty dirty ;
int ret ;
2012-02-09 16:56:45 +01:00
2015-06-26 02:14:27 -07:00
ret = vmw_kms_helper_buffer_prepare ( dev_priv , buf , interruptible ,
false ) ;
if ( ret )
return ret ;
2012-02-09 16:56:45 +01:00
2015-06-26 02:14:27 -07:00
ret = do_dmabuf_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
2015-06-26 02:14:27 -07:00
dirty . fifo_commit = vmw_sou_dmabuf_fifo_commit ;
dirty . clip = vmw_sou_dmabuf_clip ;
dirty . fifo_reserve_size = sizeof ( struct vmw_kms_sou_dmabuf_blit ) *
num_clips ;
ret = vmw_kms_helper_dirty ( dev_priv , framebuffer , clips , NULL ,
0 , 0 , num_clips , increment , & dirty ) ;
vmw_kms_helper_buffer_finish ( dev_priv , NULL , buf , 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 :
vmw_kms_helper_buffer_revert ( buf ) ;
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 )
{
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
* a dma - buffer backed framebuffer .
*
* @ 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 .
* @ vfb : Pointer to the dma - buffer backed framebuffer .
* @ 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 .
*
* 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 ,
uint32_t num_clips )
{
struct vmw_dma_buffer * buf =
container_of ( vfb , struct vmw_framebuffer_dmabuf , base ) - > buffer ;
struct vmw_kms_dirty dirty ;
int ret ;
ret = vmw_kms_helper_buffer_prepare ( dev_priv , buf , true , false ) ;
if ( ret )
return ret ;
ret = do_dmabuf_define_gmrfb ( dev_priv , vfb ) ;
if ( unlikely ( ret ! = 0 ) )
goto out_revert ;
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 ) ;
vmw_kms_helper_buffer_finish ( dev_priv , file_priv , buf , NULL ,
user_fence_rep ) ;
return ret ;
out_revert :
vmw_kms_helper_buffer_revert ( buf ) ;
return ret ;
}