2012-11-15 21:28:22 +00:00
/*
* Copyright ( C ) 2012 Avionic Design GmbH
2013-03-22 16:34:09 +02:00
* Copyright ( C ) 2012 - 2013 NVIDIA CORPORATION . All rights reserved .
2012-11-15 21:28:22 +00:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
2013-10-14 14:43:22 +02:00
# include <linux/host1x.h>
2012-11-15 21:28:22 +00:00
# include "drm.h"
2013-03-22 16:34:08 +02:00
# include "gem.h"
2012-11-15 21:28:22 +00:00
# define DRIVER_NAME "tegra"
# define DRIVER_DESC "NVIDIA Tegra graphics"
# define DRIVER_DATE "20120330"
# define DRIVER_MAJOR 0
# define DRIVER_MINOR 0
# define DRIVER_PATCHLEVEL 0
2013-09-26 16:08:18 +02:00
struct tegra_drm_file {
struct list_head contexts ;
} ;
2013-10-14 14:43:22 +02:00
static int tegra_drm_load ( struct drm_device * drm , unsigned long flags )
2013-03-22 16:34:07 +02:00
{
2013-10-14 14:43:22 +02:00
struct host1x_device * device = to_host1x_device ( drm - > dev ) ;
2013-09-24 13:22:17 +02:00
struct tegra_drm * tegra ;
2013-03-22 16:34:07 +02:00
int err ;
2013-10-14 14:43:22 +02:00
tegra = kzalloc ( sizeof ( * tegra ) , GFP_KERNEL ) ;
2013-09-24 13:22:17 +02:00
if ( ! tegra )
2013-03-22 16:34:07 +02:00
return - ENOMEM ;
2013-10-14 14:43:22 +02:00
dev_set_drvdata ( drm - > dev , tegra ) ;
2013-09-24 13:22:17 +02:00
mutex_init ( & tegra - > clients_lock ) ;
INIT_LIST_HEAD ( & tegra - > clients ) ;
drm - > dev_private = tegra ;
tegra - > drm = drm ;
2012-11-15 21:28:22 +00:00
drm_mode_config_init ( drm ) ;
2013-10-14 14:43:22 +02:00
err = host1x_device_init ( device ) ;
2012-11-15 21:28:22 +00:00
if ( err < 0 )
return err ;
2013-04-22 21:22:14 +02:00
/*
* We don ' t use the drm_irq_install ( ) helpers provided by the DRM
* core , so we need to set this manually in order to allow the
* DRM_IOCTL_WAIT_VBLANK to operate correctly .
*/
2013-10-04 14:53:37 +03:00
drm - > irq_enabled = true ;
2013-04-22 21:22:14 +02:00
2012-11-28 11:45:47 +01:00
err = drm_vblank_init ( drm , drm - > mode_config . num_crtc ) ;
if ( err < 0 )
return err ;
2012-11-15 21:28:22 +00:00
err = tegra_drm_fb_init ( drm ) ;
if ( err < 0 )
return err ;
drm_kms_helper_poll_init ( drm ) ;
return 0 ;
}
static int tegra_drm_unload ( struct drm_device * drm )
{
2013-10-14 14:43:22 +02:00
struct host1x_device * device = to_host1x_device ( drm - > dev ) ;
int err ;
2012-11-15 21:28:22 +00:00
drm_kms_helper_poll_fini ( drm ) ;
tegra_drm_fb_exit ( drm ) ;
2013-10-14 14:06:02 +02:00
drm_vblank_cleanup ( drm ) ;
drm_mode_config_cleanup ( drm ) ;
2012-11-15 21:28:22 +00:00
2013-10-14 14:43:22 +02:00
err = host1x_device_exit ( device ) ;
if ( err < 0 )
return err ;
2012-11-15 21:28:22 +00:00
return 0 ;
}
static int tegra_drm_open ( struct drm_device * drm , struct drm_file * filp )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv ;
2013-03-22 16:34:09 +02:00
fpriv = kzalloc ( sizeof ( * fpriv ) , GFP_KERNEL ) ;
if ( ! fpriv )
return - ENOMEM ;
INIT_LIST_HEAD ( & fpriv - > contexts ) ;
filp - > driver_priv = fpriv ;
2012-11-15 21:28:22 +00:00
return 0 ;
}
2013-09-26 16:08:22 +02:00
static void tegra_drm_context_free ( struct tegra_drm_context * context )
2013-03-22 16:34:09 +02:00
{
context - > client - > ops - > close_channel ( context ) ;
kfree ( context ) ;
}
2012-11-15 21:28:22 +00:00
static void tegra_drm_lastclose ( struct drm_device * drm )
{
2013-09-24 13:22:17 +02:00
struct tegra_drm * tegra = drm - > dev_private ;
2012-11-15 21:28:22 +00:00
2013-09-24 13:22:17 +02:00
tegra_fbdev_restore_mode ( tegra - > fbdev ) ;
2012-11-15 21:28:22 +00:00
}
2013-10-10 11:00:33 +02:00
static struct host1x_bo *
host1x_bo_lookup ( struct drm_device * drm , struct drm_file * file , u32 handle )
{
struct drm_gem_object * gem ;
struct tegra_bo * bo ;
gem = drm_gem_object_lookup ( drm , file , handle ) ;
if ( ! gem )
return NULL ;
mutex_lock ( & drm - > struct_mutex ) ;
drm_gem_object_unreference ( gem ) ;
mutex_unlock ( & drm - > struct_mutex ) ;
bo = to_tegra_bo ( gem ) ;
return & bo - > base ;
}
int tegra_drm_submit ( struct tegra_drm_context * context ,
struct drm_tegra_submit * args , struct drm_device * drm ,
struct drm_file * file )
{
unsigned int num_cmdbufs = args - > num_cmdbufs ;
unsigned int num_relocs = args - > num_relocs ;
unsigned int num_waitchks = args - > num_waitchks ;
struct drm_tegra_cmdbuf __user * cmdbufs =
2013-11-08 13:15:43 +01:00
( void __user * ) ( uintptr_t ) args - > cmdbufs ;
2013-10-10 11:00:33 +02:00
struct drm_tegra_reloc __user * relocs =
2013-11-08 13:15:43 +01:00
( void __user * ) ( uintptr_t ) args - > relocs ;
2013-10-10 11:00:33 +02:00
struct drm_tegra_waitchk __user * waitchks =
2013-11-08 13:15:43 +01:00
( void __user * ) ( uintptr_t ) args - > waitchks ;
2013-10-10 11:00:33 +02:00
struct drm_tegra_syncpt syncpt ;
struct host1x_job * job ;
int err ;
/* We don't yet support other than one syncpt_incr struct per submit */
if ( args - > num_syncpts ! = 1 )
return - EINVAL ;
job = host1x_job_alloc ( context - > channel , args - > num_cmdbufs ,
args - > num_relocs , args - > num_waitchks ) ;
if ( ! job )
return - ENOMEM ;
job - > num_relocs = args - > num_relocs ;
job - > num_waitchk = args - > num_waitchks ;
job - > client = ( u32 ) args - > context ;
job - > class = context - > client - > base . class ;
job - > serialize = true ;
while ( num_cmdbufs ) {
struct drm_tegra_cmdbuf cmdbuf ;
struct host1x_bo * bo ;
err = copy_from_user ( & cmdbuf , cmdbufs , sizeof ( cmdbuf ) ) ;
if ( err )
goto fail ;
bo = host1x_bo_lookup ( drm , file , cmdbuf . handle ) ;
if ( ! bo ) {
err = - ENOENT ;
goto fail ;
}
host1x_job_add_gather ( job , bo , cmdbuf . words , cmdbuf . offset ) ;
num_cmdbufs - - ;
cmdbufs + + ;
}
err = copy_from_user ( job - > relocarray , relocs ,
sizeof ( * relocs ) * num_relocs ) ;
if ( err )
goto fail ;
while ( num_relocs - - ) {
struct host1x_reloc * reloc = & job - > relocarray [ num_relocs ] ;
struct host1x_bo * cmdbuf , * target ;
cmdbuf = host1x_bo_lookup ( drm , file , ( u32 ) reloc - > cmdbuf ) ;
target = host1x_bo_lookup ( drm , file , ( u32 ) reloc - > target ) ;
reloc - > cmdbuf = cmdbuf ;
reloc - > target = target ;
if ( ! reloc - > target | | ! reloc - > cmdbuf ) {
err = - ENOENT ;
goto fail ;
}
}
err = copy_from_user ( job - > waitchk , waitchks ,
sizeof ( * waitchks ) * num_waitchks ) ;
if ( err )
goto fail ;
2013-11-08 13:15:43 +01:00
err = copy_from_user ( & syncpt , ( void __user * ) ( uintptr_t ) args - > syncpts ,
2013-10-10 11:00:33 +02:00
sizeof ( syncpt ) ) ;
if ( err )
goto fail ;
job - > is_addr_reg = context - > client - > ops - > is_addr_reg ;
job - > syncpt_incrs = syncpt . incrs ;
job - > syncpt_id = syncpt . id ;
job - > timeout = 10000 ;
if ( args - > timeout & & args - > timeout < 10000 )
job - > timeout = args - > timeout ;
err = host1x_job_pin ( job , context - > client - > base . dev ) ;
if ( err )
goto fail ;
err = host1x_job_submit ( job ) ;
if ( err )
goto fail_submit ;
args - > fence = job - > syncpt_end ;
host1x_job_put ( job ) ;
return 0 ;
fail_submit :
host1x_job_unpin ( job ) ;
fail :
host1x_job_put ( job ) ;
return err ;
}
2013-03-22 16:34:09 +02:00
# ifdef CONFIG_DRM_TEGRA_STAGING
2013-09-26 16:08:22 +02:00
static struct tegra_drm_context * tegra_drm_get_context ( __u64 context )
{
return ( struct tegra_drm_context * ) ( uintptr_t ) context ;
}
2013-09-26 16:08:18 +02:00
static bool tegra_drm_file_owns_context ( struct tegra_drm_file * file ,
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context )
2013-03-22 16:34:09 +02:00
{
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * ctx ;
2013-03-22 16:34:09 +02:00
list_for_each_entry ( ctx , & file - > contexts , list )
if ( ctx = = context )
return true ;
return false ;
}
static int tegra_gem_create ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
struct drm_tegra_gem_create * args = data ;
struct tegra_bo * bo ;
2013-10-04 22:34:01 +02:00
bo = tegra_bo_create_with_handle ( file , drm , args - > size , args - > flags ,
2013-03-22 16:34:09 +02:00
& args - > handle ) ;
if ( IS_ERR ( bo ) )
return PTR_ERR ( bo ) ;
return 0 ;
}
static int tegra_gem_mmap ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
struct drm_tegra_gem_mmap * args = data ;
struct drm_gem_object * gem ;
struct tegra_bo * bo ;
gem = drm_gem_object_lookup ( drm , file , args - > handle ) ;
if ( ! gem )
return - EINVAL ;
bo = to_tegra_bo ( gem ) ;
2013-08-13 14:19:58 +02:00
args - > offset = drm_vma_node_offset_addr ( & bo - > gem . vma_node ) ;
2013-03-22 16:34:09 +02:00
drm_gem_object_unreference ( gem ) ;
return 0 ;
}
static int tegra_syncpt_read ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-10-14 14:43:22 +02:00
struct host1x * host = dev_get_drvdata ( drm - > dev - > parent ) ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_syncpt_read * args = data ;
2013-10-14 14:43:22 +02:00
struct host1x_syncpt * sp ;
2013-03-22 16:34:09 +02:00
2013-10-14 14:43:22 +02:00
sp = host1x_syncpt_get ( host , args - > id ) ;
2013-03-22 16:34:09 +02:00
if ( ! sp )
return - EINVAL ;
args - > value = host1x_syncpt_read_min ( sp ) ;
return 0 ;
}
static int tegra_syncpt_incr ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-10-14 14:43:22 +02:00
struct host1x * host1x = dev_get_drvdata ( drm - > dev - > parent ) ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_syncpt_incr * args = data ;
2013-10-14 14:43:22 +02:00
struct host1x_syncpt * sp ;
2013-03-22 16:34:09 +02:00
2013-10-14 14:43:22 +02:00
sp = host1x_syncpt_get ( host1x , args - > id ) ;
2013-03-22 16:34:09 +02:00
if ( ! sp )
return - EINVAL ;
2013-05-29 13:26:08 +03:00
return host1x_syncpt_incr ( sp ) ;
2013-03-22 16:34:09 +02:00
}
static int tegra_syncpt_wait ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-10-14 14:43:22 +02:00
struct host1x * host1x = dev_get_drvdata ( drm - > dev - > parent ) ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_syncpt_wait * args = data ;
2013-10-14 14:43:22 +02:00
struct host1x_syncpt * sp ;
2013-03-22 16:34:09 +02:00
2013-10-14 14:43:22 +02:00
sp = host1x_syncpt_get ( host1x , args - > id ) ;
2013-03-22 16:34:09 +02:00
if ( ! sp )
return - EINVAL ;
return host1x_syncpt_wait ( sp , args - > thresh , args - > timeout ,
& args - > value ) ;
}
static int tegra_open_channel ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv = file - > driver_priv ;
2013-09-24 13:22:17 +02:00
struct tegra_drm * tegra = drm - > dev_private ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_open_channel * args = data ;
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context ;
2013-09-24 15:35:40 +02:00
struct tegra_drm_client * client ;
2013-03-22 16:34:09 +02:00
int err = - ENODEV ;
context = kzalloc ( sizeof ( * context ) , GFP_KERNEL ) ;
if ( ! context )
return - ENOMEM ;
2013-10-14 14:43:22 +02:00
list_for_each_entry ( client , & tegra - > clients , list )
2013-09-24 15:35:40 +02:00
if ( client - > base . class = = args - > client ) {
2013-03-22 16:34:09 +02:00
err = client - > ops - > open_channel ( client , context ) ;
if ( err )
break ;
list_add ( & context - > list , & fpriv - > contexts ) ;
args - > context = ( uintptr_t ) context ;
2013-09-24 15:35:40 +02:00
context - > client = client ;
2013-03-22 16:34:09 +02:00
return 0 ;
}
kfree ( context ) ;
return err ;
}
static int tegra_close_channel ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv = file - > driver_priv ;
2013-10-14 14:43:22 +02:00
struct drm_tegra_close_channel * args = data ;
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context ;
context = tegra_drm_get_context ( args - > context ) ;
2013-03-22 16:34:09 +02:00
2013-09-26 16:08:18 +02:00
if ( ! tegra_drm_file_owns_context ( fpriv , context ) )
2013-03-22 16:34:09 +02:00
return - EINVAL ;
list_del ( & context - > list ) ;
2013-09-26 16:08:22 +02:00
tegra_drm_context_free ( context ) ;
2013-03-22 16:34:09 +02:00
return 0 ;
}
static int tegra_get_syncpt ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv = file - > driver_priv ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_get_syncpt * args = data ;
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context ;
2013-03-22 16:34:09 +02:00
struct host1x_syncpt * syncpt ;
2013-09-26 16:08:22 +02:00
context = tegra_drm_get_context ( args - > context ) ;
2013-09-26 16:08:18 +02:00
if ( ! tegra_drm_file_owns_context ( fpriv , context ) )
2013-03-22 16:34:09 +02:00
return - ENODEV ;
2013-09-24 15:35:40 +02:00
if ( args - > index > = context - > client - > base . num_syncpts )
2013-03-22 16:34:09 +02:00
return - EINVAL ;
2013-09-24 15:35:40 +02:00
syncpt = context - > client - > base . syncpts [ args - > index ] ;
2013-03-22 16:34:09 +02:00
args - > id = host1x_syncpt_id ( syncpt ) ;
return 0 ;
}
static int tegra_submit ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv = file - > driver_priv ;
2013-03-22 16:34:09 +02:00
struct drm_tegra_submit * args = data ;
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context ;
context = tegra_drm_get_context ( args - > context ) ;
2013-03-22 16:34:09 +02:00
2013-09-26 16:08:18 +02:00
if ( ! tegra_drm_file_owns_context ( fpriv , context ) )
2013-03-22 16:34:09 +02:00
return - ENODEV ;
return context - > client - > ops - > submit ( context , args , drm , file ) ;
}
2013-10-14 15:21:54 +03:00
static int tegra_get_syncpt_base ( struct drm_device * drm , void * data ,
struct drm_file * file )
{
struct tegra_drm_file * fpriv = file - > driver_priv ;
struct drm_tegra_get_syncpt_base * args = data ;
struct tegra_drm_context * context ;
struct host1x_syncpt_base * base ;
struct host1x_syncpt * syncpt ;
context = tegra_drm_get_context ( args - > context ) ;
if ( ! tegra_drm_file_owns_context ( fpriv , context ) )
return - ENODEV ;
if ( args - > syncpt > = context - > client - > base . num_syncpts )
return - EINVAL ;
syncpt = context - > client - > base . syncpts [ args - > syncpt ] ;
base = host1x_syncpt_get_base ( syncpt ) ;
if ( ! base )
return - ENXIO ;
args - > id = host1x_syncpt_base_id ( base ) ;
return 0 ;
}
2013-03-22 16:34:09 +02:00
# endif
2013-08-02 13:27:49 -04:00
static const struct drm_ioctl_desc tegra_drm_ioctls [ ] = {
2013-03-22 16:34:09 +02:00
# ifdef CONFIG_DRM_TEGRA_STAGING
DRM_IOCTL_DEF_DRV ( TEGRA_GEM_CREATE , tegra_gem_create , DRM_UNLOCKED | DRM_AUTH ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_GEM_MMAP , tegra_gem_mmap , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_SYNCPT_READ , tegra_syncpt_read , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_SYNCPT_INCR , tegra_syncpt_incr , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_SYNCPT_WAIT , tegra_syncpt_wait , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_OPEN_CHANNEL , tegra_open_channel , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_CLOSE_CHANNEL , tegra_close_channel , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_GET_SYNCPT , tegra_get_syncpt , DRM_UNLOCKED ) ,
DRM_IOCTL_DEF_DRV ( TEGRA_SUBMIT , tegra_submit , DRM_UNLOCKED ) ,
2013-10-14 15:21:54 +03:00
DRM_IOCTL_DEF_DRV ( TEGRA_GET_SYNCPT_BASE , tegra_get_syncpt_base , DRM_UNLOCKED ) ,
2013-03-22 16:34:09 +02:00
# endif
2012-11-15 21:28:22 +00:00
} ;
static const struct file_operations tegra_drm_fops = {
. owner = THIS_MODULE ,
. open = drm_open ,
. release = drm_release ,
. unlocked_ioctl = drm_ioctl ,
2013-03-22 16:34:08 +02:00
. mmap = tegra_drm_mmap ,
2012-11-15 21:28:22 +00:00
. poll = drm_poll ,
. read = drm_read ,
# ifdef CONFIG_COMPAT
. compat_ioctl = drm_compat_ioctl ,
# endif
. llseek = noop_llseek ,
} ;
2012-11-28 11:45:47 +01:00
static struct drm_crtc * tegra_crtc_from_pipe ( struct drm_device * drm , int pipe )
{
struct drm_crtc * crtc ;
list_for_each_entry ( crtc , & drm - > mode_config . crtc_list , head ) {
struct tegra_dc * dc = to_tegra_dc ( crtc ) ;
if ( dc - > pipe = = pipe )
return crtc ;
}
return NULL ;
}
static u32 tegra_drm_get_vblank_counter ( struct drm_device * dev , int crtc )
{
/* TODO: implement real hardware counter using syncpoints */
return drm_vblank_count ( dev , crtc ) ;
}
static int tegra_drm_enable_vblank ( struct drm_device * drm , int pipe )
{
struct drm_crtc * crtc = tegra_crtc_from_pipe ( drm , pipe ) ;
struct tegra_dc * dc = to_tegra_dc ( crtc ) ;
if ( ! crtc )
return - ENODEV ;
tegra_dc_enable_vblank ( dc ) ;
return 0 ;
}
static void tegra_drm_disable_vblank ( struct drm_device * drm , int pipe )
{
struct drm_crtc * crtc = tegra_crtc_from_pipe ( drm , pipe ) ;
struct tegra_dc * dc = to_tegra_dc ( crtc ) ;
if ( crtc )
tegra_dc_disable_vblank ( dc ) ;
}
2012-11-28 12:00:18 +01:00
static void tegra_drm_preclose ( struct drm_device * drm , struct drm_file * file )
{
2013-09-26 16:08:18 +02:00
struct tegra_drm_file * fpriv = file - > driver_priv ;
2013-09-26 16:08:22 +02:00
struct tegra_drm_context * context , * tmp ;
2012-11-28 12:00:18 +01:00
struct drm_crtc * crtc ;
list_for_each_entry ( crtc , & drm - > mode_config . crtc_list , head )
tegra_dc_cancel_page_flip ( crtc , file ) ;
2013-03-22 16:34:09 +02:00
list_for_each_entry_safe ( context , tmp , & fpriv - > contexts , list )
2013-09-26 16:08:22 +02:00
tegra_drm_context_free ( context ) ;
2013-03-22 16:34:09 +02:00
kfree ( fpriv ) ;
2012-11-28 12:00:18 +01:00
}
2013-02-13 16:13:16 +01:00
# ifdef CONFIG_DEBUG_FS
static int tegra_debugfs_framebuffers ( struct seq_file * s , void * data )
{
struct drm_info_node * node = ( struct drm_info_node * ) s - > private ;
struct drm_device * drm = node - > minor - > dev ;
struct drm_framebuffer * fb ;
mutex_lock ( & drm - > mode_config . fb_lock ) ;
list_for_each_entry ( fb , & drm - > mode_config . fb_list , head ) {
seq_printf ( s , " %3d: user size: %d x %d, depth %d, %d bpp, refcount %d \n " ,
fb - > base . id , fb - > width , fb - > height , fb - > depth ,
fb - > bits_per_pixel ,
atomic_read ( & fb - > refcount . refcount ) ) ;
}
mutex_unlock ( & drm - > mode_config . fb_lock ) ;
return 0 ;
}
static struct drm_info_list tegra_debugfs_list [ ] = {
{ " framebuffers " , tegra_debugfs_framebuffers , 0 } ,
} ;
static int tegra_debugfs_init ( struct drm_minor * minor )
{
return drm_debugfs_create_files ( tegra_debugfs_list ,
ARRAY_SIZE ( tegra_debugfs_list ) ,
minor - > debugfs_root , minor ) ;
}
static void tegra_debugfs_cleanup ( struct drm_minor * minor )
{
drm_debugfs_remove_files ( tegra_debugfs_list ,
ARRAY_SIZE ( tegra_debugfs_list ) , minor ) ;
}
# endif
2013-11-08 13:17:14 +01:00
static struct drm_driver tegra_drm_driver = {
2013-05-29 07:44:34 +02:00
. driver_features = DRIVER_MODESET | DRIVER_GEM ,
2012-11-15 21:28:22 +00:00
. load = tegra_drm_load ,
. unload = tegra_drm_unload ,
. open = tegra_drm_open ,
2012-11-28 12:00:18 +01:00
. preclose = tegra_drm_preclose ,
2012-11-15 21:28:22 +00:00
. lastclose = tegra_drm_lastclose ,
2012-11-28 11:45:47 +01:00
. get_vblank_counter = tegra_drm_get_vblank_counter ,
. enable_vblank = tegra_drm_enable_vblank ,
. disable_vblank = tegra_drm_disable_vblank ,
2013-02-13 16:13:16 +01:00
# if defined(CONFIG_DEBUG_FS)
. debugfs_init = tegra_debugfs_init ,
. debugfs_cleanup = tegra_debugfs_cleanup ,
# endif
2013-03-22 16:34:08 +02:00
. gem_free_object = tegra_bo_free_object ,
. gem_vm_ops = & tegra_bo_vm_ops ,
. dumb_create = tegra_bo_dumb_create ,
. dumb_map_offset = tegra_bo_dumb_map_offset ,
2013-07-16 09:12:04 +02:00
. dumb_destroy = drm_gem_dumb_destroy ,
2012-11-15 21:28:22 +00:00
. ioctls = tegra_drm_ioctls ,
. num_ioctls = ARRAY_SIZE ( tegra_drm_ioctls ) ,
. fops = & tegra_drm_fops ,
. name = DRIVER_NAME ,
. desc = DRIVER_DESC ,
. date = DRIVER_DATE ,
. major = DRIVER_MAJOR ,
. minor = DRIVER_MINOR ,
. patchlevel = DRIVER_PATCHLEVEL ,
} ;
2013-10-14 14:43:22 +02:00
int tegra_drm_register_client ( struct tegra_drm * tegra ,
struct tegra_drm_client * client )
{
mutex_lock ( & tegra - > clients_lock ) ;
list_add_tail ( & client - > list , & tegra - > clients ) ;
mutex_unlock ( & tegra - > clients_lock ) ;
return 0 ;
}
int tegra_drm_unregister_client ( struct tegra_drm * tegra ,
struct tegra_drm_client * client )
{
mutex_lock ( & tegra - > clients_lock ) ;
list_del_init ( & client - > list ) ;
mutex_unlock ( & tegra - > clients_lock ) ;
return 0 ;
}
static int host1x_drm_probe ( struct host1x_device * device )
{
return drm_host1x_init ( & tegra_drm_driver , device ) ;
}
static int host1x_drm_remove ( struct host1x_device * device )
{
drm_host1x_exit ( & tegra_drm_driver , device ) ;
return 0 ;
}
static const struct of_device_id host1x_drm_subdevs [ ] = {
{ . compatible = " nvidia,tegra20-dc " , } ,
{ . compatible = " nvidia,tegra20-hdmi " , } ,
{ . compatible = " nvidia,tegra20-gr2d " , } ,
2013-02-28 08:08:01 +01:00
{ . compatible = " nvidia,tegra20-gr3d " , } ,
2013-10-14 14:43:22 +02:00
{ . compatible = " nvidia,tegra30-dc " , } ,
{ . compatible = " nvidia,tegra30-hdmi " , } ,
{ . compatible = " nvidia,tegra30-gr2d " , } ,
2013-02-28 08:08:01 +01:00
{ . compatible = " nvidia,tegra30-gr3d " , } ,
2013-09-30 16:54:47 +02:00
{ . compatible = " nvidia,tegra114-hdmi " , } ,
2013-02-28 08:08:01 +01:00
{ . compatible = " nvidia,tegra114-gr3d " , } ,
2013-10-14 14:43:22 +02:00
{ /* sentinel */ }
} ;
static struct host1x_driver host1x_drm_driver = {
. name = " drm " ,
. probe = host1x_drm_probe ,
. remove = host1x_drm_remove ,
. subdevs = host1x_drm_subdevs ,
} ;
static int __init host1x_drm_init ( void )
{
int err ;
err = host1x_driver_register ( & host1x_drm_driver ) ;
if ( err < 0 )
return err ;
err = platform_driver_register ( & tegra_dc_driver ) ;
if ( err < 0 )
goto unregister_host1x ;
err = platform_driver_register ( & tegra_hdmi_driver ) ;
if ( err < 0 )
goto unregister_dc ;
err = platform_driver_register ( & tegra_gr2d_driver ) ;
if ( err < 0 )
goto unregister_hdmi ;
2013-02-28 08:08:01 +01:00
err = platform_driver_register ( & tegra_gr3d_driver ) ;
if ( err < 0 )
goto unregister_gr2d ;
2013-10-14 14:43:22 +02:00
return 0 ;
2013-02-28 08:08:01 +01:00
unregister_gr2d :
platform_driver_unregister ( & tegra_gr2d_driver ) ;
2013-10-14 14:43:22 +02:00
unregister_hdmi :
platform_driver_unregister ( & tegra_hdmi_driver ) ;
unregister_dc :
platform_driver_unregister ( & tegra_dc_driver ) ;
unregister_host1x :
host1x_driver_unregister ( & host1x_drm_driver ) ;
return err ;
}
module_init ( host1x_drm_init ) ;
static void __exit host1x_drm_exit ( void )
{
2013-02-28 08:08:01 +01:00
platform_driver_unregister ( & tegra_gr3d_driver ) ;
2013-10-14 14:43:22 +02:00
platform_driver_unregister ( & tegra_gr2d_driver ) ;
platform_driver_unregister ( & tegra_hdmi_driver ) ;
platform_driver_unregister ( & tegra_dc_driver ) ;
host1x_driver_unregister ( & host1x_drm_driver ) ;
}
module_exit ( host1x_drm_exit ) ;
MODULE_AUTHOR ( " Thierry Reding <thierry.reding@avionic-design.de> " ) ;
MODULE_DESCRIPTION ( " NVIDIA Tegra DRM driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;