2014-08-22 18:36:26 +08:00
/*
* Copyright ( C ) Fuzhou Rockchip Electronics Co . Ltd
* Author : Mark Yao < mark . yao @ rock - chips . com >
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <drm/drm.h>
# include <drm/drmP.h>
2015-11-30 18:22:42 +08:00
# include <drm/drm_atomic.h>
2014-08-22 18:36:26 +08:00
# include <drm/drm_fb_helper.h>
# include <drm/drm_crtc_helper.h>
# 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"
2016-07-24 14:57:44 +08:00
# include "rockchip_drm_psr.h"
2014-08-22 18:36:26 +08:00
# define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
struct rockchip_drm_fb {
struct drm_framebuffer fb ;
struct drm_gem_object * obj [ ROCKCHIP_MAX_FB_BUFFER ] ;
} ;
struct drm_gem_object * rockchip_fb_get_gem_obj ( struct drm_framebuffer * fb ,
unsigned int plane )
{
struct rockchip_drm_fb * rk_fb = to_rockchip_fb ( fb ) ;
if ( plane > = ROCKCHIP_MAX_FB_BUFFER )
return NULL ;
return rk_fb - > obj [ plane ] ;
}
static void rockchip_drm_fb_destroy ( struct drm_framebuffer * fb )
{
struct rockchip_drm_fb * rockchip_fb = to_rockchip_fb ( fb ) ;
int i ;
2016-07-15 15:23:22 +02:00
for ( i = 0 ; i < ROCKCHIP_MAX_FB_BUFFER ; i + + )
2017-08-11 15:33:06 +03:00
drm_gem_object_put_unlocked ( rockchip_fb - > obj [ i ] ) ;
2014-08-22 18:36:26 +08:00
drm_framebuffer_cleanup ( fb ) ;
kfree ( rockchip_fb ) ;
}
static int rockchip_drm_fb_create_handle ( struct drm_framebuffer * fb ,
struct drm_file * file_priv ,
unsigned int * handle )
{
struct rockchip_drm_fb * rockchip_fb = to_rockchip_fb ( fb ) ;
return drm_gem_handle_create ( file_priv ,
rockchip_fb - > obj [ 0 ] , handle ) ;
}
2016-07-24 14:57:44 +08:00
static int rockchip_drm_fb_dirty ( struct drm_framebuffer * fb ,
struct drm_file * file ,
unsigned int flags , unsigned int color ,
struct drm_clip_rect * clips ,
unsigned int num_clips )
{
2016-08-18 12:01:46 -07:00
rockchip_drm_psr_flush_all ( fb - > dev ) ;
2016-07-24 14:57:44 +08:00
return 0 ;
}
2015-12-15 12:21:12 +01:00
static const struct drm_framebuffer_funcs rockchip_drm_fb_funcs = {
2014-08-22 18:36:26 +08:00
. destroy = rockchip_drm_fb_destroy ,
. create_handle = rockchip_drm_fb_create_handle ,
2016-07-24 14:57:44 +08:00
. dirty = rockchip_drm_fb_dirty ,
2014-08-22 18:36:26 +08:00
} ;
static struct rockchip_drm_fb *
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 )
{
struct rockchip_drm_fb * rockchip_fb ;
int ret ;
int i ;
rockchip_fb = kzalloc ( sizeof ( * rockchip_fb ) , GFP_KERNEL ) ;
if ( ! rockchip_fb )
return ERR_PTR ( - ENOMEM ) ;
drm: Pass 'dev' to drm_helper_mode_fill_fb_struct()
Pass the drm_device to drm_helper_mode_fill_fb_struct() so that we can
populate fb->dev early. Will make it easier to use the fb before we
register it.
@@
identifier fb, mode_cmd;
@@
void drm_helper_mode_fill_fb_struct(
+ struct drm_device *dev,
struct drm_framebuffer *fb,
const struct drm_mode_fb_cmd2 *mode_cmd
);
@@
identifier fb, mode_cmd;
@@
void drm_helper_mode_fill_fb_struct(
+ struct drm_device *dev,
struct drm_framebuffer *fb,
const struct drm_mode_fb_cmd2 *mode_cmd
)
{ ... }
@@
function func;
identifier dev;
expression E1, E2;
@@
func(struct drm_device *dev, ...)
{
...
drm_helper_mode_fill_fb_struct(
+ dev,
E1, E2);
...
}
@@
expression E1, E2;
@@
drm_helper_mode_fill_fb_struct(
+ dev,
E1, E2);
v2: Rerun spatch due to code changes
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1481748539-18283-1-git-send-email-ville.syrjala@linux.intel.com
2016-12-14 22:48:59 +02:00
drm_helper_mode_fill_fb_struct ( dev , & rockchip_fb - > fb , mode_cmd ) ;
2014-08-22 18:36:26 +08:00
for ( i = 0 ; i < num_planes ; i + + )
rockchip_fb - > obj [ i ] = obj [ i ] ;
ret = drm_framebuffer_init ( dev , & rockchip_fb - > fb ,
& rockchip_drm_fb_funcs ) ;
if ( ret ) {
dev_err ( dev - > dev , " Failed to initialize framebuffer: %d \n " ,
ret ) ;
kfree ( rockchip_fb ) ;
return ERR_PTR ( ret ) ;
}
return rockchip_fb ;
}
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
{
struct rockchip_drm_fb * rockchip_fb ;
struct drm_gem_object * objs [ ROCKCHIP_MAX_FB_BUFFER ] ;
struct drm_gem_object * obj ;
unsigned int hsub ;
unsigned int vsub ;
int num_planes ;
int ret ;
int i ;
hsub = drm_format_horz_chroma_subsampling ( mode_cmd - > pixel_format ) ;
vsub = drm_format_vert_chroma_subsampling ( mode_cmd - > pixel_format ) ;
num_planes = min ( drm_format_num_planes ( mode_cmd - > pixel_format ) ,
ROCKCHIP_MAX_FB_BUFFER ) ;
for ( i = 0 ; i < num_planes ; i + + ) {
unsigned int width = mode_cmd - > width / ( i ? hsub : 1 ) ;
unsigned int height = mode_cmd - > height / ( i ? vsub : 1 ) ;
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 ) {
dev_err ( dev - > dev , " Failed to lookup GEM object \n " ) ;
ret = - ENXIO ;
goto err_gem_object_unreference ;
}
min_size = ( height - 1 ) * mode_cmd - > pitches [ i ] +
mode_cmd - > offsets [ i ] +
width * drm_format_plane_cpp ( mode_cmd - > pixel_format , i ) ;
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 ;
}
rockchip_fb = rockchip_fb_alloc ( dev , mode_cmd , objs , i ) ;
if ( IS_ERR ( rockchip_fb ) ) {
ret = PTR_ERR ( rockchip_fb ) ;
goto err_gem_object_unreference ;
}
return & rockchip_fb - > fb ;
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 ) ;
}
static void rockchip_drm_output_poll_changed ( struct drm_device * dev )
{
struct rockchip_drm_private * private = dev - > dev_private ;
2017-03-29 16:44:01 +02:00
drm_fb_helper_hotplug_event ( & private - > fbdev_helper ) ;
2014-08-22 18:36:26 +08:00
}
2017-01-02 11:16:13 +02:00
static const struct drm_mode_config_helper_funcs rockchip_mode_config_helpers = {
2017-07-20 15:01:16 +02: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 ,
. output_poll_changed = rockchip_drm_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 )
{
struct rockchip_drm_fb * rockchip_fb ;
rockchip_fb = rockchip_fb_alloc ( dev , mode_cmd , & obj , 1 ) ;
if ( IS_ERR ( rockchip_fb ) )
2016-11-10 22:10:56 +01:00
return ERR_CAST ( rockchip_fb ) ;
2014-08-22 18:36:26 +08:00
return & rockchip_fb - > fb ;
}
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
}