2012-07-02 16:37:47 +02:00
/*
* drm kms / fb cma ( contiguous memory allocator ) helper functions
*
* Copyright ( C ) 2012 Analog Device Inc .
* Author : Lars - Peter Clausen < lars @ metafoo . de >
*
* Based on udl_fbdev . c
* Copyright ( C ) 2012 Red Hat
*
* 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 .
* 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>
2016-11-14 11:07:31 +01:00
# include <drm/drm_atomic.h>
2012-07-02 16:37:47 +02:00
# include <drm/drm_crtc.h>
# include <drm/drm_fb_helper.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_gem_cma_helper.h>
# include <drm/drm_fb_cma_helper.h>
2016-11-14 11:07:31 +01:00
# include <linux/dma-buf.h>
2016-06-07 13:18:09 +01:00
# include <linux/dma-mapping.h>
2012-07-02 16:37:47 +02:00
# include <linux/module.h>
2016-11-14 11:07:31 +01:00
# include <linux/reservation.h>
2012-07-02 16:37:47 +02:00
2016-04-28 17:18:35 +02:00
# define DEFAULT_FBDEFIO_DELAY_MS 50
2012-07-02 16:37:47 +02:00
struct drm_fb_cma {
struct drm_framebuffer fb ;
struct drm_gem_cma_object * obj [ 4 ] ;
} ;
struct drm_fbdev_cma {
struct drm_fb_helper fb_helper ;
struct drm_fb_cma * fb ;
2016-12-29 21:48:31 +01:00
const struct drm_framebuffer_funcs * fb_funcs ;
2012-07-02 16:37:47 +02:00
} ;
2016-04-28 17:18:35 +02:00
/**
* DOC : framebuffer cma helper functions
*
* Provides helper functions for creating a cma ( contiguous memory allocator )
* backed framebuffer .
*
2016-12-29 21:48:34 +01:00
* drm_fb_cma_create ( ) is used in the & drm_mode_config_funcs . fb_create
2016-05-11 18:09:18 +02:00
* callback function to create a cma backed framebuffer .
2016-04-28 17:18:35 +02:00
*
* An fbdev framebuffer backed by cma is also available by calling
* drm_fbdev_cma_init ( ) . drm_fbdev_cma_fini ( ) tears it down .
2016-12-29 21:48:34 +01:00
* If the & drm_framebuffer_funcs . dirty callback is set , fb_deferred_io will be
* set up automatically . & drm_framebuffer_funcs . dirty is called by
* drm_fb_helper_deferred_io ( ) in process context ( & struct delayed_work ) .
2016-04-28 17:18:35 +02:00
*
2016-05-31 22:55:13 +02:00
* Example fbdev deferred io code : :
2016-04-28 17:18:35 +02:00
*
2016-12-29 21:48:31 +01:00
* static int driver_fb_dirty ( struct drm_framebuffer * fb ,
* struct drm_file * file_priv ,
* unsigned flags , unsigned color ,
* struct drm_clip_rect * clips ,
* unsigned num_clips )
2016-04-28 17:18:35 +02:00
* {
* struct drm_gem_cma_object * cma = drm_fb_cma_get_gem_obj ( fb , 0 ) ;
* . . . push changes . . .
* return 0 ;
* }
*
2016-12-29 21:48:31 +01:00
* static struct drm_framebuffer_funcs driver_fb_funcs = {
2016-04-28 17:18:35 +02:00
* . destroy = drm_fb_cma_destroy ,
* . create_handle = drm_fb_cma_create_handle ,
2016-12-29 21:48:31 +01:00
* . dirty = driver_fb_dirty ,
2016-04-28 17:18:35 +02:00
* } ;
*
2016-12-29 21:48:31 +01:00
* Initialize : :
2016-04-28 17:18:35 +02:00
*
* fbdev = drm_fbdev_cma_init_with_funcs ( dev , 16 ,
* dev - > mode_config . num_crtc ,
* dev - > mode_config . num_connector ,
2016-12-29 21:48:31 +01:00
* & driver_fb_funcs ) ;
2016-04-28 17:18:35 +02:00
*
*/
2012-07-02 16:37:47 +02:00
static inline struct drm_fbdev_cma * to_fbdev_cma ( struct drm_fb_helper * helper )
{
return container_of ( helper , struct drm_fbdev_cma , fb_helper ) ;
}
static inline struct drm_fb_cma * to_fb_cma ( struct drm_framebuffer * fb )
{
return container_of ( fb , struct drm_fb_cma , fb ) ;
}
2016-04-28 17:18:35 +02:00
void drm_fb_cma_destroy ( struct drm_framebuffer * fb )
2012-07-02 16:37:47 +02:00
{
struct drm_fb_cma * fb_cma = to_fb_cma ( fb ) ;
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( fb_cma - > obj [ i ] )
2017-02-28 15:46:41 +01:00
drm_gem_object_put_unlocked ( & fb_cma - > obj [ i ] - > base ) ;
2012-07-02 16:37:47 +02:00
}
drm_framebuffer_cleanup ( fb ) ;
kfree ( fb_cma ) ;
}
2016-04-28 17:18:35 +02:00
EXPORT_SYMBOL ( drm_fb_cma_destroy ) ;
2012-07-02 16:37:47 +02:00
2016-04-28 17:18:35 +02:00
int drm_fb_cma_create_handle ( struct drm_framebuffer * fb ,
2012-07-02 16:37:47 +02:00
struct drm_file * file_priv , unsigned int * handle )
{
struct drm_fb_cma * fb_cma = to_fb_cma ( fb ) ;
return drm_gem_handle_create ( file_priv ,
& fb_cma - > obj [ 0 ] - > base , handle ) ;
}
2016-04-28 17:18:35 +02:00
EXPORT_SYMBOL ( drm_fb_cma_create_handle ) ;
2012-07-02 16:37:47 +02:00
static struct drm_framebuffer_funcs drm_fb_cma_funcs = {
. destroy = drm_fb_cma_destroy ,
. create_handle = drm_fb_cma_create_handle ,
} ;
static struct drm_fb_cma * drm_fb_cma_alloc ( struct drm_device * dev ,
2016-01-20 10:59:34 +00:00
const struct drm_mode_fb_cmd2 * mode_cmd ,
struct drm_gem_cma_object * * obj ,
2016-05-12 20:25:21 +02:00
unsigned int num_planes , const struct drm_framebuffer_funcs * funcs )
2012-07-02 16:37:47 +02:00
{
struct drm_fb_cma * fb_cma ;
int ret ;
int i ;
fb_cma = kzalloc ( sizeof ( * fb_cma ) , GFP_KERNEL ) ;
if ( ! fb_cma )
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 , & fb_cma - > fb , mode_cmd ) ;
2012-12-13 23:38:38 +01:00
for ( i = 0 ; i < num_planes ; i + + )
fb_cma - > obj [ i ] = obj [ i ] ;
2016-04-28 17:18:35 +02:00
ret = drm_framebuffer_init ( dev , & fb_cma - > fb , funcs ) ;
2012-07-02 16:37:47 +02:00
if ( ret ) {
2013-05-21 23:13:12 +09:00
dev_err ( dev - > dev , " Failed to initialize framebuffer: %d \n " , ret ) ;
2012-07-02 16:37:47 +02:00
kfree ( fb_cma ) ;
return ERR_PTR ( ret ) ;
}
return fb_cma ;
}
/**
2016-05-12 20:25:22 +02:00
* drm_fb_cma_create_with_funcs ( ) - helper function for the
2016-12-29 21:48:34 +01:00
* & drm_mode_config_funcs . fb_create
* callback
2016-05-31 23:11:12 +02:00
* @ dev : DRM device
* @ file_priv : drm file for the ioctl call
* @ mode_cmd : metadata from the userspace fb creation request
* @ funcs : vtable to be used for the new framebuffer object
2012-07-02 16:37:47 +02:00
*
2016-05-12 20:25:22 +02:00
* This can be used to set & drm_framebuffer_funcs for drivers that need the
2016-12-29 21:48:34 +01:00
* & drm_framebuffer_funcs . dirty callback . Use drm_fb_cma_create ( ) if you don ' t
* need to change & drm_framebuffer_funcs .
2012-07-02 16:37:47 +02:00
*/
2016-05-12 20:25:22 +02:00
struct drm_framebuffer * drm_fb_cma_create_with_funcs ( struct drm_device * dev ,
struct drm_file * file_priv , const struct drm_mode_fb_cmd2 * mode_cmd ,
const struct drm_framebuffer_funcs * funcs )
2012-07-02 16:37:47 +02:00
{
2016-10-18 01:41:11 +03:00
const struct drm_format_info * info ;
2012-07-02 16:37:47 +02:00
struct drm_fb_cma * fb_cma ;
struct drm_gem_cma_object * objs [ 4 ] ;
struct drm_gem_object * obj ;
int ret ;
int i ;
2017-03-21 20:12:16 +02:00
info = drm_get_format_info ( dev , mode_cmd ) ;
2016-10-18 01:41:11 +03:00
if ( ! info )
return ERR_PTR ( - EINVAL ) ;
2012-07-02 16:37:47 +02:00
2016-10-18 01:41:11 +03:00
for ( i = 0 ; i < info - > num_planes ; i + + ) {
unsigned int width = mode_cmd - > width / ( i ? info - > hsub : 1 ) ;
unsigned int height = mode_cmd - > height / ( i ? info - > vsub : 1 ) ;
2012-07-02 16:37:47 +02:00
unsigned int min_size ;
2016-05-09 11:04:54 +01:00
obj = drm_gem_object_lookup ( file_priv , mode_cmd - > handles [ i ] ) ;
2012-07-02 16:37:47 +02:00
if ( ! obj ) {
dev_err ( dev - > dev , " Failed to lookup GEM object \n " ) ;
2017-04-18 14:11:20 +02:00
ret = - ENOENT ;
2017-02-28 15:46:41 +01:00
goto err_gem_object_put ;
2012-07-02 16:37:47 +02:00
}
min_size = ( height - 1 ) * mode_cmd - > pitches [ i ]
2016-10-18 01:41:11 +03:00
+ width * info - > cpp [ i ]
2012-07-02 16:37:47 +02:00
+ mode_cmd - > offsets [ i ] ;
if ( obj - > size < min_size ) {
2017-02-28 15:46:41 +01:00
drm_gem_object_put_unlocked ( obj ) ;
2012-07-02 16:37:47 +02:00
ret = - EINVAL ;
2017-02-28 15:46:41 +01:00
goto err_gem_object_put ;
2012-07-02 16:37:47 +02:00
}
objs [ i ] = to_drm_gem_cma_obj ( obj ) ;
}
2016-05-12 20:25:22 +02:00
fb_cma = drm_fb_cma_alloc ( dev , mode_cmd , objs , i , funcs ) ;
2012-07-02 16:37:47 +02:00
if ( IS_ERR ( fb_cma ) ) {
ret = PTR_ERR ( fb_cma ) ;
2017-02-28 15:46:41 +01:00
goto err_gem_object_put ;
2012-07-02 16:37:47 +02:00
}
return & fb_cma - > fb ;
2017-02-28 15:46:41 +01:00
err_gem_object_put :
2012-07-02 16:37:47 +02:00
for ( i - - ; i > = 0 ; i - - )
2017-02-28 15:46:41 +01:00
drm_gem_object_put_unlocked ( & objs [ i ] - > base ) ;
2012-07-02 16:37:47 +02:00
return ERR_PTR ( ret ) ;
}
2016-05-12 20:25:22 +02:00
EXPORT_SYMBOL_GPL ( drm_fb_cma_create_with_funcs ) ;
/**
2016-12-29 21:48:34 +01:00
* drm_fb_cma_create ( ) - & drm_mode_config_funcs . fb_create callback function
2016-05-31 23:11:12 +02:00
* @ dev : DRM device
* @ file_priv : drm file for the ioctl call
* @ mode_cmd : metadata from the userspace fb creation request
2016-05-12 20:25:22 +02:00
*
* If your hardware has special alignment or pitch requirements these should be
* checked before calling this function . Use drm_fb_cma_create_with_funcs ( ) if
2016-12-29 21:48:34 +01:00
* you need to set & drm_framebuffer_funcs . dirty .
2016-05-12 20:25:22 +02:00
*/
struct drm_framebuffer * drm_fb_cma_create ( struct drm_device * dev ,
struct drm_file * file_priv , const struct drm_mode_fb_cmd2 * mode_cmd )
{
return drm_fb_cma_create_with_funcs ( dev , file_priv , mode_cmd ,
& drm_fb_cma_funcs ) ;
}
2012-07-02 16:37:47 +02:00
EXPORT_SYMBOL_GPL ( drm_fb_cma_create ) ;
/**
* drm_fb_cma_get_gem_obj ( ) - Get CMA GEM object for framebuffer
* @ fb : The framebuffer
* @ plane : Which plane
*
* Return the CMA GEM object for given framebuffer .
*
* This function will usually be called from the CRTC callback functions .
*/
struct drm_gem_cma_object * drm_fb_cma_get_gem_obj ( struct drm_framebuffer * fb ,
2016-05-31 23:11:12 +02:00
unsigned int plane )
2012-07-02 16:37:47 +02:00
{
struct drm_fb_cma * fb_cma = to_fb_cma ( fb ) ;
if ( plane > = 4 )
return NULL ;
return fb_cma - > obj [ plane ] ;
}
EXPORT_SYMBOL_GPL ( drm_fb_cma_get_gem_obj ) ;
2017-04-14 12:13:32 +02:00
/**
* drm_fb_cma_get_gem_addr ( ) - Get physical address for framebuffer
* @ fb : The framebuffer
* @ state : Which state of drm plane
* @ plane : Which plane
* Return the CMA GEM address for given framebuffer .
*
* This function will usually be called from the PLANE callback functions .
*/
dma_addr_t drm_fb_cma_get_gem_addr ( struct drm_framebuffer * fb ,
struct drm_plane_state * state ,
unsigned int plane )
{
struct drm_fb_cma * fb_cma = to_fb_cma ( fb ) ;
dma_addr_t paddr ;
if ( plane > = 4 )
return 0 ;
paddr = fb_cma - > obj [ plane ] - > paddr + fb - > offsets [ plane ] ;
paddr + = fb - > format - > cpp [ plane ] * ( state - > src_x > > 16 ) ;
paddr + = fb - > pitches [ plane ] * ( state - > src_y > > 16 ) ;
return paddr ;
}
EXPORT_SYMBOL_GPL ( drm_fb_cma_get_gem_addr ) ;
2016-11-14 11:07:31 +01:00
/**
* drm_fb_cma_prepare_fb ( ) - Prepare CMA framebuffer
* @ plane : Which plane
* @ state : Plane state attach fence to
*
2016-12-29 21:48:34 +01:00
* This should be set as the & struct drm_plane_helper_funcs . prepare_fb hook .
2016-11-14 11:07:31 +01:00
*
* This function checks if the plane FB has an dma - buf attached , extracts
* the exclusive fence and attaches it to plane state for the atomic helper
* to wait on .
*
* There is no need for cleanup_fb for CMA based framebuffer drivers .
*/
int drm_fb_cma_prepare_fb ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct dma_buf * dma_buf ;
struct dma_fence * fence ;
if ( ( plane - > state - > fb = = state - > fb ) | | ! state - > fb )
return 0 ;
dma_buf = drm_fb_cma_get_gem_obj ( state - > fb , 0 ) - > base . dma_buf ;
if ( dma_buf ) {
fence = reservation_object_get_excl_rcu ( dma_buf - > resv ) ;
drm_atomic_set_fence_for_plane ( state , fence ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( drm_fb_cma_prepare_fb ) ;
2012-12-10 10:46:43 -06:00
# ifdef CONFIG_DEBUG_FS
2013-08-20 00:53:08 +01:00
static void drm_fb_cma_describe ( struct drm_framebuffer * fb , struct seq_file * m )
2012-12-10 10:46:43 -06:00
{
struct drm_fb_cma * fb_cma = to_fb_cma ( fb ) ;
2016-10-18 01:41:11 +03:00
int i ;
2012-12-10 10:46:43 -06:00
seq_printf ( m , " fb: %dx%d@%4.4s \n " , fb - > width , fb - > height ,
2016-12-14 23:32:55 +02:00
( char * ) & fb - > format - > format ) ;
2012-12-10 10:46:43 -06:00
2016-12-15 16:29:27 +02:00
for ( i = 0 ; i < fb - > format - > num_planes ; i + + ) {
2012-12-10 10:46:43 -06:00
seq_printf ( m , " %d: offset=%d pitch=%d, obj: " ,
i , fb - > offsets [ i ] , fb - > pitches [ i ] ) ;
drm_gem_cma_describe ( fb_cma - > obj [ i ] , m ) ;
}
}
/**
* drm_fb_cma_debugfs_show ( ) - Helper to list CMA framebuffer objects
2016-05-31 23:11:12 +02:00
* in debugfs .
* @ m : output file
* @ arg : private data for the callback
2012-12-10 10:46:43 -06:00
*/
int drm_fb_cma_debugfs_show ( struct seq_file * m , void * arg )
{
struct drm_info_node * node = ( struct drm_info_node * ) m - > private ;
struct drm_device * dev = node - > minor - > dev ;
struct drm_framebuffer * fb ;
2015-07-09 23:32:34 +02:00
mutex_lock ( & dev - > mode_config . fb_lock ) ;
2015-07-09 23:44:35 +02:00
drm_for_each_fb ( fb , dev )
2012-12-10 10:46:43 -06:00
drm_fb_cma_describe ( fb , m ) ;
2015-07-09 23:32:34 +02:00
mutex_unlock ( & dev - > mode_config . fb_lock ) ;
2012-12-10 10:46:43 -06:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( drm_fb_cma_debugfs_show ) ;
# endif
2016-06-07 13:18:09 +01:00
static int drm_fb_cma_mmap ( struct fb_info * info , struct vm_area_struct * vma )
{
return dma_mmap_writecombine ( info - > device , vma , info - > screen_base ,
info - > fix . smem_start , info - > fix . smem_len ) ;
}
2012-07-02 16:37:47 +02:00
static struct fb_ops drm_fbdev_cma_ops = {
. owner = THIS_MODULE ,
2016-11-14 00:03:16 +01:00
DRM_FB_HELPER_DEFAULT_OPS ,
2015-07-22 14:58:20 +05:30
. fb_fillrect = drm_fb_helper_sys_fillrect ,
. fb_copyarea = drm_fb_helper_sys_copyarea ,
. fb_imageblit = drm_fb_helper_sys_imageblit ,
2016-06-07 13:18:09 +01:00
. fb_mmap = drm_fb_cma_mmap ,
2012-07-02 16:37:47 +02:00
} ;
2016-04-28 17:18:35 +02:00
static int drm_fbdev_cma_deferred_io_mmap ( struct fb_info * info ,
struct vm_area_struct * vma )
{
fb_deferred_io_mmap ( info , vma ) ;
vma - > vm_page_prot = pgprot_writecombine ( vma - > vm_page_prot ) ;
return 0 ;
}
static int drm_fbdev_cma_defio_init ( struct fb_info * fbi ,
struct drm_gem_cma_object * cma_obj )
{
struct fb_deferred_io * fbdefio ;
struct fb_ops * fbops ;
/*
* Per device structures are needed because :
* fbops : fb_deferred_io_cleanup ( ) clears fbops . fb_mmap
* fbdefio : individual delays
*/
fbdefio = kzalloc ( sizeof ( * fbdefio ) , GFP_KERNEL ) ;
fbops = kzalloc ( sizeof ( * fbops ) , GFP_KERNEL ) ;
if ( ! fbdefio | | ! fbops ) {
kfree ( fbdefio ) ;
2016-06-12 16:03:56 +01:00
kfree ( fbops ) ;
2016-04-28 17:18:35 +02:00
return - ENOMEM ;
}
/* can't be offset from vaddr since dirty() uses cma_obj */
fbi - > screen_buffer = cma_obj - > vaddr ;
/* fb_deferred_io_fault() needs a physical address */
fbi - > fix . smem_start = page_to_phys ( virt_to_page ( fbi - > screen_buffer ) ) ;
* fbops = * fbi - > fbops ;
fbi - > fbops = fbops ;
fbdefio - > delay = msecs_to_jiffies ( DEFAULT_FBDEFIO_DELAY_MS ) ;
fbdefio - > deferred_io = drm_fb_helper_deferred_io ;
fbi - > fbdefio = fbdefio ;
fb_deferred_io_init ( fbi ) ;
fbi - > fbops - > fb_mmap = drm_fbdev_cma_deferred_io_mmap ;
return 0 ;
}
static void drm_fbdev_cma_defio_fini ( struct fb_info * fbi )
{
if ( ! fbi - > fbdefio )
return ;
fb_deferred_io_cleanup ( fbi ) ;
kfree ( fbi - > fbdefio ) ;
kfree ( fbi - > fbops ) ;
}
2016-12-29 21:48:31 +01:00
static int
drm_fbdev_cma_create ( struct drm_fb_helper * helper ,
struct drm_fb_helper_surface_size * sizes )
2012-07-02 16:37:47 +02:00
{
struct drm_fbdev_cma * fbdev_cma = to_fbdev_cma ( helper ) ;
struct drm_mode_fb_cmd2 mode_cmd = { 0 } ;
struct drm_device * dev = helper - > dev ;
struct drm_gem_cma_object * obj ;
struct drm_framebuffer * fb ;
unsigned int bytes_per_pixel ;
unsigned long offset ;
struct fb_info * fbi ;
size_t size ;
int ret ;
2012-10-20 10:32:46 +00:00
DRM_DEBUG_KMS ( " surface width(%d), height(%d) and bpp(%d) \n " ,
2012-07-02 16:37:47 +02:00
sizes - > surface_width , sizes - > surface_height ,
sizes - > surface_bpp ) ;
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 ;
obj = drm_gem_cma_create ( dev , size ) ;
2012-10-20 10:32:47 +00:00
if ( IS_ERR ( obj ) )
2012-07-02 16:37:47 +02:00
return - ENOMEM ;
2015-07-22 14:58:20 +05:30
fbi = drm_fb_helper_alloc_fbi ( helper ) ;
if ( IS_ERR ( fbi ) ) {
ret = PTR_ERR ( fbi ) ;
2015-12-14 16:26:26 -08:00
goto err_gem_free_object ;
2012-07-02 16:37:47 +02:00
}
2016-12-29 21:48:31 +01:00
fbdev_cma - > fb = drm_fb_cma_alloc ( dev , & mode_cmd , & obj , 1 ,
fbdev_cma - > fb_funcs ) ;
2012-07-02 16:37:47 +02:00
if ( IS_ERR ( fbdev_cma - > fb ) ) {
dev_err ( dev - > dev , " Failed to allocate DRM framebuffer. \n " ) ;
ret = PTR_ERR ( fbdev_cma - > fb ) ;
2015-07-22 14:58:20 +05:30
goto err_fb_info_destroy ;
2012-07-02 16:37:47 +02:00
}
fb = & fbdev_cma - > fb - > fb ;
helper - > fb = fb ;
fbi - > par = helper ;
fbi - > flags = FBINFO_FLAG_DEFAULT ;
fbi - > fbops = & drm_fbdev_cma_ops ;
2016-12-14 23:31:35 +02:00
drm_fb_helper_fill_fix ( fbi , fb - > pitches [ 0 ] , fb - > format - > depth ) ;
2015-03-11 10:23:10 -04:00
drm_fb_helper_fill_var ( fbi , helper , sizes - > fb_width , sizes - > fb_height ) ;
2012-07-02 16:37:47 +02:00
offset = fbi - > var . xoffset * bytes_per_pixel ;
offset + = fbi - > var . yoffset * fb - > pitches [ 0 ] ;
dev - > mode_config . fb_base = ( resource_size_t ) obj - > paddr ;
fbi - > screen_base = obj - > vaddr + offset ;
fbi - > fix . smem_start = ( unsigned long ) ( obj - > paddr + offset ) ;
fbi - > screen_size = size ;
fbi - > fix . smem_len = size ;
2016-12-29 21:48:31 +01:00
if ( fbdev_cma - > fb_funcs - > dirty ) {
2016-04-28 17:18:35 +02:00
ret = drm_fbdev_cma_defio_init ( fbi , obj ) ;
if ( ret )
goto err_cma_destroy ;
}
2012-07-02 16:37:47 +02:00
return 0 ;
2016-04-28 17:18:35 +02:00
err_cma_destroy :
2016-12-27 11:49:22 +01:00
drm_framebuffer_remove ( & fbdev_cma - > fb - > fb ) ;
2015-07-22 14:58:20 +05:30
err_fb_info_destroy :
2017-02-07 17:16:03 +01:00
drm_fb_helper_fini ( helper ) ;
2015-12-14 16:26:26 -08:00
err_gem_free_object :
2017-02-28 15:46:41 +01:00
drm_gem_object_put_unlocked ( & obj - > base ) ;
2012-07-02 16:37:47 +02:00
return ret ;
}
2014-06-27 17:19:23 +02:00
static const struct drm_fb_helper_funcs drm_fb_cma_helper_funcs = {
2013-01-21 23:42:49 +01:00
. fb_probe = drm_fbdev_cma_create ,
2012-07-02 16:37:47 +02:00
} ;
/**
2016-04-28 17:18:35 +02:00
* drm_fbdev_cma_init_with_funcs ( ) - Allocate and initializes a drm_fbdev_cma struct
2012-07-02 16:37:47 +02:00
* @ dev : DRM device
* @ preferred_bpp : Preferred bits per pixel for the device
* @ max_conn_count : Maximum number of connectors
2016-12-29 21:48:31 +01:00
* @ funcs : fb helper functions , in particular a custom dirty ( ) callback
2012-07-02 16:37:47 +02:00
*
* Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR .
*/
2016-04-28 17:18:35 +02:00
struct drm_fbdev_cma * drm_fbdev_cma_init_with_funcs ( struct drm_device * dev ,
drm: Rely on mode_config data for fb_helper initialization
Instead of receiving the num_crts as a parameter, we can read it
directly from the mode_config structure. I audited the drivers that
invoke this helper and I believe all of them initialize the mode_config
struct accordingly, prior to calling the fb_helper.
I used the following coccinelle hack to make this transformation, except
for the function headers and comment updates. The first and second
rules are split because I couldn't find a way to remove the unused
temporary variables at the same time I removed the parameter.
// <smpl>
@r@
expression A,B,D,E;
identifier C;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
expression A,B,C,D,E;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
identifier r.C;
type T;
expression V;
@@
- T C;
<...
when != C
- C = V;
...>
// </smpl>
Changes since v1:
- Rebased on top of the tip of drm-misc-next.
- Remove mention to sti since a proper fix got merged.
Suggested-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202162640.27261-1-krisman@collabora.co.uk
2017-02-02 14:26:40 -02:00
unsigned int preferred_bpp , unsigned int max_conn_count ,
const struct drm_framebuffer_funcs * funcs )
2012-07-02 16:37:47 +02:00
{
struct drm_fbdev_cma * fbdev_cma ;
struct drm_fb_helper * helper ;
int ret ;
fbdev_cma = kzalloc ( sizeof ( * fbdev_cma ) , GFP_KERNEL ) ;
if ( ! fbdev_cma ) {
dev_err ( dev - > dev , " Failed to allocate drm fbdev. \n " ) ;
return ERR_PTR ( - ENOMEM ) ;
}
2016-12-29 21:48:31 +01:00
fbdev_cma - > fb_funcs = funcs ;
2012-07-02 16:37:47 +02:00
helper = & fbdev_cma - > fb_helper ;
2016-12-29 21:48:31 +01:00
drm_fb_helper_prepare ( dev , helper , & drm_fb_cma_helper_funcs ) ;
2014-06-27 17:19:24 +02:00
drm: Rely on mode_config data for fb_helper initialization
Instead of receiving the num_crts as a parameter, we can read it
directly from the mode_config structure. I audited the drivers that
invoke this helper and I believe all of them initialize the mode_config
struct accordingly, prior to calling the fb_helper.
I used the following coccinelle hack to make this transformation, except
for the function headers and comment updates. The first and second
rules are split because I couldn't find a way to remove the unused
temporary variables at the same time I removed the parameter.
// <smpl>
@r@
expression A,B,D,E;
identifier C;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
expression A,B,C,D,E;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
identifier r.C;
type T;
expression V;
@@
- T C;
<...
when != C
- C = V;
...>
// </smpl>
Changes since v1:
- Rebased on top of the tip of drm-misc-next.
- Remove mention to sti since a proper fix got merged.
Suggested-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202162640.27261-1-krisman@collabora.co.uk
2017-02-02 14:26:40 -02:00
ret = drm_fb_helper_init ( dev , helper , max_conn_count ) ;
2012-07-02 16:37:47 +02:00
if ( ret < 0 ) {
dev_err ( dev - > dev , " Failed to initialize drm fb helper. \n " ) ;
goto err_free ;
}
ret = drm_fb_helper_single_add_all_connectors ( helper ) ;
if ( ret < 0 ) {
dev_err ( dev - > dev , " Failed to add connectors. \n " ) ;
goto err_drm_fb_helper_fini ;
}
ret = drm_fb_helper_initial_config ( helper , preferred_bpp ) ;
if ( ret < 0 ) {
2013-05-21 23:13:12 +09:00
dev_err ( dev - > dev , " Failed to set initial hw configuration. \n " ) ;
2012-07-02 16:37:47 +02:00
goto err_drm_fb_helper_fini ;
}
return fbdev_cma ;
err_drm_fb_helper_fini :
drm_fb_helper_fini ( helper ) ;
err_free :
kfree ( fbdev_cma ) ;
return ERR_PTR ( ret ) ;
}
2016-04-28 17:18:35 +02:00
EXPORT_SYMBOL_GPL ( drm_fbdev_cma_init_with_funcs ) ;
/**
* drm_fbdev_cma_init ( ) - Allocate and initializes a drm_fbdev_cma struct
* @ dev : DRM device
* @ preferred_bpp : Preferred bits per pixel for the device
* @ max_conn_count : Maximum number of connectors
*
* Returns a newly allocated drm_fbdev_cma struct or a ERR_PTR .
*/
struct drm_fbdev_cma * drm_fbdev_cma_init ( struct drm_device * dev ,
drm: Rely on mode_config data for fb_helper initialization
Instead of receiving the num_crts as a parameter, we can read it
directly from the mode_config structure. I audited the drivers that
invoke this helper and I believe all of them initialize the mode_config
struct accordingly, prior to calling the fb_helper.
I used the following coccinelle hack to make this transformation, except
for the function headers and comment updates. The first and second
rules are split because I couldn't find a way to remove the unused
temporary variables at the same time I removed the parameter.
// <smpl>
@r@
expression A,B,D,E;
identifier C;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
expression A,B,C,D,E;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
identifier r.C;
type T;
expression V;
@@
- T C;
<...
when != C
- C = V;
...>
// </smpl>
Changes since v1:
- Rebased on top of the tip of drm-misc-next.
- Remove mention to sti since a proper fix got merged.
Suggested-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202162640.27261-1-krisman@collabora.co.uk
2017-02-02 14:26:40 -02:00
unsigned int preferred_bpp , unsigned int max_conn_count )
2016-04-28 17:18:35 +02:00
{
drm: Rely on mode_config data for fb_helper initialization
Instead of receiving the num_crts as a parameter, we can read it
directly from the mode_config structure. I audited the drivers that
invoke this helper and I believe all of them initialize the mode_config
struct accordingly, prior to calling the fb_helper.
I used the following coccinelle hack to make this transformation, except
for the function headers and comment updates. The first and second
rules are split because I couldn't find a way to remove the unused
temporary variables at the same time I removed the parameter.
// <smpl>
@r@
expression A,B,D,E;
identifier C;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
expression A,B,C,D,E;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
identifier r.C;
type T;
expression V;
@@
- T C;
<...
when != C
- C = V;
...>
// </smpl>
Changes since v1:
- Rebased on top of the tip of drm-misc-next.
- Remove mention to sti since a proper fix got merged.
Suggested-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202162640.27261-1-krisman@collabora.co.uk
2017-02-02 14:26:40 -02:00
return drm_fbdev_cma_init_with_funcs ( dev , preferred_bpp ,
max_conn_count ,
& drm_fb_cma_funcs ) ;
2016-04-28 17:18:35 +02:00
}
2012-07-02 16:37:47 +02:00
EXPORT_SYMBOL_GPL ( drm_fbdev_cma_init ) ;
/**
* drm_fbdev_cma_fini ( ) - Free drm_fbdev_cma struct
* @ fbdev_cma : The drm_fbdev_cma struct
*/
void drm_fbdev_cma_fini ( struct drm_fbdev_cma * fbdev_cma )
{
2015-07-22 14:58:20 +05:30
drm_fb_helper_unregister_fbi ( & fbdev_cma - > fb_helper ) ;
2016-10-19 17:32:19 -07:00
if ( fbdev_cma - > fb_helper . fbdev )
drm_fbdev_cma_defio_fini ( fbdev_cma - > fb_helper . fbdev ) ;
2012-07-02 16:37:47 +02:00
2016-12-27 11:49:22 +01:00
if ( fbdev_cma - > fb )
drm_framebuffer_remove ( & fbdev_cma - > fb - > fb ) ;
2012-07-02 16:37:47 +02:00
drm_fb_helper_fini ( & fbdev_cma - > fb_helper ) ;
kfree ( fbdev_cma ) ;
}
EXPORT_SYMBOL_GPL ( drm_fbdev_cma_fini ) ;
/**
* drm_fbdev_cma_restore_mode ( ) - Restores initial framebuffer mode
* @ fbdev_cma : The drm_fbdev_cma struct , may be NULL
*
2016-12-29 21:48:34 +01:00
* This function is usually called from the & drm_driver . lastclose callback .
2012-07-02 16:37:47 +02:00
*/
void drm_fbdev_cma_restore_mode ( struct drm_fbdev_cma * fbdev_cma )
{
2014-05-30 12:29:48 -04:00
if ( fbdev_cma )
drm_fb_helper_restore_fbdev_mode_unlocked ( & fbdev_cma - > fb_helper ) ;
2012-07-02 16:37:47 +02:00
}
EXPORT_SYMBOL_GPL ( drm_fbdev_cma_restore_mode ) ;
/**
* drm_fbdev_cma_hotplug_event ( ) - Poll for hotpulug events
* @ fbdev_cma : The drm_fbdev_cma struct , may be NULL
*
2016-12-29 21:48:34 +01:00
* This function is usually called from the & drm_mode_config . output_poll_changed
2012-07-02 16:37:47 +02:00
* callback .
*/
void drm_fbdev_cma_hotplug_event ( struct drm_fbdev_cma * fbdev_cma )
{
if ( fbdev_cma )
drm_fb_helper_hotplug_event ( & fbdev_cma - > fb_helper ) ;
}
EXPORT_SYMBOL_GPL ( drm_fbdev_cma_hotplug_event ) ;
2016-02-11 17:30:14 -08:00
/**
* drm_fbdev_cma_set_suspend - wrapper around drm_fb_helper_set_suspend
* @ fbdev_cma : The drm_fbdev_cma struct , may be NULL
* @ state : desired state , zero to resume , non - zero to suspend
*
* Calls drm_fb_helper_set_suspend , which is a wrapper around
* fb_set_suspend implemented by fbdev core .
*/
2017-06-20 11:23:20 +01:00
void drm_fbdev_cma_set_suspend ( struct drm_fbdev_cma * fbdev_cma , bool state )
2016-02-11 17:30:14 -08:00
{
if ( fbdev_cma )
drm_fb_helper_set_suspend ( & fbdev_cma - > fb_helper , state ) ;
}
EXPORT_SYMBOL ( drm_fbdev_cma_set_suspend ) ;
2017-01-22 19:11:09 +01:00
/**
* drm_fbdev_cma_set_suspend_unlocked - wrapper around
* drm_fb_helper_set_suspend_unlocked
* @ fbdev_cma : The drm_fbdev_cma struct , may be NULL
* @ state : desired state , zero to resume , non - zero to suspend
*
* Calls drm_fb_helper_set_suspend , which is a wrapper around
* fb_set_suspend implemented by fbdev core .
*/
void drm_fbdev_cma_set_suspend_unlocked ( struct drm_fbdev_cma * fbdev_cma ,
2017-06-20 11:23:20 +01:00
bool state )
2017-01-22 19:11:09 +01:00
{
if ( fbdev_cma )
drm_fb_helper_set_suspend_unlocked ( & fbdev_cma - > fb_helper ,
state ) ;
}
EXPORT_SYMBOL ( drm_fbdev_cma_set_suspend_unlocked ) ;