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 <drm/drm.h>
# include <drm/drm_fb_helper.h>
2019-07-16 08:42:19 +02:00
# include <drm/drm_fourcc.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"
# include "rockchip_drm_gem.h"
# include "rockchip_drm_fb.h"
2016-09-25 15:38:28 +08:00
# include "rockchip_drm_fbdev.h"
2014-08-22 18:36:26 +08:00
# define PREFERRED_BPP 32
# define to_drm_private(x) \
container_of ( x , struct rockchip_drm_private , fbdev_helper )
static int rockchip_fbdev_mmap ( struct fb_info * info ,
struct vm_area_struct * vma )
{
struct drm_fb_helper * helper = info - > par ;
struct rockchip_drm_private * private = to_drm_private ( helper ) ;
return rockchip_gem_mmap_buf ( private - > fbdev_bo , vma ) ;
}
2019-12-03 18:38:48 +02:00
static const struct fb_ops rockchip_drm_fbdev_ops = {
2014-08-22 18:36:26 +08:00
. owner = THIS_MODULE ,
2016-11-14 00:03:20 +01:00
DRM_FB_HELPER_DEFAULT_OPS ,
2014-08-22 18:36:26 +08:00
. fb_mmap = rockchip_fbdev_mmap ,
2015-07-22 14:58:03 +05:30
. fb_fillrect = drm_fb_helper_cfb_fillrect ,
. fb_copyarea = drm_fb_helper_cfb_copyarea ,
. fb_imageblit = drm_fb_helper_cfb_imageblit ,
2014-08-22 18:36:26 +08:00
} ;
static int rockchip_drm_fbdev_create ( struct drm_fb_helper * helper ,
struct drm_fb_helper_surface_size * sizes )
{
struct rockchip_drm_private * private = to_drm_private ( helper ) ;
struct drm_mode_fb_cmd2 mode_cmd = { 0 } ;
struct drm_device * dev = helper - > dev ;
struct rockchip_gem_object * rk_obj ;
struct drm_framebuffer * fb ;
unsigned int bytes_per_pixel ;
unsigned long offset ;
struct fb_info * fbi ;
size_t size ;
int ret ;
bytes_per_pixel = DIV_ROUND_UP ( sizes - > surface_bpp , 8 ) ;
mode_cmd . width = sizes - > surface_width ;
mode_cmd . height = sizes - > surface_height ;
mode_cmd . pitches [ 0 ] = sizes - > surface_width * bytes_per_pixel ;
mode_cmd . pixel_format = drm_mode_legacy_fb_format ( sizes - > surface_bpp ,
sizes - > surface_depth ) ;
size = mode_cmd . pitches [ 0 ] * mode_cmd . height ;
2015-01-12 14:58:23 +08:00
rk_obj = rockchip_gem_create_object ( dev , size , true ) ;
2014-08-22 18:36:26 +08:00
if ( IS_ERR ( rk_obj ) )
return - ENOMEM ;
private - > fbdev_bo = & rk_obj - > base ;
2015-07-22 14:58:03 +05:30
fbi = drm_fb_helper_alloc_fbi ( helper ) ;
if ( IS_ERR ( fbi ) ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev , " Failed to create framebuffer info. \n " ) ;
2015-07-22 14:58:03 +05:30
ret = PTR_ERR ( fbi ) ;
2017-02-07 17:16:03 +01:00
goto out ;
2014-08-22 18:36:26 +08:00
}
helper - > fb = rockchip_drm_framebuffer_init ( dev , & mode_cmd ,
private - > fbdev_bo ) ;
if ( IS_ERR ( helper - > fb ) ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev ,
" Failed to allocate DRM framebuffer. \n " ) ;
2014-08-22 18:36:26 +08:00
ret = PTR_ERR ( helper - > fb ) ;
2017-02-07 17:16:03 +01:00
goto out ;
2014-08-22 18:36:26 +08:00
}
fbi - > fbops = & rockchip_drm_fbdev_ops ;
fb = helper - > fb ;
2019-03-26 14:20:04 +01:00
drm_fb_helper_fill_info ( fbi , helper , sizes ) ;
2014-08-22 18:36:26 +08:00
offset = fbi - > var . xoffset * bytes_per_pixel ;
offset + = fbi - > var . yoffset * fb - > pitches [ 0 ] ;
dev - > mode_config . fb_base = 0 ;
fbi - > screen_base = rk_obj - > kvaddr + offset ;
fbi - > screen_size = rk_obj - > base . size ;
fbi - > fix . smem_len = rk_obj - > base . size ;
2016-06-09 10:46:32 -07:00
DRM_DEBUG_KMS ( " FB [%dx%d]-%d kvaddr=%p offset=%ld size=%zu \n " ,
2016-12-14 23:31:35 +02:00
fb - > width , fb - > height , fb - > format - > depth ,
rk_obj - > kvaddr ,
2014-08-22 18:36:26 +08:00
offset , size ) ;
2015-03-31 18:22:50 +08:00
2014-08-22 18:36:26 +08:00
return 0 ;
2017-02-07 17:16:03 +01:00
out :
2014-08-22 18:36:26 +08:00
rockchip_gem_free_object ( & rk_obj - > base ) ;
return ret ;
}
static const struct drm_fb_helper_funcs rockchip_drm_fb_helper_funcs = {
. fb_probe = rockchip_drm_fbdev_create ,
} ;
int rockchip_drm_fbdev_init ( struct drm_device * dev )
{
struct rockchip_drm_private * private = dev - > dev_private ;
struct drm_fb_helper * helper ;
int ret ;
if ( ! dev - > mode_config . num_crtc | | ! dev - > mode_config . num_connector )
return - EINVAL ;
helper = & private - > fbdev_helper ;
drm_fb_helper_prepare ( dev , helper , & rockchip_drm_fb_helper_funcs ) ;
2020-03-05 17:34:28 +05:30
ret = drm_fb_helper_init ( dev , helper ) ;
2014-08-22 18:36:26 +08:00
if ( ret < 0 ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev ,
" Failed to initialize drm fb helper - %d. \n " ,
ret ) ;
2014-08-22 18:36:26 +08:00
return ret ;
}
ret = drm_fb_helper_initial_config ( helper , PREFERRED_BPP ) ;
if ( ret < 0 ) {
2017-09-15 02:36:03 -06:00
DRM_DEV_ERROR ( dev - > dev ,
" Failed to set initial hw config - %d. \n " ,
ret ) ;
2014-08-22 18:36:26 +08:00
goto err_drm_fb_helper_fini ;
}
return 0 ;
err_drm_fb_helper_fini :
drm_fb_helper_fini ( helper ) ;
return ret ;
}
void rockchip_drm_fbdev_fini ( struct drm_device * dev )
{
struct rockchip_drm_private * private = dev - > dev_private ;
struct drm_fb_helper * helper ;
helper = & private - > fbdev_helper ;
2015-07-22 14:58:03 +05:30
drm_fb_helper_unregister_fbi ( helper ) ;
2014-08-22 18:36:26 +08:00
if ( helper - > fb )
2017-08-11 15:33:06 +03:00
drm_framebuffer_put ( helper - > fb ) ;
2014-08-22 18:36:26 +08:00
drm_fb_helper_fini ( helper ) ;
}