2011-12-08 17:54:07 +09:00
/*
* Copyright ( C ) 2011 Samsung Electronics Co . Ltd
* Authors : Joonyoung Shim < jy0922 . shim @ 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>
2011-12-08 17:54:07 +09:00
2012-10-02 18:01:07 +01:00
# include <drm/exynos_drm.h>
2014-11-27 14:56:09 -02:00
# include <drm/drm_plane_helper.h>
2015-06-01 12:04:44 -03:00
# include <drm/drm_atomic_helper.h>
2011-12-08 17:54:07 +09:00
# include "exynos_drm_drv.h"
2014-02-19 21:02:55 +09:00
# include "exynos_drm_crtc.h"
2012-06-27 14:27:05 +09:00
# include "exynos_drm_fb.h"
# include "exynos_drm_gem.h"
2013-08-13 00:46:40 +01:00
# include "exynos_drm_plane.h"
2011-12-08 17:54:07 +09:00
2012-03-16 18:47:15 +09:00
static const uint32_t formats [ ] = {
DRM_FORMAT_XRGB8888 ,
2012-04-05 11:21:09 +09:00
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_NV12 ,
2012-03-16 18:47:15 +09:00
} ;
2012-09-27 19:25:21 +09:00
/*
* This function is to get X or Y size shown via screen . This needs length and
* start position of CRTC .
*
* < - - - length - - - >
* CRTC - - - - - - - - - - - - - - - -
* ^ start ^ end
*
2012-12-14 15:48:22 +09:00
* There are six cases from a to f .
2012-09-27 19:25:21 +09:00
*
* < - - - - - SCREEN - - - - - >
* 0 last
* - - - - - - - - - - | - - - - - - - - - - - - - - - - - - | - - - - - - - - - -
* CRTCs
* a - - - - - - -
* b - - - - - - -
* c - - - - - - - - - - - - - - - - - - - - - - - - - -
* d - - - - - - - -
* e - - - - - - -
* f - - - - - - -
*/
static int exynos_plane_get_size ( int start , unsigned length , unsigned last )
{
int end = start + length ;
int size = 0 ;
if ( start < = 0 ) {
if ( end > 0 )
size = min_t ( unsigned , end , last ) ;
} else if ( start < = last ) {
size = min_t ( unsigned , last - start , length ) ;
}
return size ;
}
2015-06-01 12:04:49 -03:00
static void exynos_plane_mode_set ( struct drm_plane * plane ,
struct drm_crtc * crtc ,
struct drm_framebuffer * fb ,
int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t src_x , uint32_t src_y ,
uint32_t src_w , uint32_t src_h )
2014-11-27 14:56:09 -02:00
{
struct exynos_drm_plane * exynos_plane = to_exynos_plane ( plane ) ;
2015-06-02 21:04:42 +09:00
struct drm_display_mode * mode = & crtc - > state - > adjusted_mode ;
2014-11-27 14:56:09 -02:00
unsigned int actual_w ;
unsigned int actual_h ;
2015-06-02 21:04:42 +09:00
actual_w = exynos_plane_get_size ( crtc_x , crtc_w , mode - > hdisplay ) ;
actual_h = exynos_plane_get_size ( crtc_y , crtc_h , mode - > vdisplay ) ;
2012-09-27 19:25:21 +09:00
if ( crtc_x < 0 ) {
if ( actual_w )
src_x - = crtc_x ;
crtc_x = 0 ;
}
if ( crtc_y < 0 ) {
if ( actual_h )
src_y - = crtc_y ;
crtc_y = 0 ;
}
2012-06-27 14:27:05 +09:00
2015-04-07 15:59:39 +09:00
/* set ratio */
exynos_plane - > h_ratio = ( src_w < < 16 ) / crtc_w ;
exynos_plane - > v_ratio = ( src_h < < 16 ) / crtc_h ;
2012-06-27 14:27:05 +09:00
/* set drm framebuffer data. */
2015-04-07 15:59:38 +09:00
exynos_plane - > src_x = src_x ;
exynos_plane - > src_y = src_y ;
2015-04-07 15:59:39 +09:00
exynos_plane - > src_width = ( actual_w * exynos_plane - > h_ratio ) > > 16 ;
exynos_plane - > src_height = ( actual_h * exynos_plane - > v_ratio ) > > 16 ;
2015-04-07 15:59:38 +09:00
exynos_plane - > fb_width = fb - > width ;
exynos_plane - > fb_height = fb - > height ;
2014-11-03 18:13:27 -02:00
exynos_plane - > bpp = fb - > bits_per_pixel ;
exynos_plane - > pitch = fb - > pitches [ 0 ] ;
exynos_plane - > pixel_format = fb - > pixel_format ;
/* set plane range to be displayed. */
exynos_plane - > crtc_x = crtc_x ;
exynos_plane - > crtc_y = crtc_y ;
exynos_plane - > crtc_width = actual_w ;
exynos_plane - > crtc_height = actual_h ;
2012-06-27 14:27:05 +09:00
/* set drm mode data. */
2015-06-02 21:04:42 +09:00
exynos_plane - > mode_width = mode - > hdisplay ;
exynos_plane - > mode_height = mode - > vdisplay ;
exynos_plane - > refresh = mode - > vrefresh ;
exynos_plane - > scan_flag = mode - > flags ;
2012-06-27 14:27:05 +09:00
2014-11-03 18:13:27 -02:00
DRM_DEBUG_KMS ( " plane : offset_x/y(%d,%d), width/height(%d,%d) " ,
exynos_plane - > crtc_x , exynos_plane - > crtc_y ,
exynos_plane - > crtc_width , exynos_plane - > crtc_height ) ;
2012-06-27 14:27:05 +09:00
2014-09-19 14:58:53 +02:00
plane - > crtc = crtc ;
2012-06-27 14:27:05 +09:00
}
2011-12-08 17:54:07 +09:00
static struct drm_plane_funcs exynos_plane_funcs = {
2015-06-01 12:04:46 -03:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2015-04-01 13:02:10 -03:00
. destroy = drm_plane_cleanup ,
2015-06-01 12:04:44 -03:00
. reset = drm_atomic_helper_plane_reset ,
. atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_plane_destroy_state ,
2011-12-08 17:54:07 +09:00
} ;
2015-06-01 12:04:41 -03:00
static int exynos_plane_atomic_check ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
2015-06-01 12:04:49 -03:00
struct exynos_drm_plane * exynos_plane = to_exynos_plane ( plane ) ;
int nr ;
int i ;
if ( ! state - > fb )
return 0 ;
nr = exynos_drm_fb_get_buf_cnt ( state - > fb ) ;
for ( i = 0 ; i < nr ; i + + ) {
struct exynos_drm_gem_buf * buffer =
exynos_drm_fb_buffer ( state - > fb , i ) ;
if ( ! buffer ) {
DRM_DEBUG_KMS ( " buffer is null \n " ) ;
return - EFAULT ;
}
exynos_plane - > dma_addr [ i ] = buffer - > dma_addr +
state - > fb - > offsets [ i ] ;
DRM_DEBUG_KMS ( " buffer: %d, dma_addr = 0x%lx \n " ,
i , ( unsigned long ) exynos_plane - > dma_addr [ i ] ) ;
}
return 0 ;
2015-06-01 12:04:41 -03:00
}
static void exynos_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct drm_plane_state * state = plane - > state ;
2015-06-01 12:04:49 -03:00
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( state - > crtc ) ;
struct exynos_drm_plane * exynos_plane = to_exynos_plane ( plane ) ;
2015-06-01 12:04:41 -03:00
if ( ! state - > crtc )
return ;
2015-06-01 12:04:49 -03:00
exynos_plane_mode_set ( plane , state - > crtc , state - > fb ,
state - > crtc_x , state - > crtc_y ,
state - > crtc_w , state - > crtc_h ,
state - > src_x > > 16 , state - > src_y > > 16 ,
state - > src_w > > 16 , state - > src_h > > 16 ) ;
if ( exynos_crtc - > ops - > win_commit )
exynos_crtc - > ops - > win_commit ( exynos_crtc , exynos_plane - > zpos ) ;
2015-06-01 12:04:41 -03:00
}
2015-06-01 12:04:42 -03:00
static void exynos_plane_atomic_disable ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct exynos_drm_plane * exynos_plane = to_exynos_plane ( plane ) ;
struct exynos_drm_crtc * exynos_crtc = to_exynos_crtc ( old_state - > crtc ) ;
if ( ! old_state - > crtc )
return ;
if ( exynos_crtc - > ops - > win_disable )
exynos_crtc - > ops - > win_disable ( exynos_crtc ,
exynos_plane - > zpos ) ;
}
2015-06-01 12:04:41 -03:00
static const struct drm_plane_helper_funcs plane_helper_funcs = {
. atomic_check = exynos_plane_atomic_check ,
. atomic_update = exynos_plane_atomic_update ,
2015-06-01 12:04:42 -03:00
. atomic_disable = exynos_plane_atomic_disable ,
2015-06-01 12:04:41 -03:00
} ;
2015-04-03 21:05:52 +09:00
static void exynos_plane_attach_zpos_property ( struct drm_plane * plane ,
unsigned int zpos )
2012-06-27 14:27:06 +09:00
{
struct drm_device * dev = plane - > dev ;
struct exynos_drm_private * dev_priv = dev - > dev_private ;
struct drm_property * prop ;
prop = dev_priv - > plane_zpos_property ;
if ( ! prop ) {
2015-04-01 13:02:09 -03:00
prop = drm_property_create_range ( dev , DRM_MODE_PROP_IMMUTABLE ,
" zpos " , 0 , MAX_PLANE - 1 ) ;
2012-06-27 14:27:06 +09:00
if ( ! prop )
return ;
dev_priv - > plane_zpos_property = prop ;
}
2015-04-03 21:05:52 +09:00
drm_object_attach_property ( & plane - > base , prop , zpos ) ;
2012-06-27 14:27:06 +09:00
}
2015-04-03 21:03:40 +09:00
int exynos_plane_init ( struct drm_device * dev ,
struct exynos_drm_plane * exynos_plane ,
2015-04-03 21:05:52 +09:00
unsigned long possible_crtcs , enum drm_plane_type type ,
unsigned int zpos )
2011-12-08 17:54:07 +09:00
{
2012-06-27 14:27:04 +09:00
int err ;
2011-12-08 17:54:07 +09:00
2014-09-19 14:58:53 +02:00
err = drm_universal_plane_init ( dev , & exynos_plane - > base , possible_crtcs ,
& exynos_plane_funcs , formats ,
ARRAY_SIZE ( formats ) , type ) ;
2012-06-27 14:27:04 +09:00
if ( err ) {
DRM_ERROR ( " failed to initialize plane \n " ) ;
2015-04-03 21:03:40 +09:00
return err ;
2012-06-27 14:27:04 +09:00
}
2015-06-01 12:04:41 -03:00
drm_plane_helper_add ( & exynos_plane - > base , & plane_helper_funcs ) ;
2015-04-03 21:05:52 +09:00
exynos_plane - > zpos = zpos ;
if ( type = = DRM_PLANE_TYPE_OVERLAY )
exynos_plane_attach_zpos_property ( & exynos_plane - > base , zpos ) ;
2011-12-08 17:54:07 +09:00
2015-04-03 21:03:40 +09:00
return 0 ;
2011-12-08 17:54:07 +09:00
}