2012-03-21 10:55:26 +09:00
/* exynos_drm_vidi.c
*
* Copyright ( C ) 2012 Samsung Electronics Co . Ltd
* Authors :
* Inki Dae < inki . dae @ samsung . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
2012-03-21 10:55:26 +09:00
# include <linux/kernel.h>
# include <linux/platform_device.h>
# include <drm/exynos_drm.h>
2012-10-02 18:01:07 +01:00
# include <drm/drm_edid.h>
# include <drm/drm_crtc_helper.h>
2012-03-21 10:55:26 +09:00
# include "exynos_drm_drv.h"
# include "exynos_drm_crtc.h"
# include "exynos_drm_encoder.h"
2013-08-13 00:46:40 +01:00
# include "exynos_drm_vidi.h"
2012-03-21 10:55:26 +09:00
/* vidi has totally three virtual windows. */
# define WINDOWS_NR 3
2014-01-30 16:19:06 -05:00
# define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev))
2012-03-21 10:55:26 +09:00
struct vidi_win_data {
unsigned int offset_x ;
unsigned int offset_y ;
unsigned int ovl_width ;
unsigned int ovl_height ;
unsigned int fb_width ;
unsigned int fb_height ;
unsigned int bpp ;
dma_addr_t dma_addr ;
unsigned int buf_offsize ;
unsigned int line_size ; /* bytes */
bool enabled ;
} ;
struct vidi_context {
2014-02-19 21:02:55 +09:00
struct drm_device * drm_dev ;
2012-03-21 10:55:26 +09:00
struct drm_crtc * crtc ;
struct vidi_win_data win_data [ WINDOWS_NR ] ;
struct edid * raw_edid ;
unsigned int clkdiv ;
unsigned int default_win ;
unsigned long irq_flags ;
unsigned int connected ;
bool vblank_on ;
bool suspended ;
2012-09-19 11:02:43 +09:00
bool direct_vblank ;
2012-03-21 10:55:26 +09:00
struct work_struct work ;
struct mutex lock ;
2014-02-19 21:02:55 +09:00
int pipe ;
2012-03-21 10:55:26 +09:00
} ;
static const char fake_edid_info [ ] = {
0x00 , 0xff , 0xff , 0xff , 0xff , 0xff , 0xff , 0x00 , 0x4c , 0x2d , 0x05 , 0x05 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x30 , 0x12 , 0x01 , 0x03 , 0x80 , 0x10 , 0x09 , 0x78 ,
0x0a , 0xee , 0x91 , 0xa3 , 0x54 , 0x4c , 0x99 , 0x26 , 0x0f , 0x50 , 0x54 , 0xbd ,
0xee , 0x00 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 ,
0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x01 , 0x66 , 0x21 , 0x50 , 0xb0 , 0x51 , 0x00 ,
0x1b , 0x30 , 0x40 , 0x70 , 0x36 , 0x00 , 0xa0 , 0x5a , 0x00 , 0x00 , 0x00 , 0x1e ,
0x01 , 0x1d , 0x00 , 0x72 , 0x51 , 0xd0 , 0x1e , 0x20 , 0x6e , 0x28 , 0x55 , 0x00 ,
0xa0 , 0x5a , 0x00 , 0x00 , 0x00 , 0x1e , 0x00 , 0x00 , 0x00 , 0xfd , 0x00 , 0x18 ,
0x4b , 0x1a , 0x44 , 0x17 , 0x00 , 0x0a , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 ,
0x00 , 0x00 , 0x00 , 0xfc , 0x00 , 0x53 , 0x41 , 0x4d , 0x53 , 0x55 , 0x4e , 0x47 ,
0x0a , 0x20 , 0x20 , 0x20 , 0x20 , 0x20 , 0x01 , 0xbc , 0x02 , 0x03 , 0x1e , 0xf1 ,
0x46 , 0x84 , 0x05 , 0x03 , 0x10 , 0x20 , 0x22 , 0x23 , 0x09 , 0x07 , 0x07 , 0x83 ,
0x01 , 0x00 , 0x00 , 0xe2 , 0x00 , 0x0f , 0x67 , 0x03 , 0x0c , 0x00 , 0x10 , 0x00 ,
0xb8 , 0x2d , 0x01 , 0x1d , 0x80 , 0x18 , 0x71 , 0x1c , 0x16 , 0x20 , 0x58 , 0x2c ,
0x25 , 0x00 , 0xa0 , 0x5a , 0x00 , 0x00 , 0x00 , 0x9e , 0x8c , 0x0a , 0xd0 , 0x8a ,
0x20 , 0xe0 , 0x2d , 0x10 , 0x10 , 0x3e , 0x96 , 0x00 , 0xa0 , 0x5a , 0x00 , 0x00 ,
0x00 , 0x18 , 0x02 , 0x3a , 0x80 , 0x18 , 0x71 , 0x38 , 0x2d , 0x40 , 0x58 , 0x2c ,
0x45 , 0x00 , 0xa0 , 0x5a , 0x00 , 0x00 , 0x00 , 0x1e , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x06
} ;
2014-02-19 21:02:55 +09:00
static bool vidi_display_is_connected ( struct exynos_drm_display * display )
2012-03-21 10:55:26 +09:00
{
2014-02-19 21:02:55 +09:00
struct vidi_context * ctx = display - > ctx ;
2012-03-21 10:55:26 +09:00
/*
* connection request would come from user side
* to do hotplug through specific ioctl .
*/
return ctx - > connected ? true : false ;
}
2014-02-19 21:02:55 +09:00
static struct edid * vidi_get_edid ( struct exynos_drm_display * display ,
2013-01-04 07:59:11 -05:00
struct drm_connector * connector )
2012-03-21 10:55:26 +09:00
{
2014-02-19 21:02:55 +09:00
struct vidi_context * ctx = display - > ctx ;
2013-01-04 07:59:11 -05:00
struct edid * edid ;
2012-03-21 10:55:26 +09:00
/*
* the edid data comes from user side and it would be set
* to ctx - > raw_edid through specific ioctl .
*/
if ( ! ctx - > raw_edid ) {
DRM_DEBUG_KMS ( " raw_edid is null. \n " ) ;
2013-01-04 07:59:11 -05:00
return ERR_PTR ( - EFAULT ) ;
2012-03-21 10:55:26 +09:00
}
2013-09-27 15:08:29 +03:00
edid = drm_edid_duplicate ( ctx - > raw_edid ) ;
2013-01-04 07:59:11 -05:00
if ( ! edid ) {
DRM_DEBUG_KMS ( " failed to allocate edid \n " ) ;
return ERR_PTR ( - ENOMEM ) ;
}
2012-03-21 10:55:26 +09:00
2013-01-04 07:59:11 -05:00
return edid ;
2012-03-21 10:55:26 +09:00
}
2014-02-19 21:02:55 +09:00
static int vidi_check_mode ( struct exynos_drm_display * display ,
struct drm_display_mode * mode )
2012-03-21 10:55:26 +09:00
{
/* TODO. */
return 0 ;
}
static struct exynos_drm_display_ops vidi_display_ops = {
. is_connected = vidi_display_is_connected ,
. get_edid = vidi_get_edid ,
2013-06-10 14:50:00 +05:30
. check_mode = vidi_check_mode ,
2012-03-21 10:55:26 +09:00
} ;
2014-02-19 21:02:55 +09:00
static struct exynos_drm_display vidi_display = {
. type = EXYNOS_DISPLAY_TYPE_VIDI ,
. ops = & vidi_display_ops ,
} ;
2014-01-30 16:19:06 -05:00
static void vidi_apply ( struct exynos_drm_manager * mgr )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
struct exynos_drm_manager_ops * mgr_ops = mgr - > ops ;
struct vidi_win_data * win_data ;
int i ;
for ( i = 0 ; i < WINDOWS_NR ; i + + ) {
win_data = & ctx - > win_data [ i ] ;
2014-01-30 16:19:02 -05:00
if ( win_data - > enabled & & ( mgr_ops & & mgr_ops - > win_commit ) )
2014-01-30 16:19:06 -05:00
mgr_ops - > win_commit ( mgr , i ) ;
2012-03-21 10:55:26 +09:00
}
if ( mgr_ops & & mgr_ops - > commit )
2014-01-30 16:19:06 -05:00
mgr_ops - > commit ( mgr ) ;
2012-03-21 10:55:26 +09:00
}
2014-01-30 16:19:06 -05:00
static void vidi_commit ( struct exynos_drm_manager * mgr )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
if ( ctx - > suspended )
return ;
}
2014-01-30 16:19:06 -05:00
static int vidi_enable_vblank ( struct exynos_drm_manager * mgr )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
if ( ctx - > suspended )
return - EPERM ;
if ( ! test_and_set_bit ( 0 , & ctx - > irq_flags ) )
ctx - > vblank_on = true ;
2012-09-19 11:02:43 +09:00
ctx - > direct_vblank = true ;
/*
* in case of page flip request , vidi_finish_pageflip function
* will not be called because direct_vblank is true and then
2014-01-30 16:19:02 -05:00
* that function will be called by manager_ops - > win_commit callback
2012-09-19 11:02:43 +09:00
*/
schedule_work ( & ctx - > work ) ;
2012-03-21 10:55:26 +09:00
return 0 ;
}
2014-01-30 16:19:06 -05:00
static void vidi_disable_vblank ( struct exynos_drm_manager * mgr )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
if ( ctx - > suspended )
return ;
if ( test_and_clear_bit ( 0 , & ctx - > irq_flags ) )
ctx - > vblank_on = false ;
}
2014-01-30 16:19:06 -05:00
static void vidi_win_mode_set ( struct exynos_drm_manager * mgr ,
struct exynos_drm_overlay * overlay )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
struct vidi_win_data * win_data ;
int win ;
unsigned long offset ;
if ( ! overlay ) {
2014-01-30 16:19:06 -05:00
DRM_ERROR ( " overlay is NULL \n " ) ;
2012-03-21 10:55:26 +09:00
return ;
}
win = overlay - > zpos ;
if ( win = = DEFAULT_ZPOS )
win = ctx - > default_win ;
2013-05-28 16:01:21 +09:00
if ( win < 0 | | win > = WINDOWS_NR )
2012-03-21 10:55:26 +09:00
return ;
offset = overlay - > fb_x * ( overlay - > bpp > > 3 ) ;
offset + = overlay - > fb_y * overlay - > pitch ;
DRM_DEBUG_KMS ( " offset = 0x%lx, pitch = %x \n " , offset , overlay - > pitch ) ;
win_data = & ctx - > win_data [ win ] ;
win_data - > offset_x = overlay - > crtc_x ;
win_data - > offset_y = overlay - > crtc_y ;
win_data - > ovl_width = overlay - > crtc_width ;
win_data - > ovl_height = overlay - > crtc_height ;
win_data - > fb_width = overlay - > fb_width ;
win_data - > fb_height = overlay - > fb_height ;
win_data - > dma_addr = overlay - > dma_addr [ 0 ] + offset ;
win_data - > bpp = overlay - > bpp ;
win_data - > buf_offsize = ( overlay - > fb_width - overlay - > crtc_width ) *
( overlay - > bpp > > 3 ) ;
win_data - > line_size = overlay - > crtc_width * ( overlay - > bpp > > 3 ) ;
/*
* some parts of win_data should be transferred to user side
* through specific ioctl .
*/
DRM_DEBUG_KMS ( " offset_x = %d, offset_y = %d \n " ,
win_data - > offset_x , win_data - > offset_y ) ;
DRM_DEBUG_KMS ( " ovl_width = %d, ovl_height = %d \n " ,
win_data - > ovl_width , win_data - > ovl_height ) ;
2012-12-10 15:44:58 +09:00
DRM_DEBUG_KMS ( " paddr = 0x%lx \n " , ( unsigned long ) win_data - > dma_addr ) ;
2012-03-21 10:55:26 +09:00
DRM_DEBUG_KMS ( " fb_width = %d, crtc_width = %d \n " ,
overlay - > fb_width , overlay - > crtc_width ) ;
}
2014-01-30 16:19:06 -05:00
static void vidi_win_commit ( struct exynos_drm_manager * mgr , int zpos )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
struct vidi_win_data * win_data ;
int win = zpos ;
if ( ctx - > suspended )
return ;
if ( win = = DEFAULT_ZPOS )
win = ctx - > default_win ;
2013-05-28 16:01:21 +09:00
if ( win < 0 | | win > = WINDOWS_NR )
2012-03-21 10:55:26 +09:00
return ;
win_data = & ctx - > win_data [ win ] ;
win_data - > enabled = true ;
DRM_DEBUG_KMS ( " dma_addr = 0x%x \n " , win_data - > dma_addr ) ;
if ( ctx - > vblank_on )
schedule_work ( & ctx - > work ) ;
}
2014-01-30 16:19:06 -05:00
static void vidi_win_disable ( struct exynos_drm_manager * mgr , int zpos )
2012-03-21 10:55:26 +09:00
{
2014-01-30 16:19:06 -05:00
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
struct vidi_win_data * win_data ;
int win = zpos ;
if ( win = = DEFAULT_ZPOS )
win = ctx - > default_win ;
2013-05-28 16:01:21 +09:00
if ( win < 0 | | win > = WINDOWS_NR )
2012-03-21 10:55:26 +09:00
return ;
win_data = & ctx - > win_data [ win ] ;
win_data - > enabled = false ;
/* TODO. */
}
2014-01-30 16:19:27 -05:00
static int vidi_power_on ( struct exynos_drm_manager * mgr , bool enable )
{
struct vidi_context * ctx = mgr - > ctx ;
DRM_DEBUG_KMS ( " %s \n " , __FILE__ ) ;
if ( enable ! = false & & enable ! = true )
return - EINVAL ;
if ( enable ) {
ctx - > suspended = false ;
/* if vblank was enabled status, enable it again. */
if ( test_and_clear_bit ( 0 , & ctx - > irq_flags ) )
vidi_enable_vblank ( mgr ) ;
vidi_apply ( mgr ) ;
} else {
ctx - > suspended = true ;
}
return 0 ;
}
static void vidi_dpms ( struct exynos_drm_manager * mgr , int mode )
{
struct vidi_context * ctx = mgr - > ctx ;
DRM_DEBUG_KMS ( " %d \n " , mode ) ;
mutex_lock ( & ctx - > lock ) ;
switch ( mode ) {
case DRM_MODE_DPMS_ON :
vidi_power_on ( mgr , true ) ;
break ;
case DRM_MODE_DPMS_STANDBY :
case DRM_MODE_DPMS_SUSPEND :
case DRM_MODE_DPMS_OFF :
vidi_power_on ( mgr , false ) ;
break ;
default :
DRM_DEBUG_KMS ( " unspecified mode %d \n " , mode ) ;
break ;
}
mutex_unlock ( & ctx - > lock ) ;
}
2014-02-19 21:02:55 +09:00
static int vidi_mgr_initialize ( struct exynos_drm_manager * mgr ,
struct drm_device * drm_dev , int pipe )
{
struct vidi_context * ctx = mgr - > ctx ;
DRM_ERROR ( " vidi initialize ct=%p dev=%p pipe=%d \n " , ctx , drm_dev , pipe ) ;
ctx - > drm_dev = drm_dev ;
ctx - > pipe = pipe ;
/*
* enable drm irq mode .
* - with irq_enabled = 1 , we can use the vblank feature .
*
* P . S . note that we wouldn ' t use drm irq handler but
* just specific driver own one instead because
* drm framework supports only one irq handler .
*/
drm_dev - > irq_enabled = 1 ;
/*
* with vblank_disable_allowed = 1 , vblank interrupt will be disabled
* by drm timer once a current process gives up ownership of
* vblank event . ( after drm_vblank_put function is called )
*/
drm_dev - > vblank_disable_allowed = 1 ;
return 0 ;
}
2014-01-30 16:19:02 -05:00
static struct exynos_drm_manager_ops vidi_manager_ops = {
2014-02-19 21:02:55 +09:00
. initialize = vidi_mgr_initialize ,
2014-01-30 16:19:02 -05:00
. dpms = vidi_dpms ,
. commit = vidi_commit ,
. enable_vblank = vidi_enable_vblank ,
. disable_vblank = vidi_disable_vblank ,
. win_mode_set = vidi_win_mode_set ,
. win_commit = vidi_win_commit ,
. win_disable = vidi_win_disable ,
2012-03-21 10:55:26 +09:00
} ;
2012-04-05 20:49:27 +09:00
static struct exynos_drm_manager vidi_manager = {
2014-02-19 21:02:55 +09:00
. type = EXYNOS_DISPLAY_TYPE_VIDI ,
. ops = & vidi_manager_ops ,
2012-04-05 20:49:27 +09:00
} ;
2012-03-21 10:55:26 +09:00
static void vidi_fake_vblank_handler ( struct work_struct * work )
{
struct vidi_context * ctx = container_of ( work , struct vidi_context ,
work ) ;
2014-02-19 21:02:55 +09:00
if ( ctx - > pipe < 0 )
2012-03-21 10:55:26 +09:00
return ;
/* refresh rate is about 50Hz. */
usleep_range ( 16000 , 20000 ) ;
2012-09-19 11:02:43 +09:00
mutex_lock ( & ctx - > lock ) ;
if ( ctx - > direct_vblank ) {
2014-02-19 21:02:55 +09:00
drm_handle_vblank ( ctx - > drm_dev , ctx - > pipe ) ;
2012-09-19 11:02:43 +09:00
ctx - > direct_vblank = false ;
mutex_unlock ( & ctx - > lock ) ;
return ;
}
mutex_unlock ( & ctx - > lock ) ;
2014-02-19 21:02:55 +09:00
exynos_drm_crtc_finish_pageflip ( ctx - > drm_dev , ctx - > pipe ) ;
2012-03-21 10:55:26 +09:00
}
static int vidi_show_connection ( struct device * dev ,
struct device_attribute * attr , char * buf )
{
int rc ;
2014-01-30 16:19:06 -05:00
struct exynos_drm_manager * mgr = get_vidi_mgr ( dev ) ;
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
mutex_lock ( & ctx - > lock ) ;
rc = sprintf ( buf , " %d \n " , ctx - > connected ) ;
mutex_unlock ( & ctx - > lock ) ;
return rc ;
}
static int vidi_store_connection ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t len )
{
2014-01-30 16:19:06 -05:00
struct exynos_drm_manager * mgr = get_vidi_mgr ( dev ) ;
struct vidi_context * ctx = mgr - > ctx ;
2012-03-21 10:55:26 +09:00
int ret ;
ret = kstrtoint ( buf , 0 , & ctx - > connected ) ;
if ( ret )
return ret ;
if ( ctx - > connected > 1 )
return - EINVAL ;
2012-06-27 16:00:56 +09:00
/* use fake edid data for test. */
if ( ! ctx - > raw_edid )
ctx - > raw_edid = ( struct edid * ) fake_edid_info ;
2012-06-27 16:16:26 +09:00
/* if raw_edid isn't same as fake data then it can't be tested. */
if ( ctx - > raw_edid ! = ( struct edid * ) fake_edid_info ) {
DRM_DEBUG_KMS ( " edid data is not fake data. \n " ) ;
return - EINVAL ;
}
2012-03-21 10:55:26 +09:00
DRM_DEBUG_KMS ( " requested connection. \n " ) ;
2014-02-19 21:02:55 +09:00
drm_helper_hpd_irq_event ( ctx - > drm_dev ) ;
2012-03-21 10:55:26 +09:00
return len ;
}
static DEVICE_ATTR ( connection , 0644 , vidi_show_connection ,
vidi_store_connection ) ;
int vidi_connection_ioctl ( struct drm_device * drm_dev , void * data ,
struct drm_file * file_priv )
{
struct vidi_context * ctx = NULL ;
struct drm_encoder * encoder ;
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * display ;
2012-03-21 10:55:26 +09:00
struct drm_exynos_vidi_connection * vidi = data ;
if ( ! vidi ) {
DRM_DEBUG_KMS ( " user data for vidi is null. \n " ) ;
return - EINVAL ;
}
if ( vidi - > connection > 1 ) {
DRM_DEBUG_KMS ( " connection should be 0 or 1. \n " ) ;
return - EINVAL ;
}
list_for_each_entry ( encoder , & drm_dev - > mode_config . encoder_list ,
head ) {
2014-02-19 21:02:55 +09:00
display = exynos_drm_get_display ( encoder ) ;
2012-03-21 10:55:26 +09:00
2014-02-19 21:02:55 +09:00
if ( display - > type = = EXYNOS_DISPLAY_TYPE_VIDI ) {
ctx = display - > ctx ;
2012-03-21 10:55:26 +09:00
break ;
}
}
if ( ! ctx ) {
DRM_DEBUG_KMS ( " not found virtual device type encoder. \n " ) ;
return - EINVAL ;
}
if ( ctx - > connected = = vidi - > connection ) {
DRM_DEBUG_KMS ( " same connection request. \n " ) ;
return - EINVAL ;
}
2012-06-27 16:36:12 +09:00
if ( vidi - > connection ) {
2013-01-10 19:35:06 +09:00
struct edid * raw_edid = ( struct edid * ) ( uint32_t ) vidi - > edid ;
if ( ! drm_edid_is_valid ( raw_edid ) ) {
DRM_DEBUG_KMS ( " edid data is invalid. \n " ) ;
2012-06-27 16:36:12 +09:00
return - EINVAL ;
}
2013-09-27 15:08:29 +03:00
ctx - > raw_edid = drm_edid_duplicate ( raw_edid ) ;
2012-06-27 16:36:12 +09:00
if ( ! ctx - > raw_edid ) {
DRM_DEBUG_KMS ( " failed to allocate raw_edid. \n " ) ;
return - ENOMEM ;
}
} else {
/*
* with connection = 0 , free raw_edid
* only if raw edid data isn ' t same as fake data .
*/
if ( ctx - > raw_edid & & ctx - > raw_edid ! =
( struct edid * ) fake_edid_info ) {
kfree ( ctx - > raw_edid ) ;
ctx - > raw_edid = NULL ;
}
}
2012-03-21 10:55:26 +09:00
ctx - > connected = vidi - > connection ;
2014-02-19 21:02:55 +09:00
drm_helper_hpd_irq_event ( ctx - > drm_dev ) ;
2012-03-21 10:55:26 +09:00
return 0 ;
}
2012-12-21 15:09:25 -08:00
static int vidi_probe ( struct platform_device * pdev )
2012-03-21 10:55:26 +09:00
{
struct device * dev = & pdev - > dev ;
struct vidi_context * ctx ;
int ret ;
2013-05-22 21:14:14 +09:00
ctx = devm_kzalloc ( dev , sizeof ( * ctx ) , GFP_KERNEL ) ;
2012-03-21 10:55:26 +09:00
if ( ! ctx )
return - ENOMEM ;
ctx - > default_win = 0 ;
INIT_WORK ( & ctx - > work , vidi_fake_vblank_handler ) ;
2014-01-30 16:19:06 -05:00
vidi_manager . ctx = ctx ;
2014-02-19 21:02:55 +09:00
vidi_display . ctx = ctx ;
2012-03-21 10:55:26 +09:00
mutex_init ( & ctx - > lock ) ;
2014-01-30 16:19:06 -05:00
platform_set_drvdata ( pdev , & vidi_manager ) ;
2012-03-21 10:55:26 +09:00
2013-05-22 21:14:14 +09:00
ret = device_create_file ( dev , & dev_attr_connection ) ;
2012-03-21 10:55:26 +09:00
if ( ret < 0 )
DRM_INFO ( " failed to create connection sysfs. \n " ) ;
2014-02-19 21:02:55 +09:00
exynos_drm_manager_register ( & vidi_manager ) ;
exynos_drm_display_register ( & vidi_display ) ;
2012-03-21 10:55:26 +09:00
return 0 ;
}
2012-12-21 15:09:25 -08:00
static int vidi_remove ( struct platform_device * pdev )
2012-03-21 10:55:26 +09:00
{
struct vidi_context * ctx = platform_get_drvdata ( pdev ) ;
2014-02-19 21:02:55 +09:00
exynos_drm_display_unregister ( & vidi_display ) ;
exynos_drm_manager_unregister ( & vidi_manager ) ;
2012-03-21 10:55:26 +09:00
2012-06-27 16:36:12 +09:00
if ( ctx - > raw_edid ! = ( struct edid * ) fake_edid_info ) {
kfree ( ctx - > raw_edid ) ;
ctx - > raw_edid = NULL ;
}
2012-03-21 10:55:26 +09:00
return 0 ;
}
struct platform_driver vidi_driver = {
. probe = vidi_probe ,
2012-12-21 15:09:25 -08:00
. remove = vidi_remove ,
2012-03-21 10:55:26 +09:00
. driver = {
. name = " exynos-drm-vidi " ,
. owner = THIS_MODULE ,
} ,
} ;