2019-05-29 07:17:56 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-08-22 18:36:26 +08:00
/*
* Copyright ( C ) Fuzhou Rockchip Electronics Co . Ltd
* Author : Mark Yao < mark . yao @ rock - chips . com >
*/
# include <linux/kernel.h>
2019-07-16 08:42:19 +02:00
2014-08-22 18:36:26 +08:00
# include <drm/drm.h>
2015-11-30 18:22:42 +08:00
# include <drm/drm_atomic.h>
2019-06-11 12:08:20 -04:00
# include <drm/drm_damage_helper.h>
2014-08-22 18:36:26 +08:00
# include <drm/drm_fb_helper.h>
2019-07-16 08:42:19 +02:00
# include <drm/drm_fourcc.h>
2018-03-30 15:11:18 +01:00
# include <drm/drm_gem_framebuffer_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2014-08-22 18:36:26 +08:00
# include "rockchip_drm_drv.h"
2016-05-10 17:03:55 +01:00
# include "rockchip_drm_fb.h"
2014-08-22 18:36:26 +08:00
# include "rockchip_drm_gem.h"
2015-12-15 12:21:12 +01:00
static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
2018-03-30 15:11:18 +01:00
. destroy = drm_gem_fb_destroy ,
. create_handle = drm_gem_fb_create_handle ,
2019-06-11 12:08:20 -04:00
. dirty = drm_atomic_helper_dirtyfb ,
2014-08-22 18:36:26 +08:00
} ;
2018-03-30 15:11:19 +01:00
static struct drm_framebuffer *
2015-11-11 19:11:29 +02:00
rockchip_fb_alloc ( struct drm_device * dev , const struct drm_mode_fb_cmd2 * mode_cmd ,
2014-08-22 18:36:26 +08:00
struct drm_gem_object * * obj , unsigned int num_planes )
{
2018-03-30 15:11:19 +01:00
struct drm_framebuffer * fb ;
2014-08-22 18:36:26 +08:00
int ret ;
int i ;
2018-03-30 15:11:19 +01:00
fb = kzalloc ( sizeof ( * fb ) , GFP_KERNEL ) ;
if ( ! fb )
2014-08-22 18:36:26 +08:00
return ERR_PTR ( - ENOMEM ) ;
2018-03-30 15:11:19 +01:00
drm_helper_mode_fill_fb_struct ( dev , fb , mode_cmd ) ;
2014-08-22 18:36:26 +08:00
for ( i = 0 ; i < num_planes ; i + + )
2018-03-30 15:11:19 +01:00
fb - > obj [ i ] = obj [ i ] ;
2014-08-22 18:36:26 +08:00
2018-03-30 15:11:19 +01:00
ret = drm_framebuffer_init ( dev , fb , & rockchip_drm_fb_funcs ) ;
2014-08-22 18:36:26 +08:00
if ( ret ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev ,
" Failed to initialize framebuffer: %d \n " ,
ret ) ;
2018-03-30 15:11:19 +01:00
kfree ( fb ) ;
2014-08-22 18:36:26 +08:00
return ERR_PTR ( ret ) ;
}
2018-03-30 15:11:19 +01:00
return fb ;
2014-08-22 18:36:26 +08:00
}
static struct drm_framebuffer *
rockchip_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 )
2014-08-22 18:36:26 +08:00
{
2019-05-16 12:31:47 +02:00
const struct drm_format_info * info = drm_get_format_info ( dev ,
mode_cmd ) ;
2018-03-30 15:11:19 +01:00
struct drm_framebuffer * fb ;
2014-08-22 18:36:26 +08:00
struct drm_gem_object * objs [ ROCKCHIP_MAX_FB_BUFFER ] ;
struct drm_gem_object * obj ;
2019-05-16 12:31:47 +02:00
int num_planes = min_t ( int , info - > num_planes , ROCKCHIP_MAX_FB_BUFFER ) ;
2014-08-22 18:36:26 +08:00
int ret ;
int i ;
for ( i = 0 ; i < num_planes ; i + + ) {
2019-05-16 12:31:48 +02:00
unsigned int width = mode_cmd - > width / ( i ? info - > hsub : 1 ) ;
unsigned int height = mode_cmd - > height / ( i ? info - > vsub : 1 ) ;
2014-08-22 18:36:26 +08:00
unsigned int min_size ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( file_priv , mode_cmd - > handles [ i ] ) ;
2014-08-22 18:36:26 +08:00
if ( ! obj ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev ,
" Failed to lookup GEM object \n " ) ;
2014-08-22 18:36:26 +08:00
ret = - ENXIO ;
goto err_gem_object_unreference ;
}
min_size = ( height - 1 ) * mode_cmd - > pitches [ i ] +
mode_cmd - > offsets [ i ] +
2019-05-16 12:31:52 +02:00
width * info - > cpp [ i ] ;
2014-08-22 18:36:26 +08:00
if ( obj - > size < min_size ) {
2017-08-11 15:33:06 +03:00
drm_gem_object_put_unlocked ( obj ) ;
2014-08-22 18:36:26 +08:00
ret = - EINVAL ;
goto err_gem_object_unreference ;
}
objs [ i ] = obj ;
}
2018-03-30 15:11:19 +01:00
fb = rockchip_fb_alloc ( dev , mode_cmd , objs , i ) ;
if ( IS_ERR ( fb ) ) {
ret = PTR_ERR ( fb ) ;
2014-08-22 18:36:26 +08:00
goto err_gem_object_unreference ;
}
2018-03-30 15:11:19 +01:00
return fb ;
2014-08-22 18:36:26 +08:00
err_gem_object_unreference :
for ( i - - ; i > = 0 ; i - - )
2017-08-11 15:33:06 +03:00
drm_gem_object_put_unlocked ( objs [ i ] ) ;
2014-08-22 18:36:26 +08:00
return ERR_PTR ( ret ) ;
}
2017-01-02 11:16:13 +02:00
static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
2019-06-11 12:08:25 -04:00
. atomic_commit_tail = drm_atomic_helper_commit_tail_rpm ,
2016-06-08 14:19:12 +02:00
} ;
2015-11-30 18:22:42 +08:00
2014-08-22 18:36:26 +08:00
static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = {
. fb_create = rockchip_user_fb_create ,
2017-12-05 19:25:03 +01:00
. output_poll_changed = drm_fb_helper_output_poll_changed ,
2015-11-30 18:22:42 +08:00
. atomic_check = drm_atomic_helper_check ,
2016-06-08 14:19:12 +02:00
. atomic_commit = drm_atomic_helper_commit ,
2014-08-22 18:36:26 +08:00
} ;
struct drm_framebuffer *
rockchip_drm_framebuffer_init ( struct drm_device * dev ,
2015-11-11 19:11:29 +02:00
const struct drm_mode_fb_cmd2 * mode_cmd ,
2014-08-22 18:36:26 +08:00
struct drm_gem_object * obj )
{
2018-03-30 15:11:19 +01:00
struct drm_framebuffer * fb ;
2014-08-22 18:36:26 +08:00
2018-03-30 15:11:19 +01:00
fb = rockchip_fb_alloc ( dev , mode_cmd , & obj , 1 ) ;
if ( IS_ERR ( fb ) )
return ERR_CAST ( fb ) ;
2014-08-22 18:36:26 +08:00
2018-03-30 15:11:19 +01:00
return fb ;
2014-08-22 18:36:26 +08:00
}
void rockchip_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 = & rockchip_drm_mode_config_funcs ;
2016-06-08 14:19:12 +02:00
dev - > mode_config . helper_private = & rockchip_mode_config_helpers ;
2014-08-22 18:36:26 +08:00
}