2009-12-10 00:19:58 +00:00
/**************************************************************************
*
* Copyright © 2009 VMware , Inc . , Palo Alto , CA . , USA
* 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"
2011-10-04 20:13:22 +02:00
2009-12-10 00:19:58 +00:00
/* Might need a hrtimer here? */
# define VMWGFX_PRESENT_RATE ((HZ / 60 > 0) ? HZ / 60 : 1)
void vmw_display_unit_cleanup ( struct vmw_display_unit * du )
{
if ( du - > cursor_surface )
vmw_surface_unreference ( & du - > cursor_surface ) ;
if ( du - > cursor_dmabuf )
vmw_dmabuf_unreference ( & du - > cursor_dmabuf ) ;
drm_crtc_cleanup ( & du - > crtc ) ;
drm_encoder_cleanup ( & du - > encoder ) ;
drm_connector_cleanup ( & du - > connector ) ;
}
/*
* Display Unit Cursor functions
*/
int vmw_cursor_update_image ( struct vmw_private * dev_priv ,
u32 * image , u32 width , u32 height ,
u32 hotspotX , u32 hotspotY )
{
struct {
u32 cmd ;
SVGAFifoCmdDefineAlphaCursor cursor ;
} * cmd ;
u32 image_size = width * height * 4 ;
u32 cmd_size = sizeof ( * cmd ) + image_size ;
if ( ! image )
return - EINVAL ;
cmd = vmw_fifo_reserve ( dev_priv , cmd_size ) ;
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Fifo reserve failed. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , sizeof ( * cmd ) ) ;
memcpy ( & cmd [ 1 ] , image , image_size ) ;
cmd - > cmd = cpu_to_le32 ( SVGA_CMD_DEFINE_ALPHA_CURSOR ) ;
cmd - > cursor . id = cpu_to_le32 ( 0 ) ;
cmd - > cursor . width = cpu_to_le32 ( width ) ;
cmd - > cursor . height = cpu_to_le32 ( height ) ;
cmd - > cursor . hotspotX = cpu_to_le32 ( hotspotX ) ;
cmd - > cursor . hotspotY = cpu_to_le32 ( hotspotY ) ;
vmw_fifo_commit ( dev_priv , cmd_size ) ;
return 0 ;
}
void vmw_cursor_update_position ( struct vmw_private * dev_priv ,
bool show , int x , int y )
{
__le32 __iomem * fifo_mem = dev_priv - > mmio_virt ;
uint32_t count ;
iowrite32 ( show ? 1 : 0 , fifo_mem + SVGA_FIFO_CURSOR_ON ) ;
iowrite32 ( x , fifo_mem + SVGA_FIFO_CURSOR_X ) ;
iowrite32 ( y , fifo_mem + SVGA_FIFO_CURSOR_Y ) ;
count = ioread32 ( fifo_mem + SVGA_FIFO_CURSOR_COUNT ) ;
iowrite32 ( + + count , fifo_mem + SVGA_FIFO_CURSOR_COUNT ) ;
}
int vmw_du_crtc_cursor_set ( struct drm_crtc * crtc , struct drm_file * file_priv ,
uint32_t handle , uint32_t width , uint32_t height )
{
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
struct ttm_object_file * tfile = vmw_fpriv ( file_priv ) - > tfile ;
struct vmw_display_unit * du = vmw_crtc_to_du ( crtc ) ;
struct vmw_surface * surface = NULL ;
struct vmw_dma_buffer * dmabuf = NULL ;
int ret ;
if ( handle ) {
2009-12-22 16:53:41 +01:00
ret = vmw_user_surface_lookup_handle ( dev_priv , tfile ,
handle , & surface ) ;
2009-12-10 00:19:58 +00:00
if ( ! ret ) {
if ( ! surface - > snooper . image ) {
DRM_ERROR ( " surface not suitable for cursor \n " ) ;
return - EINVAL ;
}
} else {
ret = vmw_user_dmabuf_lookup ( tfile ,
handle , & dmabuf ) ;
if ( ret ) {
DRM_ERROR ( " failed to find surface or dmabuf: %i \n " , ret ) ;
return - EINVAL ;
}
}
}
/* takedown old cursor */
if ( du - > cursor_surface ) {
du - > cursor_surface - > snooper . crtc = NULL ;
vmw_surface_unreference ( & du - > cursor_surface ) ;
}
if ( du - > cursor_dmabuf )
vmw_dmabuf_unreference ( & du - > cursor_dmabuf ) ;
/* setup new image */
if ( surface ) {
/* vmw_user_surface_lookup takes one reference */
du - > cursor_surface = surface ;
du - > cursor_surface - > snooper . crtc = crtc ;
du - > cursor_age = du - > cursor_surface - > snooper . age ;
vmw_cursor_update_image ( dev_priv , surface - > snooper . image ,
64 , 64 , du - > hotspot_x , du - > hotspot_y ) ;
} else if ( dmabuf ) {
struct ttm_bo_kmap_obj map ;
unsigned long kmap_offset ;
unsigned long kmap_num ;
void * virtual ;
bool dummy ;
/* vmw_user_surface_lookup takes one reference */
du - > cursor_dmabuf = dmabuf ;
kmap_offset = 0 ;
kmap_num = ( 64 * 64 * 4 ) > > PAGE_SHIFT ;
ret = ttm_bo_reserve ( & dmabuf - > base , true , false , false , 0 ) ;
if ( unlikely ( ret ! = 0 ) ) {
DRM_ERROR ( " reserve failed \n " ) ;
return - EINVAL ;
}
ret = ttm_bo_kmap ( & dmabuf - > base , kmap_offset , kmap_num , & map ) ;
if ( unlikely ( ret ! = 0 ) )
goto err_unreserve ;
virtual = ttm_kmap_obj_virtual ( & map , & dummy ) ;
vmw_cursor_update_image ( dev_priv , virtual , 64 , 64 ,
du - > hotspot_x , du - > hotspot_y ) ;
ttm_bo_kunmap ( & map ) ;
err_unreserve :
ttm_bo_unreserve ( & dmabuf - > base ) ;
} else {
vmw_cursor_update_position ( dev_priv , false , 0 , 0 ) ;
return 0 ;
}
vmw_cursor_update_position ( dev_priv , true , du - > cursor_x , du - > cursor_y ) ;
return 0 ;
}
int vmw_du_crtc_cursor_move ( struct drm_crtc * crtc , int x , int y )
{
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
struct vmw_display_unit * du = vmw_crtc_to_du ( crtc ) ;
bool shown = du - > cursor_surface | | du - > cursor_dmabuf ? true : false ;
du - > cursor_x = x + crtc - > x ;
du - > cursor_y = y + crtc - > y ;
vmw_cursor_update_position ( dev_priv , shown ,
du - > cursor_x , du - > cursor_y ) ;
return 0 ;
}
void vmw_kms_cursor_snoop ( struct vmw_surface * srf ,
struct ttm_object_file * tfile ,
struct ttm_buffer_object * bo ,
SVGA3dCmdHeader * header )
{
struct ttm_bo_kmap_obj map ;
unsigned long kmap_offset ;
unsigned long kmap_num ;
SVGA3dCopyBox * box ;
unsigned box_count ;
void * virtual ;
bool dummy ;
struct vmw_dma_cmd {
SVGA3dCmdHeader header ;
SVGA3dCmdSurfaceDMA dma ;
} * cmd ;
int ret ;
cmd = container_of ( header , struct vmw_dma_cmd , header ) ;
/* No snooper installed */
if ( ! srf - > snooper . image )
return ;
if ( cmd - > dma . host . face ! = 0 | | cmd - > dma . host . mipmap ! = 0 ) {
DRM_ERROR ( " face and mipmap for cursors should never != 0 \n " ) ;
return ;
}
if ( cmd - > header . size < 64 ) {
DRM_ERROR ( " at least one full copy box must be given \n " ) ;
return ;
}
box = ( SVGA3dCopyBox * ) & cmd [ 1 ] ;
box_count = ( cmd - > header . size - sizeof ( SVGA3dCmdSurfaceDMA ) ) /
sizeof ( SVGA3dCopyBox ) ;
if ( cmd - > dma . guest . pitch ! = ( 64 * 4 ) | |
cmd - > dma . guest . ptr . offset % PAGE_SIZE | |
box - > x ! = 0 | | box - > y ! = 0 | | box - > z ! = 0 | |
box - > srcx ! = 0 | | box - > srcy ! = 0 | | box - > srcz ! = 0 | |
box - > w ! = 64 | | box - > h ! = 64 | | box - > d ! = 1 | |
box_count ! = 1 ) {
/* TODO handle none page aligned offsets */
/* TODO handle partial uploads and pitch != 256 */
/* TODO handle more then one copy (size != 64) */
2011-03-30 22:57:33 -03:00
DRM_ERROR ( " lazy programmer, can't handle weird stuff \n " ) ;
2009-12-10 00:19:58 +00:00
return ;
}
kmap_offset = cmd - > dma . guest . ptr . offset > > PAGE_SHIFT ;
kmap_num = ( 64 * 64 * 4 ) > > PAGE_SHIFT ;
ret = ttm_bo_reserve ( bo , true , false , false , 0 ) ;
if ( unlikely ( ret ! = 0 ) ) {
DRM_ERROR ( " reserve failed \n " ) ;
return ;
}
ret = ttm_bo_kmap ( bo , kmap_offset , kmap_num , & map ) ;
if ( unlikely ( ret ! = 0 ) )
goto err_unreserve ;
virtual = ttm_kmap_obj_virtual ( & map , & dummy ) ;
memcpy ( srf - > snooper . image , virtual , 64 * 64 * 4 ) ;
srf - > snooper . age + + ;
/* we can't call this function from this function since execbuf has
* reserved fifo space .
*
* if ( srf - > snooper . crtc )
* vmw_ldu_crtc_cursor_update_image ( dev_priv ,
* srf - > snooper . image , 64 , 64 ,
* du - > hotspot_x , du - > hotspot_y ) ;
*/
ttm_bo_kunmap ( & map ) ;
err_unreserve :
ttm_bo_unreserve ( bo ) ;
}
void vmw_kms_cursor_post_execbuf ( struct vmw_private * dev_priv )
{
struct drm_device * dev = dev_priv - > dev ;
struct vmw_display_unit * du ;
struct drm_crtc * crtc ;
mutex_lock ( & dev - > mode_config . mutex ) ;
list_for_each_entry ( crtc , & dev - > mode_config . crtc_list , head ) {
du = vmw_crtc_to_du ( crtc ) ;
if ( ! du - > cursor_surface | |
du - > cursor_age = = du - > cursor_surface - > snooper . age )
continue ;
du - > cursor_age = du - > cursor_surface - > snooper . age ;
vmw_cursor_update_image ( dev_priv ,
du - > cursor_surface - > snooper . image ,
64 , 64 , du - > hotspot_x , du - > hotspot_y ) ;
}
mutex_unlock ( & dev - > mode_config . mutex ) ;
}
/*
* Generic framebuffer code
*/
int vmw_framebuffer_create_handle ( struct drm_framebuffer * fb ,
struct drm_file * file_priv ,
unsigned int * handle )
{
if ( handle )
handle = 0 ;
return 0 ;
}
/*
* Surface framebuffer code
*/
# define vmw_framebuffer_to_vfbs(x) \
container_of ( x , struct vmw_framebuffer_surface , base . base )
struct vmw_framebuffer_surface {
struct vmw_framebuffer base ;
struct vmw_surface * surface ;
2010-05-28 11:22:00 +02:00
struct vmw_dma_buffer * buffer ;
2010-10-05 12:43:03 +02:00
struct list_head head ;
struct drm_master * master ;
2009-12-10 00:19:58 +00:00
} ;
void vmw_framebuffer_surface_destroy ( struct drm_framebuffer * framebuffer )
{
2010-10-05 12:43:03 +02:00
struct vmw_framebuffer_surface * vfbs =
2009-12-10 00:19:58 +00:00
vmw_framebuffer_to_vfbs ( framebuffer ) ;
2010-10-05 12:43:03 +02:00
struct vmw_master * vmaster = vmw_master ( vfbs - > master ) ;
mutex_lock ( & vmaster - > fb_surf_mutex ) ;
list_del ( & vfbs - > head ) ;
mutex_unlock ( & vmaster - > fb_surf_mutex ) ;
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
drm_master_put ( & vfbs - > master ) ;
2009-12-10 00:19:58 +00:00
drm_framebuffer_cleanup ( framebuffer ) ;
2010-10-05 12:43:03 +02:00
vmw_surface_unreference ( & vfbs - > surface ) ;
2011-10-04 20:13:32 +02:00
ttm_base_object_unref ( & vfbs - > base . user_obj ) ;
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
kfree ( vfbs ) ;
2009-12-10 00:19:58 +00:00
}
2011-10-04 20:13:22 +02:00
static int do_surface_dirty_sou ( struct vmw_private * dev_priv ,
2011-10-04 20:13:32 +02:00
struct drm_file * file_priv ,
2011-10-04 20:13:22 +02:00
struct vmw_framebuffer * framebuffer ,
unsigned flags , unsigned color ,
struct drm_clip_rect * clips ,
unsigned num_clips , int inc )
{
2011-10-07 15:23:07 +02:00
struct drm_clip_rect * clips_ptr ;
struct vmw_display_unit * units [ VMWGFX_NUM_DISPLAY_UNITS ] ;
struct drm_crtc * crtc ;
2011-10-04 20:13:22 +02:00
size_t fifo_size ;
2011-10-07 15:23:07 +02:00
int i , num_units ;
int ret = 0 ; /* silence warning */
int left , right , top , bottom ;
2011-10-04 20:13:22 +02:00
struct {
SVGA3dCmdHeader header ;
SVGA3dCmdBlitSurfaceToScreen body ;
} * cmd ;
2011-10-07 15:23:07 +02:00
SVGASignedRect * blits ;
2011-10-04 20:13:22 +02:00
2011-10-07 15:23:07 +02:00
num_units = 0 ;
list_for_each_entry ( crtc , & dev_priv - > dev - > mode_config . crtc_list ,
head ) {
if ( crtc - > fb ! = & framebuffer - > base )
continue ;
units [ num_units + + ] = vmw_crtc_to_du ( crtc ) ;
}
BUG_ON ( ! clips | | ! num_clips ) ;
fifo_size = sizeof ( * cmd ) + sizeof ( SVGASignedRect ) * num_clips ;
2011-10-04 20:13:32 +02:00
cmd = kzalloc ( fifo_size , GFP_KERNEL ) ;
2011-10-04 20:13:22 +02:00
if ( unlikely ( cmd = = NULL ) ) {
2011-10-04 20:13:32 +02:00
DRM_ERROR ( " Temporary fifo memory alloc failed. \n " ) ;
2011-10-04 20:13:22 +02:00
return - ENOMEM ;
}
2011-10-07 15:23:07 +02:00
left = clips - > x1 ;
right = clips - > x2 ;
top = clips - > y1 ;
bottom = clips - > y2 ;
clips_ptr = clips ;
for ( i = 1 ; i < num_clips ; i + + , clips_ptr + = inc ) {
left = min_t ( int , left , ( int ) clips_ptr - > x1 ) ;
right = max_t ( int , right , ( int ) clips_ptr - > x2 ) ;
top = min_t ( int , top , ( int ) clips_ptr - > y1 ) ;
bottom = max_t ( int , bottom , ( int ) clips_ptr - > y2 ) ;
2011-10-04 20:13:22 +02:00
}
2011-10-07 15:23:07 +02:00
/* only need to do this once */
memset ( cmd , 0 , fifo_size ) ;
cmd - > header . id = cpu_to_le32 ( SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN ) ;
cmd - > header . size = cpu_to_le32 ( fifo_size - sizeof ( cmd - > header ) ) ;
2011-10-04 20:13:22 +02:00
cmd - > body . srcRect . left = left ;
cmd - > body . srcRect . right = right ;
cmd - > body . srcRect . top = top ;
cmd - > body . srcRect . bottom = bottom ;
2011-10-07 15:23:07 +02:00
clips_ptr = clips ;
blits = ( SVGASignedRect * ) & cmd [ 1 ] ;
for ( i = 0 ; i < num_clips ; i + + , clips_ptr + = inc ) {
blits [ i ] . left = clips_ptr - > x1 - left ;
blits [ i ] . right = clips_ptr - > x2 - left ;
blits [ i ] . top = clips_ptr - > y1 - top ;
blits [ i ] . bottom = clips_ptr - > y2 - top ;
}
/* do per unit writing, reuse fifo for each */
for ( i = 0 ; i < num_units ; i + + ) {
struct vmw_display_unit * unit = units [ i ] ;
int clip_x1 = left - unit - > crtc . x ;
int clip_y1 = top - unit - > crtc . y ;
int clip_x2 = right - unit - > crtc . x ;
int clip_y2 = bottom - unit - > crtc . y ;
/* skip any crtcs that misses the clip region */
if ( clip_x1 > = unit - > crtc . mode . hdisplay | |
clip_y1 > = unit - > crtc . mode . vdisplay | |
clip_x2 < = 0 | | clip_y2 < = 0 )
continue ;
/* need to reset sid as it is changed by execbuf */
cmd - > body . srcImage . sid = cpu_to_le32 ( framebuffer - > user_handle ) ;
cmd - > body . destScreenId = unit - > unit ;
/*
* The blit command is a lot more resilient then the
* readback command when it comes to clip rects . So its
* okay to go out of bounds .
*/
cmd - > body . destRect . left = clip_x1 ;
cmd - > body . destRect . right = clip_x2 ;
cmd - > body . destRect . top = clip_y1 ;
cmd - > body . destRect . bottom = clip_y2 ;
ret = vmw_execbuf_process ( file_priv , dev_priv , NULL , cmd ,
fifo_size , 0 , NULL ) ;
if ( unlikely ( ret ! = 0 ) )
break ;
}
2011-10-04 20:13:22 +02:00
2011-10-04 20:13:32 +02:00
kfree ( cmd ) ;
2011-10-04 20:13:22 +02:00
2011-10-04 20:13:32 +02:00
return ret ;
2011-10-04 20:13:18 +02:00
}
2009-12-10 00:19:58 +00:00
int vmw_framebuffer_surface_dirty ( struct drm_framebuffer * framebuffer ,
2010-10-05 12:43:02 +02:00
struct drm_file * file_priv ,
2009-12-10 00:19:58 +00:00
unsigned flags , unsigned color ,
struct drm_clip_rect * clips ,
unsigned num_clips )
{
struct vmw_private * dev_priv = vmw_priv ( framebuffer - > dev ) ;
2010-10-05 12:43:03 +02:00
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
2009-12-10 00:19:58 +00:00
struct vmw_framebuffer_surface * vfbs =
vmw_framebuffer_to_vfbs ( framebuffer ) ;
struct drm_clip_rect norect ;
2011-10-04 20:13:18 +02:00
int ret , inc = 1 ;
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
if ( unlikely ( vfbs - > master ! = file_priv - > master ) )
return - EINVAL ;
2011-10-04 20:13:24 +02:00
/* Require ScreenObject support for 3D */
if ( ! dev_priv - > sou_priv )
return - EINVAL ;
2010-10-05 12:43:03 +02:00
ret = ttm_read_lock ( & vmaster - > lock , true ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ;
2009-12-10 00:19:58 +00:00
if ( ! num_clips ) {
num_clips = 1 ;
clips = & norect ;
norect . x1 = norect . y1 = 0 ;
norect . x2 = framebuffer - > width ;
norect . y2 = framebuffer - > height ;
} else if ( flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY ) {
num_clips / = 2 ;
inc = 2 ; /* skip source rects */
}
2011-10-22 10:29:34 +02:00
ret = do_surface_dirty_sou ( dev_priv , file_priv , & vfbs - > base ,
2011-10-04 20:13:24 +02:00
flags , color ,
clips , num_clips , inc ) ;
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
ttm_read_unlock ( & vmaster - > lock ) ;
2009-12-10 00:19:58 +00:00
return 0 ;
}
static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
. destroy = vmw_framebuffer_surface_destroy ,
. dirty = vmw_framebuffer_surface_dirty ,
. create_handle = vmw_framebuffer_create_handle ,
} ;
2010-10-05 12:42:59 +02:00
static int vmw_kms_new_framebuffer_surface ( struct vmw_private * dev_priv ,
2010-10-05 12:43:03 +02:00
struct drm_file * file_priv ,
2010-10-05 12:42:59 +02:00
struct vmw_surface * surface ,
struct vmw_framebuffer * * out ,
const struct drm_mode_fb_cmd
* mode_cmd )
2009-12-10 00:19:58 +00:00
{
struct drm_device * dev = dev_priv - > dev ;
struct vmw_framebuffer_surface * vfbs ;
2010-10-05 12:42:59 +02:00
enum SVGA3dSurfaceFormat format ;
2010-10-05 12:43:03 +02:00
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
2009-12-10 00:19:58 +00:00
int ret ;
2011-10-04 20:13:24 +02:00
/* 3D is only supported on HWv8 hosts which supports screen objects */
if ( ! dev_priv - > sou_priv )
return - ENOSYS ;
2010-10-05 12:42:59 +02:00
/*
* Sanity checks .
*/
if ( unlikely ( surface - > mip_levels [ 0 ] ! = 1 | |
surface - > num_sizes ! = 1 | |
surface - > sizes [ 0 ] . width < mode_cmd - > width | |
surface - > sizes [ 0 ] . height < mode_cmd - > height | |
surface - > sizes [ 0 ] . depth ! = 1 ) ) {
DRM_ERROR ( " Incompatible surface dimensions "
" for requested mode. \n " ) ;
return - EINVAL ;
}
switch ( mode_cmd - > depth ) {
case 32 :
format = SVGA3D_A8R8G8B8 ;
break ;
case 24 :
format = SVGA3D_X8R8G8B8 ;
break ;
case 16 :
format = SVGA3D_R5G6B5 ;
break ;
case 15 :
format = SVGA3D_A1R5G5B5 ;
break ;
2011-08-31 07:42:47 +00:00
case 8 :
format = SVGA3D_LUMINANCE8 ;
break ;
2010-10-05 12:42:59 +02:00
default :
DRM_ERROR ( " Invalid color depth: %d \n " , mode_cmd - > depth ) ;
return - EINVAL ;
}
if ( unlikely ( format ! = surface - > format ) ) {
DRM_ERROR ( " Invalid surface format for requested mode. \n " ) ;
return - EINVAL ;
}
2009-12-10 00:19:58 +00:00
vfbs = kzalloc ( sizeof ( * vfbs ) , GFP_KERNEL ) ;
if ( ! vfbs ) {
ret = - ENOMEM ;
goto out_err1 ;
}
ret = drm_framebuffer_init ( dev , & vfbs - > base . base ,
& vmw_framebuffer_surface_funcs ) ;
if ( ret )
goto out_err2 ;
if ( ! vmw_surface_reference ( surface ) ) {
DRM_ERROR ( " failed to reference surface %p \n " , surface ) ;
goto out_err3 ;
}
/* XXX get the first 3 from the surface info */
2010-10-05 12:42:59 +02:00
vfbs - > base . base . bits_per_pixel = mode_cmd - > bpp ;
vfbs - > base . base . pitch = mode_cmd - > pitch ;
vfbs - > base . base . depth = mode_cmd - > depth ;
vfbs - > base . base . width = mode_cmd - > width ;
vfbs - > base . base . height = mode_cmd - > height ;
2009-12-10 00:19:58 +00:00
vfbs - > surface = surface ;
2011-10-04 20:13:32 +02:00
vfbs - > base . user_handle = mode_cmd - > handle ;
2010-10-05 12:43:03 +02:00
vfbs - > master = drm_master_get ( file_priv - > master ) ;
mutex_lock ( & vmaster - > fb_surf_mutex ) ;
list_add_tail ( & vfbs - > head , & vmaster - > fb_surf ) ;
mutex_unlock ( & vmaster - > fb_surf_mutex ) ;
2009-12-10 00:19:58 +00:00
* out = & vfbs - > base ;
return 0 ;
out_err3 :
drm_framebuffer_cleanup ( & vfbs - > base . base ) ;
out_err2 :
kfree ( vfbs ) ;
out_err1 :
return ret ;
}
/*
* Dmabuf framebuffer code
*/
# define vmw_framebuffer_to_vfbd(x) \
container_of ( x , struct vmw_framebuffer_dmabuf , base . base )
struct vmw_framebuffer_dmabuf {
struct vmw_framebuffer base ;
struct vmw_dma_buffer * buffer ;
} ;
void vmw_framebuffer_dmabuf_destroy ( struct drm_framebuffer * framebuffer )
{
struct vmw_framebuffer_dmabuf * vfbd =
vmw_framebuffer_to_vfbd ( framebuffer ) ;
drm_framebuffer_cleanup ( framebuffer ) ;
vmw_dmabuf_unreference ( & vfbd - > buffer ) ;
2011-10-04 20:13:32 +02:00
ttm_base_object_unref ( & vfbd - > base . user_obj ) ;
2009-12-10 00:19:58 +00:00
kfree ( vfbd ) ;
}
2011-10-04 20:13:18 +02:00
static int do_dmabuf_dirty_ldu ( struct vmw_private * dev_priv ,
struct vmw_framebuffer * framebuffer ,
unsigned flags , unsigned color ,
struct drm_clip_rect * clips ,
unsigned num_clips , int increment )
{
size_t fifo_size ;
int i ;
struct {
uint32_t header ;
SVGAFifoCmdUpdate body ;
} * cmd ;
fifo_size = sizeof ( * cmd ) * num_clips ;
cmd = vmw_fifo_reserve ( dev_priv , fifo_size ) ;
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Fifo reserve failed. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , fifo_size ) ;
for ( i = 0 ; i < num_clips ; i + + , clips + = increment ) {
cmd [ i ] . header = cpu_to_le32 ( SVGA_CMD_UPDATE ) ;
cmd [ i ] . body . x = cpu_to_le32 ( clips - > x1 ) ;
cmd [ i ] . body . y = cpu_to_le32 ( clips - > y1 ) ;
cmd [ i ] . body . width = cpu_to_le32 ( clips - > x2 - clips - > x1 ) ;
cmd [ i ] . body . height = cpu_to_le32 ( clips - > y2 - clips - > y1 ) ;
}
vmw_fifo_commit ( dev_priv , fifo_size ) ;
return 0 ;
}
2011-10-07 15:23:07 +02:00
static int do_dmabuf_define_gmrfb ( struct drm_file * file_priv ,
struct vmw_private * dev_priv ,
struct vmw_framebuffer * framebuffer )
2011-10-04 20:13:22 +02:00
{
2011-10-22 10:29:33 +02:00
int depth = framebuffer - > base . depth ;
2011-10-04 20:13:22 +02:00
size_t fifo_size ;
2011-10-07 15:23:07 +02:00
int ret ;
2011-10-04 20:13:22 +02:00
struct {
uint32_t header ;
SVGAFifoCmdDefineGMRFB body ;
} * cmd ;
2011-10-22 10:29:33 +02: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 ;
2011-10-07 15:23:07 +02:00
fifo_size = sizeof ( * cmd ) ;
2011-10-04 20:13:22 +02:00
cmd = kmalloc ( fifo_size , GFP_KERNEL ) ;
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Failed to allocate temporary cmd buffer. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , fifo_size ) ;
cmd - > header = SVGA_CMD_DEFINE_GMRFB ;
cmd - > body . format . bitsPerPixel = framebuffer - > base . bits_per_pixel ;
2011-10-22 10:29:33 +02:00
cmd - > body . format . colorDepth = depth ;
2011-10-04 20:13:22 +02:00
cmd - > body . format . reserved = 0 ;
cmd - > body . bytesPerLine = framebuffer - > base . pitch ;
2011-10-04 20:13:32 +02:00
cmd - > body . ptr . gmrId = framebuffer - > user_handle ;
2011-10-04 20:13:22 +02:00
cmd - > body . ptr . offset = 0 ;
ret = vmw_execbuf_process ( file_priv , dev_priv , NULL , cmd ,
fifo_size , 0 , NULL ) ;
kfree ( cmd ) ;
return ret ;
}
2011-10-07 15:23:07 +02:00
static int do_dmabuf_dirty_sou ( struct drm_file * file_priv ,
struct vmw_private * dev_priv ,
struct vmw_framebuffer * framebuffer ,
unsigned flags , unsigned color ,
struct drm_clip_rect * clips ,
unsigned num_clips , int increment )
{
struct vmw_display_unit * units [ VMWGFX_NUM_DISPLAY_UNITS ] ;
struct drm_clip_rect * clips_ptr ;
int i , k , num_units , ret ;
struct drm_crtc * crtc ;
size_t fifo_size ;
struct {
uint32_t header ;
SVGAFifoCmdBlitGMRFBToScreen body ;
} * blits ;
ret = do_dmabuf_define_gmrfb ( file_priv , dev_priv , framebuffer ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ; /* define_gmrfb prints warnings */
fifo_size = sizeof ( * blits ) * num_clips ;
blits = kmalloc ( fifo_size , GFP_KERNEL ) ;
if ( unlikely ( blits = = NULL ) ) {
DRM_ERROR ( " Failed to allocate temporary cmd buffer. \n " ) ;
return - ENOMEM ;
}
num_units = 0 ;
list_for_each_entry ( crtc , & dev_priv - > dev - > mode_config . crtc_list , head ) {
if ( crtc - > fb ! = & framebuffer - > base )
continue ;
units [ num_units + + ] = vmw_crtc_to_du ( crtc ) ;
}
for ( k = 0 ; k < num_units ; k + + ) {
struct vmw_display_unit * unit = units [ k ] ;
int hit_num = 0 ;
clips_ptr = clips ;
for ( i = 0 ; i < num_clips ; i + + , clips_ptr + = increment ) {
int clip_x1 = clips_ptr - > x1 - unit - > crtc . x ;
int clip_y1 = clips_ptr - > y1 - unit - > crtc . y ;
int clip_x2 = clips_ptr - > x2 - unit - > crtc . x ;
int clip_y2 = clips_ptr - > y2 - unit - > crtc . y ;
/* skip any crtcs that misses the clip region */
if ( clip_x1 > = unit - > crtc . mode . hdisplay | |
clip_y1 > = unit - > crtc . mode . vdisplay | |
clip_x2 < = 0 | | clip_y2 < = 0 )
continue ;
blits [ hit_num ] . header = SVGA_CMD_BLIT_GMRFB_TO_SCREEN ;
blits [ hit_num ] . body . destScreenId = unit - > unit ;
blits [ hit_num ] . body . srcOrigin . x = clips_ptr - > x1 ;
blits [ hit_num ] . body . srcOrigin . y = clips_ptr - > y1 ;
blits [ hit_num ] . body . destRect . left = clip_x1 ;
blits [ hit_num ] . body . destRect . top = clip_y1 ;
blits [ hit_num ] . body . destRect . right = clip_x2 ;
blits [ hit_num ] . body . destRect . bottom = clip_y2 ;
hit_num + + ;
}
/* no clips hit the crtc */
if ( hit_num = = 0 )
continue ;
fifo_size = sizeof ( * blits ) * hit_num ;
ret = vmw_execbuf_process ( file_priv , dev_priv , NULL , blits ,
fifo_size , 0 , NULL ) ;
if ( unlikely ( ret ! = 0 ) )
break ;
}
kfree ( blits ) ;
return ret ;
}
2009-12-10 00:19:58 +00:00
int vmw_framebuffer_dmabuf_dirty ( struct drm_framebuffer * framebuffer ,
2010-10-05 12:43:02 +02:00
struct drm_file * file_priv ,
2009-12-10 00:19:58 +00:00
unsigned flags , unsigned color ,
struct drm_clip_rect * clips ,
unsigned num_clips )
{
struct vmw_private * dev_priv = vmw_priv ( framebuffer - > dev ) ;
2010-10-05 12:43:03 +02:00
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
2011-10-04 20:13:18 +02:00
struct vmw_framebuffer_dmabuf * vfbd =
vmw_framebuffer_to_vfbd ( framebuffer ) ;
2009-12-10 00:19:58 +00:00
struct drm_clip_rect norect ;
2011-10-04 20:13:18 +02:00
int ret , increment = 1 ;
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
ret = ttm_read_lock ( & vmaster - > lock , true ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ;
2010-01-13 22:28:36 +01:00
if ( ! num_clips ) {
2009-12-10 00:19:58 +00:00
num_clips = 1 ;
clips = & norect ;
norect . x1 = norect . y1 = 0 ;
norect . x2 = framebuffer - > width ;
norect . y2 = framebuffer - > height ;
} else if ( flags & DRM_MODE_FB_DIRTY_ANNOTATE_COPY ) {
num_clips / = 2 ;
increment = 2 ;
}
2011-10-04 20:13:22 +02:00
if ( dev_priv - > ldu_priv ) {
2011-10-22 10:29:34 +02:00
ret = do_dmabuf_dirty_ldu ( dev_priv , & vfbd - > base ,
2011-10-04 20:13:22 +02:00
flags , color ,
clips , num_clips , increment ) ;
} else {
ret = do_dmabuf_dirty_sou ( file_priv , dev_priv , & vfbd - > base ,
2011-10-22 10:29:34 +02:00
flags , color ,
2011-10-04 20:13:22 +02:00
clips , num_clips , increment ) ;
}
2009-12-10 00:19:58 +00:00
2010-10-05 12:43:03 +02:00
ttm_read_unlock ( & vmaster - > lock ) ;
2011-10-04 20:13:18 +02:00
return ret ;
2009-12-10 00:19:58 +00:00
}
static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
. destroy = vmw_framebuffer_dmabuf_destroy ,
. dirty = vmw_framebuffer_dmabuf_dirty ,
. create_handle = vmw_framebuffer_create_handle ,
} ;
2011-10-04 20:13:14 +02:00
/**
* Pin the dmabuffer to the start of vram .
*/
2009-12-10 00:19:58 +00:00
static int vmw_framebuffer_dmabuf_pin ( struct vmw_framebuffer * vfb )
{
struct vmw_private * dev_priv = vmw_priv ( vfb - > base . dev ) ;
struct vmw_framebuffer_dmabuf * vfbd =
vmw_framebuffer_to_vfbd ( & vfb - > base ) ;
int ret ;
2011-10-04 20:13:22 +02:00
/* This code should not be used with screen objects */
BUG_ON ( dev_priv - > sou_priv ) ;
2010-05-28 11:21:59 +02:00
2009-12-10 00:19:58 +00:00
vmw_overlay_pause_all ( dev_priv ) ;
2011-10-04 20:13:21 +02:00
ret = vmw_dmabuf_to_start_of_vram ( dev_priv , vfbd - > buffer , true , false ) ;
2009-12-10 00:19:58 +00:00
vmw_overlay_resume_all ( dev_priv ) ;
2010-05-28 11:22:05 +02:00
WARN_ON ( ret ! = 0 ) ;
2009-12-10 00:19:58 +00:00
return 0 ;
}
static int vmw_framebuffer_dmabuf_unpin ( struct vmw_framebuffer * vfb )
{
struct vmw_private * dev_priv = vmw_priv ( vfb - > base . dev ) ;
struct vmw_framebuffer_dmabuf * vfbd =
vmw_framebuffer_to_vfbd ( & vfb - > base ) ;
if ( ! vfbd - > buffer ) {
WARN_ON ( ! vfbd - > buffer ) ;
return 0 ;
}
2011-10-04 20:13:21 +02:00
return vmw_dmabuf_unpin ( dev_priv , vfbd - > buffer , false ) ;
2009-12-10 00:19:58 +00:00
}
2010-10-05 12:42:59 +02:00
static int vmw_kms_new_framebuffer_dmabuf ( struct vmw_private * dev_priv ,
struct vmw_dma_buffer * dmabuf ,
struct vmw_framebuffer * * out ,
const struct drm_mode_fb_cmd
* mode_cmd )
2009-12-10 00:19:58 +00:00
{
struct drm_device * dev = dev_priv - > dev ;
struct vmw_framebuffer_dmabuf * vfbd ;
2010-10-05 12:42:59 +02:00
unsigned int requested_size ;
2009-12-10 00:19:58 +00:00
int ret ;
2010-10-05 12:42:59 +02:00
requested_size = mode_cmd - > height * mode_cmd - > pitch ;
if ( unlikely ( requested_size > dmabuf - > base . num_pages * PAGE_SIZE ) ) {
DRM_ERROR ( " Screen buffer object size is too small "
" for requested mode. \n " ) ;
return - EINVAL ;
}
2011-10-04 20:13:34 +02:00
/* Limited framebuffer color depth support for screen objects */
if ( dev_priv - > sou_priv ) {
switch ( mode_cmd - > depth ) {
case 32 :
case 24 :
/* Only support 32 bpp for 32 and 24 depth fbs */
if ( mode_cmd - > bpp = = 32 )
break ;
DRM_ERROR ( " Invalid color depth/bbp: %d %d \n " ,
mode_cmd - > depth , mode_cmd - > bpp ) ;
return - EINVAL ;
case 16 :
case 15 :
/* Only support 16 bpp for 16 and 15 depth fbs */
if ( mode_cmd - > bpp = = 16 )
break ;
DRM_ERROR ( " Invalid color depth/bbp: %d %d \n " ,
mode_cmd - > depth , mode_cmd - > bpp ) ;
return - EINVAL ;
default :
DRM_ERROR ( " Invalid color depth: %d \n " , mode_cmd - > depth ) ;
return - EINVAL ;
}
}
2009-12-10 00:19:58 +00:00
vfbd = kzalloc ( sizeof ( * vfbd ) , GFP_KERNEL ) ;
if ( ! vfbd ) {
ret = - ENOMEM ;
goto out_err1 ;
}
ret = drm_framebuffer_init ( dev , & vfbd - > base . base ,
& vmw_framebuffer_dmabuf_funcs ) ;
if ( ret )
goto out_err2 ;
if ( ! vmw_dmabuf_reference ( dmabuf ) ) {
DRM_ERROR ( " failed to reference dmabuf %p \n " , dmabuf ) ;
goto out_err3 ;
}
2010-10-05 12:42:59 +02:00
vfbd - > base . base . bits_per_pixel = mode_cmd - > bpp ;
vfbd - > base . base . pitch = mode_cmd - > pitch ;
vfbd - > base . base . depth = mode_cmd - > depth ;
vfbd - > base . base . width = mode_cmd - > width ;
vfbd - > base . base . height = mode_cmd - > height ;
2011-10-04 20:13:22 +02:00
if ( ! dev_priv - > sou_priv ) {
vfbd - > base . pin = vmw_framebuffer_dmabuf_pin ;
vfbd - > base . unpin = vmw_framebuffer_dmabuf_unpin ;
}
2011-10-04 20:13:26 +02:00
vfbd - > base . dmabuf = true ;
2009-12-10 00:19:58 +00:00
vfbd - > buffer = dmabuf ;
2011-10-04 20:13:32 +02:00
vfbd - > base . user_handle = mode_cmd - > handle ;
2009-12-10 00:19:58 +00:00
* out = & vfbd - > base ;
return 0 ;
out_err3 :
drm_framebuffer_cleanup ( & vfbd - > base . base ) ;
out_err2 :
kfree ( vfbd ) ;
out_err1 :
return ret ;
}
/*
* Generic Kernel modesetting functions
*/
static struct drm_framebuffer * vmw_kms_fb_create ( struct drm_device * dev ,
struct drm_file * file_priv ,
struct drm_mode_fb_cmd * mode_cmd )
{
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct ttm_object_file * tfile = vmw_fpriv ( file_priv ) - > tfile ;
struct vmw_framebuffer * vfb = NULL ;
struct vmw_surface * surface = NULL ;
struct vmw_dma_buffer * bo = NULL ;
2011-10-04 20:13:32 +02:00
struct ttm_base_object * user_obj ;
2010-10-05 12:43:04 +02:00
u64 required_size ;
2009-12-10 00:19:58 +00:00
int ret ;
2010-10-05 12:42:59 +02:00
/**
* This code should be conditioned on Screen Objects not being used .
* If screen objects are used , we can allocate a GMR to hold the
* requested framebuffer .
*/
required_size = mode_cmd - > pitch * mode_cmd - > height ;
2010-10-05 12:43:04 +02:00
if ( unlikely ( required_size > ( u64 ) dev_priv - > vram_size ) ) {
2010-10-05 12:42:59 +02:00
DRM_ERROR ( " VRAM size is too small for requested mode. \n " ) ;
return NULL ;
}
2011-10-04 20:13:32 +02:00
/*
* Take a reference on the user object of the resource
* backing the kms fb . This ensures that user - space handle
* lookups on that resource will always work as long as
* it ' s registered with a kms framebuffer . This is important ,
* since vmw_execbuf_process identifies resources in the
* command stream using user - space handles .
*/
user_obj = ttm_base_object_lookup ( tfile , mode_cmd - > handle ) ;
if ( unlikely ( user_obj = = NULL ) ) {
DRM_ERROR ( " Could not locate requested kms frame buffer. \n " ) ;
return ERR_PTR ( - ENOENT ) ;
}
2010-10-05 12:42:59 +02:00
/**
* End conditioned code .
*/
2009-12-22 16:53:41 +01:00
ret = vmw_user_surface_lookup_handle ( dev_priv , tfile ,
mode_cmd - > handle , & surface ) ;
2009-12-10 00:19:58 +00:00
if ( ret )
goto try_dmabuf ;
2010-01-30 03:38:08 +00:00
if ( ! surface - > scanout )
goto err_not_scanout ;
2010-10-05 12:43:03 +02:00
ret = vmw_kms_new_framebuffer_surface ( dev_priv , file_priv , surface ,
& vfb , mode_cmd ) ;
2009-12-10 00:19:58 +00:00
/* vmw_user_surface_lookup takes one ref so does new_fb */
vmw_surface_unreference ( & surface ) ;
if ( ret ) {
DRM_ERROR ( " failed to create vmw_framebuffer: %i \n " , ret ) ;
2011-10-04 20:13:32 +02:00
ttm_base_object_unref ( & user_obj ) ;
2010-08-08 13:36:38 +01:00
return ERR_PTR ( ret ) ;
2011-10-04 20:13:32 +02:00
} else
vfb - > user_obj = user_obj ;
2009-12-10 00:19:58 +00:00
return & vfb - > base ;
try_dmabuf :
DRM_INFO ( " %s: trying buffer \n " , __func__ ) ;
ret = vmw_user_dmabuf_lookup ( tfile , mode_cmd - > handle , & bo ) ;
if ( ret ) {
DRM_ERROR ( " failed to find buffer: %i \n " , ret ) ;
2010-08-08 13:36:38 +01:00
return ERR_PTR ( - ENOENT ) ;
2009-12-10 00:19:58 +00:00
}
ret = vmw_kms_new_framebuffer_dmabuf ( dev_priv , bo , & vfb ,
2010-10-05 12:42:59 +02:00
mode_cmd ) ;
2009-12-10 00:19:58 +00:00
/* vmw_user_dmabuf_lookup takes one ref so does new_fb */
vmw_dmabuf_unreference ( & bo ) ;
if ( ret ) {
DRM_ERROR ( " failed to create vmw_framebuffer: %i \n " , ret ) ;
2011-10-04 20:13:32 +02:00
ttm_base_object_unref ( & user_obj ) ;
2010-08-08 13:36:38 +01:00
return ERR_PTR ( ret ) ;
2011-10-04 20:13:32 +02:00
} else
vfb - > user_obj = user_obj ;
2009-12-10 00:19:58 +00:00
return & vfb - > base ;
2010-01-30 03:38:08 +00:00
err_not_scanout :
DRM_ERROR ( " surface not marked as scanout \n " ) ;
/* vmw_user_surface_lookup takes one ref */
vmw_surface_unreference ( & surface ) ;
2011-10-04 20:13:32 +02:00
ttm_base_object_unref ( & user_obj ) ;
2010-01-30 03:38:08 +00:00
2010-08-08 13:36:38 +01:00
return ERR_PTR ( - EINVAL ) ;
2009-12-10 00:19:58 +00:00
}
static struct drm_mode_config_funcs vmw_kms_funcs = {
. fb_create = vmw_kms_fb_create ,
} ;
2011-10-04 20:13:26 +02:00
int vmw_kms_present ( struct vmw_private * dev_priv ,
struct drm_file * file_priv ,
struct vmw_framebuffer * vfb ,
struct vmw_surface * surface ,
uint32_t sid ,
int32_t destX , int32_t destY ,
struct drm_vmw_rect * clips ,
uint32_t num_clips )
{
2011-10-07 15:23:07 +02:00
struct vmw_display_unit * units [ VMWGFX_NUM_DISPLAY_UNITS ] ;
struct drm_crtc * crtc ;
2011-10-04 20:13:26 +02:00
size_t fifo_size ;
2011-10-07 15:23:07 +02:00
int i , k , num_units ;
int ret = 0 ; /* silence warning */
2011-10-04 20:13:26 +02:00
struct {
SVGA3dCmdHeader header ;
SVGA3dCmdBlitSurfaceToScreen body ;
} * cmd ;
SVGASignedRect * blits ;
2011-10-07 15:23:07 +02:00
num_units = 0 ;
list_for_each_entry ( crtc , & dev_priv - > dev - > mode_config . crtc_list , head ) {
if ( crtc - > fb ! = & vfb - > base )
continue ;
units [ num_units + + ] = vmw_crtc_to_du ( crtc ) ;
}
2011-10-04 20:13:26 +02:00
BUG_ON ( surface = = NULL ) ;
BUG_ON ( ! clips | | ! num_clips ) ;
fifo_size = sizeof ( * cmd ) + sizeof ( SVGASignedRect ) * num_clips ;
cmd = kmalloc ( fifo_size , GFP_KERNEL ) ;
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Failed to allocate temporary fifo memory. \n " ) ;
return - ENOMEM ;
}
2011-10-07 15:23:07 +02:00
/* only need to do this once */
2011-10-04 20:13:26 +02:00
memset ( cmd , 0 , fifo_size ) ;
cmd - > header . id = cpu_to_le32 ( SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN ) ;
cmd - > header . size = cpu_to_le32 ( fifo_size - sizeof ( cmd - > header ) ) ;
cmd - > body . srcRect . left = 0 ;
cmd - > body . srcRect . right = surface - > sizes [ 0 ] . width ;
cmd - > body . srcRect . top = 0 ;
cmd - > body . srcRect . bottom = surface - > sizes [ 0 ] . height ;
blits = ( SVGASignedRect * ) & cmd [ 1 ] ;
for ( i = 0 ; i < num_clips ; i + + ) {
blits [ i ] . left = clips [ i ] . x ;
blits [ i ] . right = clips [ i ] . x + clips [ i ] . w ;
blits [ i ] . top = clips [ i ] . y ;
blits [ i ] . bottom = clips [ i ] . y + clips [ i ] . h ;
}
2011-10-07 15:23:07 +02:00
for ( k = 0 ; k < num_units ; k + + ) {
struct vmw_display_unit * unit = units [ k ] ;
int clip_x1 = destX - unit - > crtc . x ;
int clip_y1 = destY - unit - > crtc . y ;
int clip_x2 = clip_x1 + surface - > sizes [ 0 ] . width ;
int clip_y2 = clip_y1 + surface - > sizes [ 0 ] . height ;
/* skip any crtcs that misses the clip region */
if ( clip_x1 > = unit - > crtc . mode . hdisplay | |
clip_y1 > = unit - > crtc . mode . vdisplay | |
clip_x2 < = 0 | | clip_y2 < = 0 )
continue ;
/* need to reset sid as it is changed by execbuf */
cmd - > body . srcImage . sid = sid ;
cmd - > body . destScreenId = unit - > unit ;
/*
* The blit command is a lot more resilient then the
* readback command when it comes to clip rects . So its
* okay to go out of bounds .
*/
cmd - > body . destRect . left = clip_x1 ;
cmd - > body . destRect . right = clip_x2 ;
cmd - > body . destRect . top = clip_y1 ;
cmd - > body . destRect . bottom = clip_y2 ;
ret = vmw_execbuf_process ( file_priv , dev_priv , NULL , cmd ,
fifo_size , 0 , NULL ) ;
if ( unlikely ( ret ! = 0 ) )
break ;
}
2011-10-04 20:13:26 +02:00
kfree ( cmd ) ;
return ret ;
}
int vmw_kms_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 * clips ,
uint32_t num_clips )
{
struct vmw_framebuffer_dmabuf * vfbd =
vmw_framebuffer_to_vfbd ( & vfb - > base ) ;
struct vmw_dma_buffer * dmabuf = vfbd - > buffer ;
struct vmw_display_unit * units [ VMWGFX_NUM_DISPLAY_UNITS ] ;
struct drm_crtc * crtc ;
size_t fifo_size ;
int i , k , ret , num_units , blits_pos ;
struct {
uint32_t header ;
SVGAFifoCmdDefineGMRFB body ;
} * cmd ;
struct {
uint32_t header ;
SVGAFifoCmdBlitScreenToGMRFB body ;
} * blits ;
num_units = 0 ;
list_for_each_entry ( crtc , & dev_priv - > dev - > mode_config . crtc_list , head ) {
if ( crtc - > fb ! = & vfb - > base )
continue ;
units [ num_units + + ] = vmw_crtc_to_du ( crtc ) ;
}
BUG_ON ( dmabuf = = NULL ) ;
BUG_ON ( ! clips | | ! num_clips ) ;
/* take a safe guess at fifo size */
fifo_size = sizeof ( * cmd ) + sizeof ( * blits ) * num_clips * num_units ;
cmd = kmalloc ( fifo_size , GFP_KERNEL ) ;
if ( unlikely ( cmd = = NULL ) ) {
DRM_ERROR ( " Failed to allocate temporary fifo memory. \n " ) ;
return - ENOMEM ;
}
memset ( cmd , 0 , fifo_size ) ;
cmd - > header = SVGA_CMD_DEFINE_GMRFB ;
cmd - > body . format . bitsPerPixel = vfb - > base . bits_per_pixel ;
cmd - > body . format . colorDepth = vfb - > base . depth ;
cmd - > body . format . reserved = 0 ;
cmd - > body . bytesPerLine = vfb - > base . pitch ;
2011-10-04 20:13:32 +02:00
cmd - > body . ptr . gmrId = vfb - > user_handle ;
2011-10-04 20:13:26 +02:00
cmd - > body . ptr . offset = 0 ;
blits = ( void * ) & cmd [ 1 ] ;
blits_pos = 0 ;
for ( i = 0 ; i < num_units ; i + + ) {
struct drm_vmw_rect * c = clips ;
for ( k = 0 ; k < num_clips ; k + + , c + + ) {
/* transform clip coords to crtc origin based coords */
int clip_x1 = c - > x - units [ i ] - > crtc . x ;
int clip_x2 = c - > x - units [ i ] - > crtc . x + c - > w ;
int clip_y1 = c - > y - units [ i ] - > crtc . y ;
int clip_y2 = c - > y - units [ i ] - > crtc . y + c - > h ;
int dest_x = c - > x ;
int dest_y = c - > y ;
/* compensate for clipping, we negate
* a negative number and add that .
*/
if ( clip_x1 < 0 )
dest_x + = - clip_x1 ;
if ( clip_y1 < 0 )
dest_y + = - clip_y1 ;
/* clip */
clip_x1 = max ( clip_x1 , 0 ) ;
clip_y1 = max ( clip_y1 , 0 ) ;
clip_x2 = min ( clip_x2 , units [ i ] - > crtc . mode . hdisplay ) ;
clip_y2 = min ( clip_y2 , units [ i ] - > crtc . mode . vdisplay ) ;
/* and cull any rects that misses the crtc */
if ( clip_x1 > = units [ i ] - > crtc . mode . hdisplay | |
clip_y1 > = units [ i ] - > crtc . mode . vdisplay | |
clip_x2 < = 0 | | clip_y2 < = 0 )
continue ;
blits [ blits_pos ] . header = SVGA_CMD_BLIT_SCREEN_TO_GMRFB ;
blits [ blits_pos ] . body . srcScreenId = units [ i ] - > unit ;
blits [ blits_pos ] . body . destOrigin . x = dest_x ;
blits [ blits_pos ] . body . destOrigin . y = dest_y ;
blits [ blits_pos ] . body . srcRect . left = clip_x1 ;
blits [ blits_pos ] . body . srcRect . top = clip_y1 ;
blits [ blits_pos ] . body . srcRect . right = clip_x2 ;
blits [ blits_pos ] . body . srcRect . bottom = clip_y2 ;
blits_pos + + ;
}
}
/* reset size here and use calculated exact size from loops */
fifo_size = sizeof ( * cmd ) + sizeof ( * blits ) * blits_pos ;
ret = vmw_execbuf_process ( file_priv , dev_priv , NULL , cmd , fifo_size ,
0 , user_fence_rep ) ;
kfree ( cmd ) ;
return ret ;
}
2009-12-10 00:19:58 +00:00
int vmw_kms_init ( struct vmw_private * dev_priv )
{
struct drm_device * dev = dev_priv - > dev ;
int ret ;
drm_mode_config_init ( dev ) ;
dev - > mode_config . funcs = & vmw_kms_funcs ;
2010-02-09 19:41:57 +00:00
dev - > mode_config . min_width = 1 ;
dev - > mode_config . min_height = 1 ;
2010-05-28 11:21:54 +02:00
/* assumed largest fb size */
dev - > mode_config . max_width = 8192 ;
dev - > mode_config . max_height = 8192 ;
2009-12-10 00:19:58 +00:00
2011-10-04 20:13:22 +02:00
ret = vmw_kms_init_screen_object_display ( dev_priv ) ;
if ( ret ) /* Fallback */
( void ) vmw_kms_init_legacy_display_system ( dev_priv ) ;
2009-12-10 00:19:58 +00:00
return 0 ;
}
int vmw_kms_close ( struct vmw_private * dev_priv )
{
/*
* Docs says we should take the lock before calling this function
* but since it destroys encoders and our destructor calls
* drm_encoder_cleanup which takes the lock we deadlock .
*/
drm_mode_config_cleanup ( dev_priv - > dev ) ;
vmw_kms_close_legacy_display_system ( dev_priv ) ;
return 0 ;
}
int vmw_kms_cursor_bypass_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct drm_vmw_cursor_bypass_arg * arg = data ;
struct vmw_display_unit * du ;
struct drm_mode_object * obj ;
struct drm_crtc * crtc ;
int ret = 0 ;
mutex_lock ( & dev - > mode_config . mutex ) ;
if ( arg - > flags & DRM_VMW_CURSOR_BYPASS_ALL ) {
list_for_each_entry ( crtc , & dev - > mode_config . crtc_list , head ) {
du = vmw_crtc_to_du ( crtc ) ;
du - > hotspot_x = arg - > xhot ;
du - > hotspot_y = arg - > yhot ;
}
mutex_unlock ( & dev - > mode_config . mutex ) ;
return 0 ;
}
obj = drm_mode_object_find ( dev , arg - > crtc_id , DRM_MODE_OBJECT_CRTC ) ;
if ( ! obj ) {
ret = - EINVAL ;
goto out ;
}
crtc = obj_to_crtc ( obj ) ;
du = vmw_crtc_to_du ( crtc ) ;
du - > hotspot_x = arg - > xhot ;
du - > hotspot_y = arg - > yhot ;
out :
mutex_unlock ( & dev - > mode_config . mutex ) ;
return ret ;
}
2011-08-31 07:42:50 +00:00
int vmw_kms_write_svga ( struct vmw_private * vmw_priv ,
2010-05-28 11:21:59 +02:00
unsigned width , unsigned height , unsigned pitch ,
2011-08-31 07:42:49 +00:00
unsigned bpp , unsigned depth )
2009-12-10 00:19:58 +00:00
{
2010-05-28 11:21:59 +02:00
if ( vmw_priv - > capabilities & SVGA_CAP_PITCHLOCK )
vmw_write ( vmw_priv , SVGA_REG_PITCHLOCK , pitch ) ;
else if ( vmw_fifo_have_pitchlock ( vmw_priv ) )
iowrite32 ( pitch , vmw_priv - > mmio_virt + SVGA_FIFO_PITCHLOCK ) ;
vmw_write ( vmw_priv , SVGA_REG_WIDTH , width ) ;
vmw_write ( vmw_priv , SVGA_REG_HEIGHT , height ) ;
2011-08-31 07:42:49 +00:00
vmw_write ( vmw_priv , SVGA_REG_BITS_PER_PIXEL , bpp ) ;
2011-08-31 07:42:50 +00:00
if ( vmw_read ( vmw_priv , SVGA_REG_DEPTH ) ! = depth ) {
DRM_ERROR ( " Invalid depth %u for %u bpp, host expects %u \n " ,
depth , bpp , vmw_read ( vmw_priv , SVGA_REG_DEPTH ) ) ;
return - EINVAL ;
}
return 0 ;
2010-05-28 11:21:59 +02:00
}
2009-12-10 00:19:58 +00:00
2010-05-28 11:21:59 +02:00
int vmw_kms_save_vga ( struct vmw_private * vmw_priv )
{
2010-06-01 11:38:17 +02:00
struct vmw_vga_topology_state * save ;
uint32_t i ;
2009-12-10 00:19:58 +00:00
vmw_priv - > vga_width = vmw_read ( vmw_priv , SVGA_REG_WIDTH ) ;
vmw_priv - > vga_height = vmw_read ( vmw_priv , SVGA_REG_HEIGHT ) ;
2010-06-01 11:38:17 +02:00
vmw_priv - > vga_bpp = vmw_read ( vmw_priv , SVGA_REG_BITS_PER_PIXEL ) ;
2010-05-28 11:21:59 +02:00
if ( vmw_priv - > capabilities & SVGA_CAP_PITCHLOCK )
vmw_priv - > vga_pitchlock =
2010-06-01 11:38:17 +02:00
vmw_read ( vmw_priv , SVGA_REG_PITCHLOCK ) ;
2010-05-28 11:21:59 +02:00
else if ( vmw_fifo_have_pitchlock ( vmw_priv ) )
2010-06-01 11:38:17 +02:00
vmw_priv - > vga_pitchlock = ioread32 ( vmw_priv - > mmio_virt +
SVGA_FIFO_PITCHLOCK ) ;
if ( ! ( vmw_priv - > capabilities & SVGA_CAP_DISPLAY_TOPOLOGY ) )
return 0 ;
2009-12-10 00:19:58 +00:00
2010-06-01 11:38:17 +02:00
vmw_priv - > num_displays = vmw_read ( vmw_priv ,
SVGA_REG_NUM_GUEST_DISPLAYS ) ;
2010-10-05 12:43:08 +02:00
if ( vmw_priv - > num_displays = = 0 )
vmw_priv - > num_displays = 1 ;
2010-06-01 11:38:17 +02:00
for ( i = 0 ; i < vmw_priv - > num_displays ; + + i ) {
save = & vmw_priv - > vga_save [ i ] ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_ID , i ) ;
save - > primary = vmw_read ( vmw_priv , SVGA_REG_DISPLAY_IS_PRIMARY ) ;
save - > pos_x = vmw_read ( vmw_priv , SVGA_REG_DISPLAY_POSITION_X ) ;
save - > pos_y = vmw_read ( vmw_priv , SVGA_REG_DISPLAY_POSITION_Y ) ;
save - > width = vmw_read ( vmw_priv , SVGA_REG_DISPLAY_WIDTH ) ;
save - > height = vmw_read ( vmw_priv , SVGA_REG_DISPLAY_HEIGHT ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_ID , SVGA_ID_INVALID ) ;
2010-10-01 10:21:48 +02:00
if ( i = = 0 & & vmw_priv - > num_displays = = 1 & &
save - > width = = 0 & & save - > height = = 0 ) {
/*
* It should be fairly safe to assume that these
* values are uninitialized .
*/
save - > width = vmw_priv - > vga_width - save - > pos_x ;
save - > height = vmw_priv - > vga_height - save - > pos_y ;
}
2010-06-01 11:38:17 +02:00
}
2010-10-01 10:21:48 +02:00
2009-12-10 00:19:58 +00:00
return 0 ;
}
int vmw_kms_restore_vga ( struct vmw_private * vmw_priv )
{
2010-06-01 11:38:17 +02:00
struct vmw_vga_topology_state * save ;
uint32_t i ;
2009-12-10 00:19:58 +00:00
vmw_write ( vmw_priv , SVGA_REG_WIDTH , vmw_priv - > vga_width ) ;
vmw_write ( vmw_priv , SVGA_REG_HEIGHT , vmw_priv - > vga_height ) ;
2010-06-01 11:38:17 +02:00
vmw_write ( vmw_priv , SVGA_REG_BITS_PER_PIXEL , vmw_priv - > vga_bpp ) ;
2010-05-28 11:21:59 +02:00
if ( vmw_priv - > capabilities & SVGA_CAP_PITCHLOCK )
vmw_write ( vmw_priv , SVGA_REG_PITCHLOCK ,
vmw_priv - > vga_pitchlock ) ;
else if ( vmw_fifo_have_pitchlock ( vmw_priv ) )
iowrite32 ( vmw_priv - > vga_pitchlock ,
vmw_priv - > mmio_virt + SVGA_FIFO_PITCHLOCK ) ;
2009-12-10 00:19:58 +00:00
2010-06-01 11:38:17 +02:00
if ( ! ( vmw_priv - > capabilities & SVGA_CAP_DISPLAY_TOPOLOGY ) )
return 0 ;
for ( i = 0 ; i < vmw_priv - > num_displays ; + + i ) {
save = & vmw_priv - > vga_save [ i ] ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_ID , i ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_IS_PRIMARY , save - > primary ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_POSITION_X , save - > pos_x ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_POSITION_Y , save - > pos_y ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_WIDTH , save - > width ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_HEIGHT , save - > height ) ;
vmw_write ( vmw_priv , SVGA_REG_DISPLAY_ID , SVGA_ID_INVALID ) ;
}
2009-12-10 00:19:58 +00:00
return 0 ;
}
2010-06-01 11:54:20 +02:00
2010-10-05 12:43:04 +02:00
bool vmw_kms_validate_mode_vram ( struct vmw_private * dev_priv ,
uint32_t pitch ,
uint32_t height )
{
return ( ( u64 ) pitch * ( u64 ) height ) < ( u64 ) dev_priv - > vram_size ;
}
2011-10-17 11:59:45 +02:00
/**
* Function called by DRM code called with vbl_lock held .
*/
2010-10-01 10:21:49 +02:00
u32 vmw_get_vblank_counter ( struct drm_device * dev , int crtc )
{
return 0 ;
}
2011-10-04 20:13:20 +02:00
2011-10-17 11:59:45 +02:00
/**
* Function called by DRM code called with vbl_lock held .
*/
int vmw_enable_vblank ( struct drm_device * dev , int crtc )
{
return - ENOSYS ;
}
/**
* Function called by DRM code called with vbl_lock held .
*/
void vmw_disable_vblank ( struct drm_device * dev , int crtc )
{
}
2011-10-04 20:13:20 +02:00
/*
* Small shared kms functions .
*/
int vmw_du_update_layout ( struct vmw_private * dev_priv , unsigned num ,
struct drm_vmw_rect * rects )
{
struct drm_device * dev = dev_priv - > dev ;
struct vmw_display_unit * du ;
struct drm_connector * con ;
mutex_lock ( & dev - > mode_config . mutex ) ;
#if 0
2011-10-04 20:13:36 +02:00
{
unsigned int i ;
DRM_INFO ( " %s: new layout " , __func__ ) ;
for ( i = 0 ; i < num ; i + + )
DRM_INFO ( " (%i, %i %ux%u) " , rects [ i ] . x , rects [ i ] . y ,
rects [ i ] . w , rects [ i ] . h ) ;
DRM_INFO ( " \n " ) ;
}
2011-10-04 20:13:20 +02:00
# endif
list_for_each_entry ( con , & dev - > mode_config . connector_list , head ) {
du = vmw_connector_to_du ( con ) ;
if ( num > du - > unit ) {
du - > pref_width = rects [ du - > unit ] . w ;
du - > pref_height = rects [ du - > unit ] . h ;
du - > pref_active = true ;
2011-10-25 23:35:53 +02:00
du - > gui_x = rects [ du - > unit ] . x ;
du - > gui_y = rects [ du - > unit ] . y ;
2011-10-04 20:13:20 +02:00
} else {
du - > pref_width = 800 ;
du - > pref_height = 600 ;
du - > pref_active = false ;
}
con - > status = vmw_du_connector_detect ( con , true ) ;
}
mutex_unlock ( & dev - > mode_config . mutex ) ;
return 0 ;
}
void vmw_du_crtc_save ( struct drm_crtc * crtc )
{
}
void vmw_du_crtc_restore ( struct drm_crtc * crtc )
{
}
void vmw_du_crtc_gamma_set ( struct drm_crtc * crtc ,
u16 * r , u16 * g , u16 * b ,
uint32_t start , uint32_t size )
{
struct vmw_private * dev_priv = vmw_priv ( crtc - > dev ) ;
int i ;
for ( i = 0 ; i < size ; i + + ) {
DRM_DEBUG ( " %d r/g/b = 0x%04x / 0x%04x / 0x%04x \n " , i ,
r [ i ] , g [ i ] , b [ i ] ) ;
vmw_write ( dev_priv , SVGA_PALETTE_BASE + i * 3 + 0 , r [ i ] > > 8 ) ;
vmw_write ( dev_priv , SVGA_PALETTE_BASE + i * 3 + 1 , g [ i ] > > 8 ) ;
vmw_write ( dev_priv , SVGA_PALETTE_BASE + i * 3 + 2 , b [ i ] > > 8 ) ;
}
}
void vmw_du_connector_dpms ( struct drm_connector * connector , int mode )
{
}
void vmw_du_connector_save ( struct drm_connector * connector )
{
}
void vmw_du_connector_restore ( struct drm_connector * connector )
{
}
enum drm_connector_status
vmw_du_connector_detect ( struct drm_connector * connector , bool force )
{
uint32_t num_displays ;
struct drm_device * dev = connector - > dev ;
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
2011-10-25 23:35:53 +02:00
struct vmw_display_unit * du = vmw_connector_to_du ( connector ) ;
2011-10-04 20:13:20 +02:00
mutex_lock ( & dev_priv - > hw_mutex ) ;
num_displays = vmw_read ( dev_priv , SVGA_REG_NUM_DISPLAYS ) ;
mutex_unlock ( & dev_priv - > hw_mutex ) ;
2011-10-25 23:35:53 +02:00
return ( ( vmw_connector_to_du ( connector ) - > unit < num_displays & &
du - > pref_active ) ?
2011-10-04 20:13:20 +02:00
connector_status_connected : connector_status_disconnected ) ;
}
static struct drm_display_mode vmw_kms_connector_builtin [ ] = {
/* 640x480@60Hz */
{ DRM_MODE ( " 640x480 " , DRM_MODE_TYPE_DRIVER , 25175 , 640 , 656 ,
752 , 800 , 0 , 480 , 489 , 492 , 525 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
/* 800x600@60Hz */
{ DRM_MODE ( " 800x600 " , DRM_MODE_TYPE_DRIVER , 40000 , 800 , 840 ,
968 , 1056 , 0 , 600 , 601 , 605 , 628 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1024x768@60Hz */
{ DRM_MODE ( " 1024x768 " , DRM_MODE_TYPE_DRIVER , 65000 , 1024 , 1048 ,
1184 , 1344 , 0 , 768 , 771 , 777 , 806 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
/* 1152x864@75Hz */
{ DRM_MODE ( " 1152x864 " , DRM_MODE_TYPE_DRIVER , 108000 , 1152 , 1216 ,
1344 , 1600 , 0 , 864 , 865 , 868 , 900 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1280x768@60Hz */
{ DRM_MODE ( " 1280x768 " , DRM_MODE_TYPE_DRIVER , 79500 , 1280 , 1344 ,
1472 , 1664 , 0 , 768 , 771 , 778 , 798 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1280x800@60Hz */
{ DRM_MODE ( " 1280x800 " , DRM_MODE_TYPE_DRIVER , 83500 , 1280 , 1352 ,
1480 , 1680 , 0 , 800 , 803 , 809 , 831 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC ) } ,
/* 1280x960@60Hz */
{ DRM_MODE ( " 1280x960 " , DRM_MODE_TYPE_DRIVER , 108000 , 1280 , 1376 ,
1488 , 1800 , 0 , 960 , 961 , 964 , 1000 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1280x1024@60Hz */
{ DRM_MODE ( " 1280x1024 " , DRM_MODE_TYPE_DRIVER , 108000 , 1280 , 1328 ,
1440 , 1688 , 0 , 1024 , 1025 , 1028 , 1066 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1360x768@60Hz */
{ DRM_MODE ( " 1360x768 " , DRM_MODE_TYPE_DRIVER , 85500 , 1360 , 1424 ,
1536 , 1792 , 0 , 768 , 771 , 777 , 795 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1440x1050@60Hz */
{ DRM_MODE ( " 1400x1050 " , DRM_MODE_TYPE_DRIVER , 121750 , 1400 , 1488 ,
1632 , 1864 , 0 , 1050 , 1053 , 1057 , 1089 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1440x900@60Hz */
{ DRM_MODE ( " 1440x900 " , DRM_MODE_TYPE_DRIVER , 106500 , 1440 , 1520 ,
1672 , 1904 , 0 , 900 , 903 , 909 , 934 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1600x1200@60Hz */
{ DRM_MODE ( " 1600x1200 " , DRM_MODE_TYPE_DRIVER , 162000 , 1600 , 1664 ,
1856 , 2160 , 0 , 1200 , 1201 , 1204 , 1250 , 0 ,
DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1680x1050@60Hz */
{ DRM_MODE ( " 1680x1050 " , DRM_MODE_TYPE_DRIVER , 146250 , 1680 , 1784 ,
1960 , 2240 , 0 , 1050 , 1053 , 1059 , 1089 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1792x1344@60Hz */
{ DRM_MODE ( " 1792x1344 " , DRM_MODE_TYPE_DRIVER , 204750 , 1792 , 1920 ,
2120 , 2448 , 0 , 1344 , 1345 , 1348 , 1394 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1853x1392@60Hz */
{ DRM_MODE ( " 1856x1392 " , DRM_MODE_TYPE_DRIVER , 218250 , 1856 , 1952 ,
2176 , 2528 , 0 , 1392 , 1393 , 1396 , 1439 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1920x1200@60Hz */
{ DRM_MODE ( " 1920x1200 " , DRM_MODE_TYPE_DRIVER , 193250 , 1920 , 2056 ,
2256 , 2592 , 0 , 1200 , 1203 , 1209 , 1245 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 1920x1440@60Hz */
{ DRM_MODE ( " 1920x1440 " , DRM_MODE_TYPE_DRIVER , 234000 , 1920 , 2048 ,
2256 , 2600 , 0 , 1440 , 1441 , 1444 , 1500 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* 2560x1600@60Hz */
{ DRM_MODE ( " 2560x1600 " , DRM_MODE_TYPE_DRIVER , 348500 , 2560 , 2752 ,
3032 , 3504 , 0 , 1600 , 1603 , 1609 , 1658 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC ) } ,
/* Terminate */
{ DRM_MODE ( " " , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ) } ,
} ;
int vmw_du_connector_fill_modes ( struct drm_connector * connector ,
uint32_t max_width , uint32_t max_height )
{
struct vmw_display_unit * du = vmw_connector_to_du ( connector ) ;
struct drm_device * dev = connector - > dev ;
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct drm_display_mode * mode = NULL ;
struct drm_display_mode * bmode ;
struct drm_display_mode prefmode = { DRM_MODE ( " preferred " ,
DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED ,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_PVSYNC )
} ;
int i ;
/* Add preferred mode */
{
mode = drm_mode_duplicate ( dev , & prefmode ) ;
if ( ! mode )
return 0 ;
mode - > hdisplay = du - > pref_width ;
mode - > vdisplay = du - > pref_height ;
mode - > vrefresh = drm_mode_vrefresh ( mode ) ;
if ( vmw_kms_validate_mode_vram ( dev_priv , mode - > hdisplay * 2 ,
mode - > vdisplay ) ) {
drm_mode_probed_add ( connector , mode ) ;
if ( du - > pref_mode ) {
list_del_init ( & du - > pref_mode - > head ) ;
drm_mode_destroy ( dev , du - > pref_mode ) ;
}
du - > pref_mode = mode ;
}
}
for ( i = 0 ; vmw_kms_connector_builtin [ i ] . type ! = 0 ; i + + ) {
bmode = & vmw_kms_connector_builtin [ i ] ;
if ( bmode - > hdisplay > max_width | |
bmode - > vdisplay > max_height )
continue ;
if ( ! vmw_kms_validate_mode_vram ( dev_priv , bmode - > hdisplay * 2 ,
bmode - > vdisplay ) )
continue ;
mode = drm_mode_duplicate ( dev , bmode ) ;
if ( ! mode )
return 0 ;
mode - > vrefresh = drm_mode_vrefresh ( mode ) ;
drm_mode_probed_add ( connector , mode ) ;
}
drm_mode_connector_list_update ( connector ) ;
return 1 ;
}
int vmw_du_connector_set_property ( struct drm_connector * connector ,
struct drm_property * property ,
uint64_t val )
{
return 0 ;
}
2011-10-25 23:35:53 +02:00
int vmw_kms_update_layout_ioctl ( struct drm_device * dev , void * data ,
struct drm_file * file_priv )
{
struct vmw_private * dev_priv = vmw_priv ( dev ) ;
struct drm_vmw_update_layout_arg * arg =
( struct drm_vmw_update_layout_arg * ) data ;
struct vmw_master * vmaster = vmw_master ( file_priv - > master ) ;
void __user * user_rects ;
struct drm_vmw_rect * rects ;
unsigned rects_size ;
int ret ;
int i ;
struct drm_mode_config * mode_config = & dev - > mode_config ;
ret = ttm_read_lock ( & vmaster - > lock , true ) ;
if ( unlikely ( ret ! = 0 ) )
return ret ;
if ( ! arg - > num_outputs ) {
struct drm_vmw_rect def_rect = { 0 , 0 , 800 , 600 } ;
vmw_du_update_layout ( dev_priv , 1 , & def_rect ) ;
goto out_unlock ;
}
rects_size = arg - > num_outputs * sizeof ( struct drm_vmw_rect ) ;
rects = kzalloc ( rects_size , GFP_KERNEL ) ;
if ( unlikely ( ! rects ) ) {
ret = - ENOMEM ;
goto out_unlock ;
}
user_rects = ( void __user * ) ( unsigned long ) arg - > rects ;
ret = copy_from_user ( rects , user_rects , rects_size ) ;
if ( unlikely ( ret ! = 0 ) ) {
DRM_ERROR ( " Failed to get rects. \n " ) ;
ret = - EFAULT ;
goto out_free ;
}
for ( i = 0 ; i < arg - > num_outputs ; + + i ) {
if ( rects - > x < 0 | |
rects - > y < 0 | |
rects - > x + rects - > w > mode_config - > max_width | |
rects - > y + rects - > h > mode_config - > max_height ) {
DRM_ERROR ( " Invalid GUI layout. \n " ) ;
ret = - EINVAL ;
goto out_free ;
}
}
vmw_du_update_layout ( dev_priv , arg - > num_outputs , rects ) ;
out_free :
kfree ( rects ) ;
out_unlock :
ttm_read_unlock ( & vmaster - > lock ) ;
return ret ;
}