2016-01-04 18:36:34 +01:00
/*
* Copyright ( c ) 2015 MediaTek Inc .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* 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 <drm/drmP.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_fb_helper.h>
# include <drm/drm_gem.h>
2018-05-18 14:47:04 +01:00
# include <drm/drm_gem_framebuffer_helper.h>
2016-01-04 18:36:34 +01:00
# include <linux/dma-buf.h>
# include <linux/reservation.h>
# include "mtk_drm_drv.h"
# include "mtk_drm_fb.h"
# include "mtk_drm_gem.h"
static const struct drm_framebuffer_funcs mtk_drm_fb_funcs = {
2018-05-18 14:47:04 +01:00
. create_handle = drm_gem_fb_create_handle ,
. destroy = drm_gem_fb_destroy ,
2016-01-04 18:36:34 +01:00
} ;
2018-05-18 14:47:05 +01:00
static struct drm_framebuffer * mtk_drm_framebuffer_init ( struct drm_device * dev ,
2016-01-04 18:36:34 +01:00
const struct drm_mode_fb_cmd2 * mode ,
struct drm_gem_object * obj )
{
2018-05-18 14:47:05 +01:00
struct drm_framebuffer * fb ;
2016-01-04 18:36:34 +01:00
int ret ;
if ( drm_format_num_planes ( mode - > pixel_format ) ! = 1 )
return ERR_PTR ( - EINVAL ) ;
2018-05-18 14:47:05 +01:00
fb = kzalloc ( sizeof ( * fb ) , GFP_KERNEL ) ;
if ( ! fb )
2016-01-04 18:36:34 +01:00
return ERR_PTR ( - ENOMEM ) ;
2018-05-18 14:47:05 +01:00
drm_helper_mode_fill_fb_struct ( dev , fb , mode ) ;
2016-01-04 18:36:34 +01:00
2018-05-18 14:47:05 +01:00
fb - > obj [ 0 ] = obj ;
2016-01-04 18:36:34 +01:00
2018-05-18 14:47:05 +01:00
ret = drm_framebuffer_init ( dev , fb , & mtk_drm_fb_funcs ) ;
2016-01-04 18:36:34 +01:00
if ( ret ) {
DRM_ERROR ( " failed to initialize framebuffer \n " ) ;
2018-05-18 14:47:05 +01:00
kfree ( fb ) ;
2016-01-04 18:36:34 +01:00
return ERR_PTR ( ret ) ;
}
2018-05-18 14:47:05 +01:00
return fb ;
2016-01-04 18:36:34 +01:00
}
/*
* Wait for any exclusive fence in fb ' s gem object ' s reservation object .
*
* Returns - ERESTARTSYS if interrupted , else 0.
*/
int mtk_fb_wait ( struct drm_framebuffer * fb )
{
struct drm_gem_object * gem ;
struct reservation_object * resv ;
long ret ;
if ( ! fb )
return 0 ;
2018-05-18 14:47:04 +01:00
gem = fb - > obj [ 0 ] ;
2016-01-04 18:36:34 +01:00
if ( ! gem | | ! gem - > dma_buf | | ! gem - > dma_buf - > resv )
return 0 ;
resv = gem - > dma_buf - > resv ;
ret = reservation_object_wait_timeout_rcu ( resv , false , true ,
MAX_SCHEDULE_TIMEOUT ) ;
/* MAX_SCHEDULE_TIMEOUT on success, -ERESTARTSYS if interrupted */
if ( WARN_ON ( ret < 0 ) )
return ret ;
return 0 ;
}
struct drm_framebuffer * mtk_drm_mode_fb_create ( struct drm_device * dev ,
struct drm_file * file ,
const struct drm_mode_fb_cmd2 * cmd )
{
2018-05-18 14:47:05 +01:00
struct drm_framebuffer * fb ;
2016-01-04 18:36:34 +01:00
struct drm_gem_object * gem ;
unsigned int width = cmd - > width ;
unsigned int height = cmd - > height ;
unsigned int size , bpp ;
int ret ;
if ( drm_format_num_planes ( cmd - > pixel_format ) ! = 1 )
return ERR_PTR ( - EINVAL ) ;
2016-05-18 18:07:31 +02:00
gem = drm_gem_object_lookup ( file , cmd - > handles [ 0 ] ) ;
2016-01-04 18:36:34 +01:00
if ( ! gem )
return ERR_PTR ( - ENOENT ) ;
bpp = drm_format_plane_cpp ( cmd - > pixel_format , 0 ) ;
size = ( height - 1 ) * cmd - > pitches [ 0 ] + width * bpp ;
size + = cmd - > offsets [ 0 ] ;
if ( gem - > size < size ) {
ret = - EINVAL ;
goto unreference ;
}
2018-05-18 14:47:05 +01:00
fb = mtk_drm_framebuffer_init ( dev , cmd , gem ) ;
if ( IS_ERR ( fb ) ) {
ret = PTR_ERR ( fb ) ;
2016-01-04 18:36:34 +01:00
goto unreference ;
}
2018-05-18 14:47:05 +01:00
return fb ;
2016-01-04 18:36:34 +01:00
unreference :
2017-08-11 15:32:59 +03:00
drm_gem_object_put_unlocked ( gem ) ;
2016-01-04 18:36:34 +01:00
return ERR_PTR ( ret ) ;
}