2009-12-11 12:24:15 +03:00
/*
* Copyright ( C ) 2008 Maarten Maathuis .
* 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 , sublicense , 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 NONINFRINGEMENT .
* IN NO EVENT SHALL THE COPYRIGHT OWNER ( S ) 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 "drmP.h"
# include "drm_crtc_helper.h"
# include "nouveau_drv.h"
# include "nouveau_fb.h"
# include "nouveau_fbcon.h"
2010-10-21 20:19:29 +04:00
# include "nouveau_hw.h"
2010-10-21 01:35:40 +04:00
# include "nouveau_crtc.h"
# include "nouveau_dma.h"
2011-10-17 06:23:41 +04:00
# include "nouveau_connector.h"
2011-11-24 06:59:44 +04:00
# include "nouveau_gpio.h"
2011-02-09 04:57:45 +03:00
# include "nv50_display.h"
2009-12-11 12:24:15 +03:00
static void
nouveau_user_framebuffer_destroy ( struct drm_framebuffer * drm_fb )
{
struct nouveau_framebuffer * fb = nouveau_framebuffer ( drm_fb ) ;
2010-02-09 08:49:12 +03:00
if ( fb - > nvbo )
drm_gem_object_unreference_unlocked ( fb - > nvbo - > gem ) ;
2009-12-11 12:24:15 +03:00
drm_framebuffer_cleanup ( drm_fb ) ;
kfree ( fb ) ;
}
static int
nouveau_user_framebuffer_create_handle ( struct drm_framebuffer * drm_fb ,
struct drm_file * file_priv ,
unsigned int * handle )
{
struct nouveau_framebuffer * fb = nouveau_framebuffer ( drm_fb ) ;
return drm_gem_handle_create ( file_priv , fb - > nvbo - > gem , handle ) ;
}
static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = {
. destroy = nouveau_user_framebuffer_destroy ,
. create_handle = nouveau_user_framebuffer_create_handle ,
} ;
2010-03-30 09:34:13 +04:00
int
2011-02-09 04:57:45 +03:00
nouveau_framebuffer_init ( struct drm_device * dev ,
struct nouveau_framebuffer * nv_fb ,
2011-11-15 02:51:28 +04:00
struct drm_mode_fb_cmd2 * mode_cmd ,
2011-02-09 04:57:45 +03:00
struct nouveau_bo * nvbo )
2009-12-11 12:24:15 +03:00
{
2011-02-09 04:57:45 +03:00
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct drm_framebuffer * fb = & nv_fb - > base ;
2009-12-11 12:24:15 +03:00
int ret ;
2011-02-09 04:57:45 +03:00
ret = drm_framebuffer_init ( dev , fb , & nouveau_framebuffer_funcs ) ;
2009-12-11 12:24:15 +03:00
if ( ret ) {
2010-03-30 09:34:13 +04:00
return ret ;
2009-12-11 12:24:15 +03:00
}
2011-02-09 04:57:45 +03:00
drm_helper_mode_fill_fb_struct ( fb , mode_cmd ) ;
nv_fb - > nvbo = nvbo ;
if ( dev_priv - > card_type > = NV_50 ) {
u32 tile_flags = nouveau_bo_tile_layout ( nvbo ) ;
if ( tile_flags = = 0x7a00 | |
tile_flags = = 0xfe00 )
nv_fb - > r_dma = NvEvoFB32 ;
else
if ( tile_flags = = 0x7000 )
nv_fb - > r_dma = NvEvoFB16 ;
else
nv_fb - > r_dma = NvEvoVRAM_LP ;
switch ( fb - > depth ) {
case 8 : nv_fb - > r_format = NV50_EVO_CRTC_FB_DEPTH_8 ; break ;
case 15 : nv_fb - > r_format = NV50_EVO_CRTC_FB_DEPTH_15 ; break ;
case 16 : nv_fb - > r_format = NV50_EVO_CRTC_FB_DEPTH_16 ; break ;
case 24 :
case 32 : nv_fb - > r_format = NV50_EVO_CRTC_FB_DEPTH_24 ; break ;
case 30 : nv_fb - > r_format = NV50_EVO_CRTC_FB_DEPTH_30 ; break ;
default :
NV_ERROR ( dev , " unknown depth %d \n " , fb - > depth ) ;
return - EINVAL ;
}
if ( dev_priv - > chipset = = 0x50 )
nv_fb - > r_format | = ( tile_flags < < 8 ) ;
2011-07-06 03:59:40 +04:00
if ( ! tile_flags ) {
if ( dev_priv - > card_type < NV_D0 )
2011-12-20 02:06:49 +04:00
nv_fb - > r_pitch = 0x00100000 | fb - > pitches [ 0 ] ;
2011-07-06 03:59:40 +04:00
else
2011-12-20 02:06:49 +04:00
nv_fb - > r_pitch = 0x01000000 | fb - > pitches [ 0 ] ;
2011-07-06 03:59:40 +04:00
} else {
2011-02-09 04:57:45 +03:00
u32 mode = nvbo - > tile_mode ;
if ( dev_priv - > card_type > = NV_C0 )
mode > > = 4 ;
2011-12-20 02:06:49 +04:00
nv_fb - > r_pitch = ( ( fb - > pitches [ 0 ] / 4 ) < < 4 ) | mode ;
2011-02-09 04:57:45 +03:00
}
}
2010-03-30 09:34:13 +04:00
return 0 ;
2009-12-11 12:24:15 +03:00
}
static struct drm_framebuffer *
nouveau_user_framebuffer_create ( struct drm_device * dev ,
struct drm_file * file_priv ,
2011-11-15 02:51:28 +04:00
struct drm_mode_fb_cmd2 * mode_cmd )
2009-12-11 12:24:15 +03:00
{
2010-03-30 09:34:13 +04:00
struct nouveau_framebuffer * nouveau_fb ;
2009-12-11 12:24:15 +03:00
struct drm_gem_object * gem ;
2010-03-30 09:34:13 +04:00
int ret ;
2009-12-11 12:24:15 +03:00
2011-11-15 02:51:28 +04:00
gem = drm_gem_object_lookup ( dev , file_priv , mode_cmd - > handles [ 0 ] ) ;
2009-12-11 12:24:15 +03:00
if ( ! gem )
2010-08-08 16:36:38 +04:00
return ERR_PTR ( - ENOENT ) ;
2009-12-11 12:24:15 +03:00
2010-03-30 09:34:13 +04:00
nouveau_fb = kzalloc ( sizeof ( struct nouveau_framebuffer ) , GFP_KERNEL ) ;
if ( ! nouveau_fb )
2010-08-08 16:36:38 +04:00
return ERR_PTR ( - ENOMEM ) ;
2010-03-30 09:34:13 +04:00
ret = nouveau_framebuffer_init ( dev , nouveau_fb , mode_cmd , nouveau_gem_object ( gem ) ) ;
if ( ret ) {
2009-12-11 12:24:15 +03:00
drm_gem_object_unreference ( gem ) ;
2010-08-08 16:36:38 +04:00
return ERR_PTR ( ret ) ;
2009-12-11 12:24:15 +03:00
}
2010-03-30 09:34:13 +04:00
return & nouveau_fb - > base ;
2009-12-11 12:24:15 +03:00
}
2011-10-06 06:46:40 +04:00
static const struct drm_mode_config_funcs nouveau_mode_config_funcs = {
2009-12-11 12:24:15 +03:00
. fb_create = nouveau_user_framebuffer_create ,
2010-05-07 10:42:51 +04:00
. output_poll_changed = nouveau_fbcon_output_poll_changed ,
2009-12-11 12:24:15 +03:00
} ;
2011-10-06 07:29:05 +04:00
2012-02-06 13:58:17 +04:00
struct nouveau_drm_prop_enum_list {
2011-10-17 06:23:41 +04:00
u8 gen_mask ;
2011-10-06 07:29:05 +04:00
int type ;
char * name ;
} ;
2012-02-06 13:58:17 +04:00
static struct nouveau_drm_prop_enum_list underscan [ ] = {
2011-11-11 17:49:06 +04:00
{ 6 , UNDERSCAN_AUTO , " auto " } ,
{ 6 , UNDERSCAN_OFF , " off " } ,
{ 6 , UNDERSCAN_ON , " on " } ,
2011-10-17 06:23:41 +04:00
{ }
2011-10-06 07:29:05 +04:00
} ;
2012-02-06 13:58:17 +04:00
static struct nouveau_drm_prop_enum_list dither_mode [ ] = {
2011-10-17 06:23:41 +04:00
{ 7 , DITHERING_MODE_AUTO , " auto " } ,
{ 7 , DITHERING_MODE_OFF , " off " } ,
{ 1 , DITHERING_MODE_ON , " on " } ,
{ 6 , DITHERING_MODE_STATIC2X2 , " static 2x2 " } ,
{ 6 , DITHERING_MODE_DYNAMIC2X2 , " dynamic 2x2 " } ,
{ 4 , DITHERING_MODE_TEMPORAL , " temporal " } ,
{ }
} ;
2012-02-06 13:58:17 +04:00
static struct nouveau_drm_prop_enum_list dither_depth [ ] = {
2011-10-17 06:23:41 +04:00
{ 6 , DITHERING_DEPTH_AUTO , " auto " } ,
{ 6 , DITHERING_DEPTH_6BPC , " 6 bpc " } ,
{ 6 , DITHERING_DEPTH_8BPC , " 8 bpc " } ,
{ }
} ;
# define PROP_ENUM(p,gen,n,list) do { \
2012-02-06 13:58:17 +04:00
struct nouveau_drm_prop_enum_list * l = ( list ) ; \
2011-10-17 06:23:41 +04:00
int c = 0 ; \
while ( l - > gen_mask ) { \
if ( l - > gen_mask & ( 1 < < ( gen ) ) ) \
c + + ; \
l + + ; \
} \
if ( c ) { \
p = drm_property_create ( dev , DRM_MODE_PROP_ENUM , n , c ) ; \
l = ( list ) ; \
c = 0 ; \
while ( p & & l - > gen_mask ) { \
if ( l - > gen_mask & ( 1 < < ( gen ) ) ) { \
drm_property_add_enum ( p , c , l - > type , l - > name ) ; \
c + + ; \
} \
l + + ; \
} \
} \
} while ( 0 )
2011-11-09 09:18:47 +04:00
int
nouveau_display_init ( struct drm_device * dev )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct nouveau_display_engine * disp = & dev_priv - > engine . display ;
2011-11-24 06:59:44 +04:00
struct drm_connector * connector ;
2011-11-09 09:18:47 +04:00
int ret ;
ret = disp - > init ( dev ) ;
2011-11-24 06:59:44 +04:00
if ( ret )
return ret ;
2012-01-31 03:16:59 +04:00
/* power on internal panel if it's not already. the init tables of
* some vbios default this to off for some reason , causing the
* panel to not work after resume
*/
if ( nouveau_gpio_func_get ( dev , DCB_GPIO_PANEL_POWER ) = = 0 ) {
nouveau_gpio_func_set ( dev , DCB_GPIO_PANEL_POWER , true ) ;
msleep ( 300 ) ;
}
/* enable polling for external displays */
2011-11-24 06:59:44 +04:00
drm_kms_helper_poll_enable ( dev ) ;
/* enable hotplug interrupts */
list_for_each_entry ( connector , & dev - > mode_config . connector_list , head ) {
struct nouveau_connector * conn = nouveau_connector ( connector ) ;
nouveau_gpio_irq ( dev , 0 , conn - > hpd , 0xff , true ) ;
2011-11-09 09:18:47 +04:00
}
return ret ;
}
void
nouveau_display_fini ( struct drm_device * dev )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct nouveau_display_engine * disp = & dev_priv - > engine . display ;
2011-11-24 06:59:44 +04:00
struct drm_connector * connector ;
/* disable hotplug interrupts */
list_for_each_entry ( connector , & dev - > mode_config . connector_list , head ) {
struct nouveau_connector * conn = nouveau_connector ( connector ) ;
nouveau_gpio_irq ( dev , 0 , conn - > hpd , 0xff , false ) ;
}
2011-11-09 09:18:47 +04:00
drm_kms_helper_poll_disable ( dev ) ;
disp - > fini ( dev ) ;
}
2011-10-06 06:46:40 +04:00
int
nouveau_display_create ( struct drm_device * dev )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct nouveau_display_engine * disp = & dev_priv - > engine . display ;
2011-10-17 06:23:41 +04:00
int ret , gen ;
2011-10-06 06:46:40 +04:00
drm_mode_config_init ( dev ) ;
drm_mode_create_scaling_mode_property ( dev ) ;
2011-10-14 17:55:47 +04:00
drm_mode_create_dvi_i_properties ( dev ) ;
2011-10-17 06:23:41 +04:00
if ( dev_priv - > card_type < NV_50 )
gen = 0 ;
else
if ( dev_priv - > card_type < NV_D0 )
gen = 1 ;
else
gen = 2 ;
PROP_ENUM ( disp - > dithering_mode , gen , " dithering mode " , dither_mode ) ;
PROP_ENUM ( disp - > dithering_depth , gen , " dithering depth " , dither_depth ) ;
PROP_ENUM ( disp - > underscan_property , gen , " underscan " , underscan ) ;
2011-10-06 07:29:05 +04:00
disp - > underscan_hborder_property =
2012-02-06 13:58:18 +04:00
drm_property_create_range ( dev , 0 , " underscan hborder " , 0 , 128 ) ;
2011-10-06 07:29:05 +04:00
disp - > underscan_vborder_property =
2012-02-06 13:58:18 +04:00
drm_property_create_range ( dev , 0 , " underscan vborder " , 0 , 128 ) ;
2011-10-06 07:29:05 +04:00
2011-10-06 06:46:40 +04:00
dev - > mode_config . funcs = ( void * ) & nouveau_mode_config_funcs ;
dev - > mode_config . fb_base = pci_resource_start ( dev - > pdev , 1 ) ;
dev - > mode_config . min_width = 0 ;
dev - > mode_config . min_height = 0 ;
if ( dev_priv - > card_type < NV_10 ) {
dev - > mode_config . max_width = 2048 ;
dev - > mode_config . max_height = 2048 ;
} else
if ( dev_priv - > card_type < NV_50 ) {
dev - > mode_config . max_width = 4096 ;
dev - > mode_config . max_height = 4096 ;
} else {
dev - > mode_config . max_width = 8192 ;
dev - > mode_config . max_height = 8192 ;
}
2011-11-09 09:18:47 +04:00
drm_kms_helper_poll_init ( dev ) ;
drm_kms_helper_poll_disable ( dev ) ;
2011-10-06 06:46:40 +04:00
ret = disp - > create ( dev ) ;
if ( ret )
return ret ;
2011-11-09 09:18:47 +04:00
if ( dev - > mode_config . num_crtc ) {
ret = drm_vblank_init ( dev , dev - > mode_config . num_crtc ) ;
if ( ret )
return ret ;
}
2011-11-09 05:36:33 +04:00
return ret ;
2011-10-06 06:46:40 +04:00
}
void
nouveau_display_destroy ( struct drm_device * dev )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct nouveau_display_engine * disp = & dev_priv - > engine . display ;
2011-11-09 09:18:47 +04:00
drm_vblank_cleanup ( dev ) ;
2011-10-06 06:46:40 +04:00
disp - > destroy ( dev ) ;
2011-11-09 09:18:47 +04:00
drm_kms_helper_poll_fini ( dev ) ;
2011-10-06 06:46:40 +04:00
drm_mode_config_cleanup ( dev ) ;
}
2010-10-21 20:19:29 +04:00
int
nouveau_vblank_enable ( struct drm_device * dev , int crtc )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
if ( dev_priv - > card_type > = NV_50 )
nv_mask ( dev , NV50_PDISPLAY_INTR_EN_1 , 0 ,
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_ ( crtc ) ) ;
else
NVWriteCRTC ( dev , crtc , NV_PCRTC_INTR_EN_0 ,
NV_PCRTC_INTR_0_VBLANK ) ;
return 0 ;
}
void
nouveau_vblank_disable ( struct drm_device * dev , int crtc )
{
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
if ( dev_priv - > card_type > = NV_50 )
nv_mask ( dev , NV50_PDISPLAY_INTR_EN_1 ,
NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_ ( crtc ) , 0 ) ;
else
NVWriteCRTC ( dev , crtc , NV_PCRTC_INTR_EN_0 , 0 ) ;
}
2010-10-21 01:35:40 +04:00
static int
nouveau_page_flip_reserve ( struct nouveau_bo * old_bo ,
struct nouveau_bo * new_bo )
{
int ret ;
ret = nouveau_bo_pin ( new_bo , TTM_PL_FLAG_VRAM ) ;
if ( ret )
return ret ;
ret = ttm_bo_reserve ( & new_bo - > bo , false , false , false , 0 ) ;
if ( ret )
goto fail ;
ret = ttm_bo_reserve ( & old_bo - > bo , false , false , false , 0 ) ;
if ( ret )
goto fail_unreserve ;
return 0 ;
fail_unreserve :
ttm_bo_unreserve ( & new_bo - > bo ) ;
fail :
nouveau_bo_unpin ( new_bo ) ;
return ret ;
}
static void
nouveau_page_flip_unreserve ( struct nouveau_bo * old_bo ,
struct nouveau_bo * new_bo ,
struct nouveau_fence * fence )
{
nouveau_bo_fence ( new_bo , fence ) ;
ttm_bo_unreserve ( & new_bo - > bo ) ;
nouveau_bo_fence ( old_bo , fence ) ;
ttm_bo_unreserve ( & old_bo - > bo ) ;
nouveau_bo_unpin ( old_bo ) ;
}
static int
nouveau_page_flip_emit ( struct nouveau_channel * chan ,
struct nouveau_bo * old_bo ,
struct nouveau_bo * new_bo ,
struct nouveau_page_flip_state * s ,
struct nouveau_fence * * pfence )
{
2011-02-08 08:16:23 +03:00
struct drm_nouveau_private * dev_priv = chan - > dev - > dev_private ;
2010-10-21 01:35:40 +04:00
struct drm_device * dev = chan - > dev ;
unsigned long flags ;
int ret ;
/* Queue it to the pending list */
spin_lock_irqsave ( & dev - > event_lock , flags ) ;
list_add_tail ( & s - > head , & chan - > nvsw . flip ) ;
spin_unlock_irqrestore ( & dev - > event_lock , flags ) ;
/* Synchronize with the old framebuffer */
ret = nouveau_fence_sync ( old_bo - > bo . sync_obj , chan ) ;
if ( ret )
goto fail ;
/* Emit the pageflip */
ret = RING_SPACE ( chan , 2 ) ;
if ( ret )
goto fail ;
2011-02-08 08:16:23 +03:00
if ( dev_priv - > card_type < NV_C0 )
BEGIN_RING ( chan , NvSubSw , NV_SW_PAGE_FLIP , 1 ) ;
else
BEGIN_NVC0 ( chan , 2 , NvSubM2MF , 0x0500 , 1 ) ;
OUT_RING ( chan , 0 ) ;
FIRE_RING ( chan ) ;
2010-10-21 01:35:40 +04:00
ret = nouveau_fence_new ( chan , pfence , true ) ;
if ( ret )
goto fail ;
return 0 ;
fail :
spin_lock_irqsave ( & dev - > event_lock , flags ) ;
list_del ( & s - > head ) ;
spin_unlock_irqrestore ( & dev - > event_lock , flags ) ;
return ret ;
}
int
nouveau_crtc_page_flip ( struct drm_crtc * crtc , struct drm_framebuffer * fb ,
struct drm_pending_vblank_event * event )
{
struct drm_device * dev = crtc - > dev ;
struct drm_nouveau_private * dev_priv = dev - > dev_private ;
struct nouveau_bo * old_bo = nouveau_framebuffer ( crtc - > fb ) - > nvbo ;
struct nouveau_bo * new_bo = nouveau_framebuffer ( fb ) - > nvbo ;
struct nouveau_page_flip_state * s ;
struct nouveau_channel * chan ;
struct nouveau_fence * fence ;
int ret ;
2011-04-01 07:56:05 +04:00
if ( ! dev_priv - > channel )
2010-10-21 01:35:40 +04:00
return - ENODEV ;
s = kzalloc ( sizeof ( * s ) , GFP_KERNEL ) ;
if ( ! s )
return - ENOMEM ;
/* Don't let the buffers go away while we flip */
ret = nouveau_page_flip_reserve ( old_bo , new_bo ) ;
if ( ret )
goto fail_free ;
/* Initialize a page flip struct */
* s = ( struct nouveau_page_flip_state )
2011-02-16 12:04:48 +03:00
{ { } , event , nouveau_crtc ( crtc ) - > index ,
2011-12-20 02:06:49 +04:00
fb - > bits_per_pixel , fb - > pitches [ 0 ] , crtc - > x , crtc - > y ,
2010-10-21 01:35:40 +04:00
new_bo - > bo . offset } ;
/* Choose the channel the flip will be handled in */
chan = nouveau_fence_channel ( new_bo - > bo . sync_obj ) ;
if ( ! chan )
chan = nouveau_channel_get_unlocked ( dev_priv - > channel ) ;
mutex_lock ( & chan - > mutex ) ;
/* Emit a page flip */
2011-02-07 07:27:04 +03:00
if ( dev_priv - > card_type > = NV_50 ) {
2011-11-12 08:28:12 +04:00
if ( dev_priv - > card_type > = NV_D0 )
ret = nvd0_display_flip_next ( crtc , fb , chan , 0 ) ;
else
ret = nv50_display_flip_next ( crtc , fb , chan ) ;
2011-02-07 07:27:04 +03:00
if ( ret ) {
nouveau_channel_put ( & chan ) ;
goto fail_unreserve ;
}
}
2010-10-21 01:35:40 +04:00
ret = nouveau_page_flip_emit ( chan , old_bo , new_bo , s , & fence ) ;
nouveau_channel_put ( & chan ) ;
if ( ret )
goto fail_unreserve ;
/* Update the crtc struct and cleanup */
crtc - > fb = fb ;
nouveau_page_flip_unreserve ( old_bo , new_bo , fence ) ;
nouveau_fence_unref ( & fence ) ;
return 0 ;
fail_unreserve :
nouveau_page_flip_unreserve ( old_bo , new_bo , NULL ) ;
fail_free :
kfree ( s ) ;
return ret ;
}
int
nouveau_finish_page_flip ( struct nouveau_channel * chan ,
struct nouveau_page_flip_state * ps )
{
struct drm_device * dev = chan - > dev ;
struct nouveau_page_flip_state * s ;
unsigned long flags ;
spin_lock_irqsave ( & dev - > event_lock , flags ) ;
if ( list_empty ( & chan - > nvsw . flip ) ) {
NV_ERROR ( dev , " Unexpected pageflip in channel %d. \n " , chan - > id ) ;
spin_unlock_irqrestore ( & dev - > event_lock , flags ) ;
return - EINVAL ;
}
s = list_first_entry ( & chan - > nvsw . flip ,
struct nouveau_page_flip_state , head ) ;
if ( s - > event ) {
struct drm_pending_vblank_event * e = s - > event ;
struct timeval now ;
do_gettimeofday ( & now ) ;
e - > event . sequence = 0 ;
e - > event . tv_sec = now . tv_sec ;
e - > event . tv_usec = now . tv_usec ;
list_add_tail ( & e - > base . link , & e - > base . file_priv - > event_list ) ;
wake_up_interruptible ( & e - > base . file_priv - > event_wait ) ;
}
list_del ( & s - > head ) ;
2011-02-07 07:27:04 +03:00
if ( ps )
* ps = * s ;
2010-10-21 01:35:40 +04:00
kfree ( s ) ;
spin_unlock_irqrestore ( & dev - > event_lock , flags ) ;
return 0 ;
}
2011-09-30 02:55:50 +04:00
int
nouveau_display_dumb_create ( struct drm_file * file_priv , struct drm_device * dev ,
struct drm_mode_create_dumb * args )
{
struct nouveau_bo * bo ;
int ret ;
args - > pitch = roundup ( args - > width * ( args - > bpp / 8 ) , 256 ) ;
args - > size = args - > pitch * args - > height ;
args - > size = roundup ( args - > size , PAGE_SIZE ) ;
ret = nouveau_gem_new ( dev , args - > size , 0 , TTM_PL_FLAG_VRAM , 0 , 0 , & bo ) ;
if ( ret )
return ret ;
ret = drm_gem_handle_create ( file_priv , bo - > gem , & args - > handle ) ;
drm_gem_object_unreference_unlocked ( bo - > gem ) ;
return ret ;
}
int
nouveau_display_dumb_destroy ( struct drm_file * file_priv , struct drm_device * dev ,
uint32_t handle )
{
return drm_gem_handle_delete ( file_priv , handle ) ;
}
int
nouveau_display_dumb_map_offset ( struct drm_file * file_priv ,
struct drm_device * dev ,
uint32_t handle , uint64_t * poffset )
{
struct drm_gem_object * gem ;
gem = drm_gem_object_lookup ( dev , file_priv , handle ) ;
if ( gem ) {
struct nouveau_bo * bo = gem - > driver_private ;
* poffset = bo - > bo . addr_space_offset ;
drm_gem_object_unreference_unlocked ( gem ) ;
return 0 ;
}
return - ENOENT ;
}