2011-10-04 19:19:01 +09:00
/* exynos_drm_fb.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>
2015-06-01 12:04:52 -03:00
# include <drm/drm_atomic.h>
2015-06-01 12:04:46 -03:00
# include <drm/drm_atomic_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_crtc.h>
# include <drm/drm_fb_helper.h>
2018-03-30 15:11:30 +01:00
# include <drm/drm_gem_framebuffer_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2012-10-20 07:53:42 -07:00
# include <uapi/drm/exynos_drm.h>
2011-10-04 19:19:01 +09:00
2011-10-18 16:58:05 +09:00
# include "exynos_drm_drv.h"
2011-10-04 19:19:01 +09:00
# include "exynos_drm_fb.h"
2014-03-17 11:27:17 +01:00
# include "exynos_drm_fbdev.h"
2014-02-19 21:02:55 +09:00
# include "exynos_drm_crtc.h"
2011-10-04 19:19:01 +09:00
2012-10-20 07:53:42 -07:00
static int check_fb_gem_memory_type ( struct drm_device * drm_dev ,
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem )
2012-10-20 07:53:42 -07:00
{
unsigned int flags ;
/*
* if exynos drm driver supports iommu then framebuffer can use
* all the buffer types .
*/
if ( is_drm_iommu_supported ( drm_dev ) )
return 0 ;
2015-10-02 09:33:47 +09:00
flags = exynos_gem - > flags ;
2012-10-20 07:53:42 -07:00
/*
2016-08-08 17:48:20 -06:00
* Physically non - contiguous memory type for framebuffer is not
* supported without IOMMU .
2012-10-20 07:53:42 -07:00
*/
if ( IS_NONCONTIG_BUFFER ( flags ) ) {
2016-08-08 17:48:20 -06:00
DRM_ERROR ( " Non-contiguous GEM memory is not supported. \n " ) ;
2012-10-20 07:53:42 -07:00
return - EINVAL ;
}
return 0 ;
}
2015-12-15 12:21:06 +01:00
static const struct drm_framebuffer_funcs exynos_drm_fb_funcs = {
2018-03-30 15:11:30 +01:00
. destroy = drm_gem_fb_destroy ,
. create_handle = drm_gem_fb_create_handle ,
2011-10-04 19:19:01 +09:00
} ;
2011-12-13 14:46:57 +09:00
struct drm_framebuffer *
exynos_drm_framebuffer_init ( struct drm_device * dev ,
2015-11-11 19:11:29 +02:00
const struct drm_mode_fb_cmd2 * mode_cmd ,
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * * exynos_gem ,
2015-09-01 16:22:52 +09:00
int count )
2011-10-04 19:19:01 +09:00
{
2018-03-30 15:11:32 +01:00
struct drm_framebuffer * fb ;
2015-09-01 16:22:52 +09:00
int i ;
2011-10-04 19:19:01 +09:00
int ret ;
2018-03-30 15:11:32 +01:00
fb = kzalloc ( sizeof ( * fb ) , GFP_KERNEL ) ;
if ( ! fb )
2011-10-04 19:19:01 +09:00
return ERR_PTR ( - ENOMEM ) ;
2015-09-01 16:22:52 +09:00
for ( i = 0 ; i < count ; i + + ) {
2015-10-02 09:33:47 +09:00
ret = check_fb_gem_memory_type ( dev , exynos_gem [ i ] ) ;
2015-09-01 16:22:52 +09:00
if ( ret < 0 )
goto err ;
2018-03-30 15:11:32 +01:00
fb - > obj [ i ] = & exynos_gem [ i ] - > base ;
2015-09-01 16:22:52 +09:00
}
2018-03-30 15:11:32 +01:00
drm_helper_mode_fill_fb_struct ( dev , fb , mode_cmd ) ;
2015-09-01 16:22:47 +09:00
2018-03-30 15:11:32 +01:00
ret = drm_framebuffer_init ( dev , fb , & exynos_drm_fb_funcs ) ;
2015-09-01 16:22:52 +09:00
if ( ret < 0 ) {
2011-12-13 14:46:57 +09:00
DRM_ERROR ( " failed to initialize framebuffer \n " ) ;
2015-09-01 16:22:52 +09:00
goto err ;
2011-10-04 19:19:01 +09:00
}
2018-03-30 15:11:32 +01:00
return fb ;
2015-09-01 16:22:52 +09:00
err :
2018-03-30 15:11:32 +01:00
kfree ( fb ) ;
2015-09-01 16:22:52 +09:00
return ERR_PTR ( ret ) ;
2011-10-04 19:19:01 +09:00
}
2011-12-13 14:46:57 +09:00
static struct drm_framebuffer *
exynos_user_fb_create ( struct drm_device * dev , struct drm_file * file_priv ,
2015-11-11 19:11:29 +02:00
const struct drm_mode_fb_cmd2 * mode_cmd )
2011-10-04 19:19:01 +09:00
{
2017-07-12 12:09:22 +02:00
const struct drm_format_info * info = drm_get_format_info ( dev , mode_cmd ) ;
2015-10-02 09:33:47 +09:00
struct exynos_drm_gem * exynos_gem [ MAX_FB_BUFFER ] ;
2015-09-01 16:22:53 +09:00
struct drm_framebuffer * fb ;
int i ;
int ret ;
2011-12-15 14:36:22 +09:00
2017-07-12 12:09:22 +02:00
for ( i = 0 ; i < info - > num_planes ; i + + ) {
unsigned int height = ( i = = 0 ) ? mode_cmd - > height :
DIV_ROUND_UP ( mode_cmd - > height , info - > vsub ) ;
unsigned long size = height * mode_cmd - > pitches [ i ] +
mode_cmd - > offsets [ i ] ;
2018-07-09 15:44:32 +02:00
exynos_gem [ i ] = exynos_drm_gem_get ( file_priv ,
mode_cmd - > handles [ i ] ) ;
if ( ! exynos_gem [ i ] ) {
2011-12-15 14:36:22 +09:00
DRM_ERROR ( " failed to lookup gem object \n " ) ;
2013-02-12 21:23:54 +09:00
ret = - ENOENT ;
2015-09-01 16:22:51 +09:00
goto err ;
2011-12-15 14:36:22 +09:00
}
2017-07-12 12:09:22 +02:00
if ( size > exynos_gem [ i ] - > size ) {
i + + ;
ret = - EINVAL ;
goto err ;
}
2011-12-15 14:36:22 +09:00
}
2015-10-02 09:33:47 +09:00
fb = exynos_drm_framebuffer_init ( dev , mode_cmd , exynos_gem , i ) ;
2015-09-01 16:22:53 +09:00
if ( IS_ERR ( fb ) ) {
ret = PTR_ERR ( fb ) ;
2015-09-01 16:22:51 +09:00
goto err ;
2012-12-14 13:39:03 +09:00
}
2015-09-01 16:22:53 +09:00
return fb ;
2013-02-12 21:23:54 +09:00
2015-09-01 16:22:51 +09:00
err :
2015-09-01 16:22:53 +09:00
while ( i - - )
2018-07-09 15:44:32 +02:00
exynos_drm_gem_put ( exynos_gem [ i ] ) ;
2013-02-12 21:23:54 +09:00
return ERR_PTR ( ret ) ;
2011-10-04 19:19:01 +09:00
}
2015-11-30 14:53:21 +01:00
dma_addr_t exynos_drm_fb_dma_addr ( struct drm_framebuffer * fb , int index )
2011-10-04 19:19:01 +09:00
{
2018-03-30 15:11:31 +01:00
struct exynos_drm_gem * exynos_gem ;
2011-10-04 19:19:01 +09:00
2017-05-22 10:40:52 +02:00
if ( WARN_ON_ONCE ( index > = MAX_FB_BUFFER ) )
return 0 ;
2011-12-15 14:36:22 +09:00
2018-03-30 15:11:31 +01:00
exynos_gem = to_exynos_gem ( fb - > obj [ index ] ) ;
return exynos_gem - > dma_addr + fb - > offsets [ index ] ;
2011-10-04 19:19:01 +09:00
}
2017-01-20 12:51:41 +09:00
static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = {
2017-07-20 15:01:16 +02:00
. atomic_commit_tail = drm_atomic_helper_commit_tail_rpm ,
2017-01-20 12:51:41 +09:00
} ;
2012-05-17 13:27:23 +02:00
static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
2011-12-13 14:46:57 +09:00
. fb_create = exynos_user_fb_create ,
2017-12-05 19:24:57 +01:00
. output_poll_changed = drm_fb_helper_output_poll_changed ,
2018-03-21 12:20:25 +02:00
. atomic_check = drm_atomic_helper_check ,
2017-01-20 12:51:41 +09:00
. atomic_commit = drm_atomic_helper_commit ,
2011-10-04 19:19:01 +09:00
} ;
void exynos_drm_mode_config_init ( struct drm_device * dev )
{
dev - > mode_config . min_width = 0 ;
dev - > mode_config . min_height = 0 ;
/*
* set max width and height as default value ( 4096 x4096 ) .
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb ( ) .
*/
dev - > mode_config . max_width = 4096 ;
dev - > mode_config . max_height = 4096 ;
dev - > mode_config . funcs = & exynos_drm_mode_config_funcs ;
2017-01-20 12:51:41 +09:00
dev - > mode_config . helper_private = & exynos_drm_mode_config_helpers ;
2017-08-22 16:19:37 +02:00
dev - > mode_config . allow_fb_modifiers = true ;
2018-03-21 12:20:25 +02:00
dev - > mode_config . normalize_zpos = true ;
2011-10-04 19:19:01 +09:00
}