2011-10-04 19:19:01 +09:00
/* exynos_drm_encoder.c
*
* Copyright ( c ) 2011 Samsung Electronics Co . , Ltd .
* Authors :
* Inki Dae < inki . dae @ samsung . com >
* Joonyoung Shim < jy0922 . shim @ samsung . com >
* Seung - Woo Kim < sw0312 . kim @ samsung . com >
*
2012-12-18 02:30:17 +09:00
* 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 .
2011-10-04 19:19:01 +09:00
*/
2012-10-02 18:01:07 +01:00
# include <drm/drmP.h>
# include <drm/drm_crtc_helper.h>
2011-10-04 19:19:01 +09:00
# include "exynos_drm_drv.h"
# include "exynos_drm_encoder.h"
# define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\
drm_encoder )
/*
* exynos specific encoder structure .
*
* @ drm_encoder : encoder object .
2014-02-19 21:02:55 +09:00
* @ display : the display structure that maps to this encoder
2011-10-04 19:19:01 +09:00
*/
struct exynos_drm_encoder {
struct drm_encoder drm_encoder ;
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * display ;
2011-10-04 19:19:01 +09:00
} ;
2011-12-06 11:06:54 +09:00
static void exynos_drm_encoder_dpms ( struct drm_encoder * encoder , int mode )
{
2014-02-19 21:02:55 +09:00
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
struct exynos_drm_display * display = exynos_encoder - > display ;
2011-10-04 19:19:01 +09:00
2013-06-12 10:40:52 +09:00
DRM_DEBUG_KMS ( " encoder dpms: %d \n " , mode ) ;
2011-10-04 19:19:01 +09:00
2014-02-19 21:02:55 +09:00
if ( display - > ops - > dpms )
display - > ops - > dpms ( display , mode ) ;
2011-10-04 19:19:01 +09:00
}
static bool
exynos_drm_encoder_mode_fixup ( struct drm_encoder * encoder ,
2012-07-17 17:56:50 +02:00
const struct drm_display_mode * mode ,
2011-10-04 19:19:01 +09:00
struct drm_display_mode * adjusted_mode )
{
2012-03-16 18:47:04 +09:00
struct drm_device * dev = encoder - > dev ;
2014-02-19 21:02:55 +09:00
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
struct exynos_drm_display * display = exynos_encoder - > display ;
2012-03-16 18:47:04 +09:00
struct drm_connector * connector ;
list_for_each_entry ( connector , & dev - > mode_config . connector_list , head ) {
2014-02-19 21:02:55 +09:00
if ( connector - > encoder ! = encoder )
continue ;
if ( display - > ops - > mode_fixup )
display - > ops - > mode_fixup ( display , connector , mode ,
adjusted_mode ) ;
2012-03-16 18:47:04 +09:00
}
2011-10-04 19:19:01 +09:00
return true ;
}
static void exynos_drm_encoder_mode_set ( struct drm_encoder * encoder ,
struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2014-01-30 16:19:17 -05:00
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
struct exynos_drm_display * display = exynos_encoder - > display ;
2012-08-17 17:58:38 +09:00
2014-01-30 16:19:17 -05:00
if ( display - > ops - > mode_set )
display - > ops - > mode_set ( display , adjusted_mode ) ;
2011-10-04 19:19:01 +09:00
}
static void exynos_drm_encoder_prepare ( struct drm_encoder * encoder )
{
/* drm framework doesn't check NULL. */
}
static void exynos_drm_encoder_commit ( struct drm_encoder * encoder )
{
2012-10-18 18:59:55 +09:00
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * display = exynos_encoder - > display ;
2011-10-04 19:19:01 +09:00
2014-02-19 21:02:55 +09:00
if ( display - > ops - > dpms )
display - > ops - > dpms ( display , DRM_MODE_DPMS_ON ) ;
2012-11-22 17:41:23 +09:00
2014-02-19 21:02:55 +09:00
if ( display - > ops - > commit )
display - > ops - > commit ( display ) ;
2012-11-22 17:41:23 +09:00
}
2012-08-24 10:54:12 -07:00
static void exynos_drm_encoder_disable ( struct drm_encoder * encoder )
{
struct drm_plane * plane ;
struct drm_device * dev = encoder - > dev ;
exynos_drm_encoder_dpms ( encoder , DRM_MODE_DPMS_OFF ) ;
/* all planes connected to this encoder should be also disabled. */
2014-04-01 15:22:31 -07:00
drm_for_each_legacy_plane ( plane , & dev - > mode_config . plane_list ) {
2015-02-05 16:11:38 +09:00
if ( plane - > crtc & & ( plane - > crtc = = encoder - > crtc ) )
2012-08-24 10:54:12 -07:00
plane - > funcs - > disable_plane ( plane ) ;
}
}
2011-10-04 19:19:01 +09:00
static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
. dpms = exynos_drm_encoder_dpms ,
. mode_fixup = exynos_drm_encoder_mode_fixup ,
. mode_set = exynos_drm_encoder_mode_set ,
. prepare = exynos_drm_encoder_prepare ,
. commit = exynos_drm_encoder_commit ,
2012-08-24 10:54:12 -07:00
. disable = exynos_drm_encoder_disable ,
2011-10-04 19:19:01 +09:00
} ;
static void exynos_drm_encoder_destroy ( struct drm_encoder * encoder )
{
2014-02-19 21:02:55 +09:00
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
2011-10-04 19:19:01 +09:00
drm_encoder_cleanup ( encoder ) ;
kfree ( exynos_encoder ) ;
}
static struct drm_encoder_funcs exynos_encoder_funcs = {
. destroy = exynos_drm_encoder_destroy ,
} ;
2012-02-15 11:25:19 +09:00
static unsigned int exynos_drm_encoder_clones ( struct drm_encoder * encoder )
{
struct drm_encoder * clone ;
struct drm_device * dev = encoder - > dev ;
struct exynos_drm_encoder * exynos_encoder = to_exynos_encoder ( encoder ) ;
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * display = exynos_encoder - > display ;
2012-02-15 11:25:19 +09:00
unsigned int clone_mask = 0 ;
int cnt = 0 ;
list_for_each_entry ( clone , & dev - > mode_config . encoder_list , head ) {
2014-02-19 21:02:55 +09:00
switch ( display - > type ) {
2012-02-15 11:25:19 +09:00
case EXYNOS_DISPLAY_TYPE_LCD :
case EXYNOS_DISPLAY_TYPE_HDMI :
2012-03-21 10:55:26 +09:00
case EXYNOS_DISPLAY_TYPE_VIDI :
2012-02-15 11:25:19 +09:00
clone_mask | = ( 1 < < ( cnt + + ) ) ;
break ;
default :
continue ;
}
}
return clone_mask ;
}
void exynos_drm_encoder_setup ( struct drm_device * dev )
{
struct drm_encoder * encoder ;
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head )
encoder - > possible_clones = exynos_drm_encoder_clones ( encoder ) ;
}
2011-10-04 19:19:01 +09:00
struct drm_encoder *
exynos_drm_encoder_create ( struct drm_device * dev ,
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * display ,
2014-01-30 16:19:11 -05:00
unsigned long possible_crtcs )
2011-10-04 19:19:01 +09:00
{
struct drm_encoder * encoder ;
struct exynos_drm_encoder * exynos_encoder ;
2014-02-19 21:02:55 +09:00
if ( ! possible_crtcs )
2011-10-04 19:19:01 +09:00
return NULL ;
exynos_encoder = kzalloc ( sizeof ( * exynos_encoder ) , GFP_KERNEL ) ;
2013-08-19 19:04:55 +09:00
if ( ! exynos_encoder )
2011-10-04 19:19:01 +09:00
return NULL ;
2014-02-19 21:02:55 +09:00
exynos_encoder - > display = display ;
2011-10-04 19:19:01 +09:00
encoder = & exynos_encoder - > drm_encoder ;
encoder - > possible_crtcs = possible_crtcs ;
DRM_DEBUG_KMS ( " possible_crtcs = 0x%x \n " , encoder - > possible_crtcs ) ;
drm_encoder_init ( dev , encoder , & exynos_encoder_funcs ,
DRM_MODE_ENCODER_TMDS ) ;
drm_encoder_helper_add ( encoder , & exynos_encoder_helper_funcs ) ;
DRM_DEBUG_KMS ( " encoder has been created \n " ) ;
return encoder ;
}
2014-02-19 21:02:55 +09:00
struct exynos_drm_display * exynos_drm_get_display ( struct drm_encoder * encoder )
2011-10-04 19:19:01 +09:00
{
2014-02-19 21:02:55 +09:00
return to_exynos_encoder ( encoder ) - > display ;
2012-06-27 14:27:02 +09:00
}