2016-02-19 15:30:26 +03:00
/*
* ARC PGU DRM driver .
*
* Copyright ( C ) 2016 Synopsys , Inc . ( www . synopsys . com )
*
* 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 <linux/clk.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_gem_cma_helper.h>
2017-08-13 15:31:47 +02:00
# include <drm/drm_gem_framebuffer_helper.h>
2016-02-19 15:30:26 +03:00
# include <drm/drm_atomic_helper.h>
2016-04-27 16:02:39 +03:00
# include <linux/of_reserved_mem.h>
2016-02-19 15:30:26 +03:00
# include "arcpgu.h"
# include "arcpgu_regs.h"
static void arcpgu_fb_output_poll_changed ( struct drm_device * dev )
{
struct arcpgu_drm_private * arcpgu = dev - > dev_private ;
2016-07-15 21:52:40 +02:00
drm_fbdev_cma_hotplug_event ( arcpgu - > fbdev ) ;
2016-02-19 15:30:26 +03:00
}
2017-08-08 20:35:51 +05:30
static const struct drm_mode_config_funcs arcpgu_drm_modecfg_funcs = {
2017-08-13 15:31:47 +02:00
. fb_create = drm_gem_fb_create ,
2016-02-19 15:30:26 +03:00
. output_poll_changed = arcpgu_fb_output_poll_changed ,
. atomic_check = drm_atomic_helper_check ,
2016-06-08 14:19:03 +02:00
. atomic_commit = drm_atomic_helper_commit ,
2016-02-19 15:30:26 +03:00
} ;
static void arcpgu_setup_mode_config ( struct drm_device * drm )
{
drm_mode_config_init ( drm ) ;
drm - > mode_config . min_width = 0 ;
drm - > mode_config . min_height = 0 ;
drm - > mode_config . max_width = 1920 ;
drm - > mode_config . max_height = 1080 ;
drm - > mode_config . funcs = & arcpgu_drm_modecfg_funcs ;
}
2017-07-17 13:08:25 +01:00
DEFINE_DRM_GEM_CMA_FOPS ( arcpgu_drm_ops ) ;
2016-02-19 15:30:26 +03:00
static void arcpgu_lastclose ( struct drm_device * drm )
{
struct arcpgu_drm_private * arcpgu = drm - > dev_private ;
drm_fbdev_cma_restore_mode ( arcpgu - > fbdev ) ;
}
static int arcpgu_load ( struct drm_device * drm )
{
struct platform_device * pdev = to_platform_device ( drm - > dev ) ;
struct arcpgu_drm_private * arcpgu ;
struct device_node * encoder_node ;
struct resource * res ;
int ret ;
arcpgu = devm_kzalloc ( & pdev - > dev , sizeof ( * arcpgu ) , GFP_KERNEL ) ;
if ( arcpgu = = NULL )
return - ENOMEM ;
drm - > dev_private = arcpgu ;
arcpgu - > clk = devm_clk_get ( drm - > dev , " pxlclk " ) ;
if ( IS_ERR ( arcpgu - > clk ) )
return PTR_ERR ( arcpgu - > clk ) ;
arcpgu_setup_mode_config ( drm ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
arcpgu - > regs = devm_ioremap_resource ( & pdev - > dev , res ) ;
2016-07-19 12:01:37 +00:00
if ( IS_ERR ( arcpgu - > regs ) )
2016-02-19 15:30:26 +03:00
return PTR_ERR ( arcpgu - > regs ) ;
dev_info ( drm - > dev , " arc_pgu ID: 0x%x \n " ,
arc_pgu_read ( arcpgu , ARCPGU_REG_ID ) ) ;
2016-04-27 16:02:39 +03:00
/* Get the optional framebuffer memory resource */
ret = of_reserved_mem_device_init ( drm - > dev ) ;
if ( ret & & ret ! = - ENODEV )
return ret ;
2016-02-19 15:30:26 +03:00
if ( dma_set_mask_and_coherent ( drm - > dev , DMA_BIT_MASK ( 32 ) ) )
return - ENODEV ;
if ( arc_pgu_setup_crtc ( drm ) < 0 )
return - ENODEV ;
/* find the encoder node and initialize it */
encoder_node = of_parse_phandle ( drm - > dev - > of_node , " encoder-slave " , 0 ) ;
2016-06-06 10:47:46 +03:00
if ( encoder_node ) {
ret = arcpgu_drm_hdmi_init ( drm , encoder_node ) ;
2016-07-15 11:17:05 +08:00
of_node_put ( encoder_node ) ;
2016-06-06 10:47:46 +03:00
if ( ret < 0 )
return ret ;
} else {
2016-07-19 12:04:05 +00:00
ret = arcpgu_drm_sim_init ( drm , NULL ) ;
2016-06-06 10:47:46 +03:00
if ( ret < 0 )
return ret ;
2016-02-19 15:30:26 +03:00
}
drm_mode_config_reset ( drm ) ;
drm_kms_helper_poll_init ( drm ) ;
arcpgu - > fbdev = drm_fbdev_cma_init ( drm , 16 ,
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
drm - > mode_config . num_connector ) ;
2016-02-19 15:30:26 +03:00
if ( IS_ERR ( arcpgu - > fbdev ) ) {
ret = PTR_ERR ( arcpgu - > fbdev ) ;
arcpgu - > fbdev = NULL ;
return - ENODEV ;
}
2017-07-17 13:08:26 +01:00
platform_set_drvdata ( pdev , drm ) ;
2016-02-19 15:30:26 +03:00
return 0 ;
}
2016-07-19 12:04:05 +00:00
static int arcpgu_unload ( struct drm_device * drm )
2016-02-19 15:30:26 +03:00
{
struct arcpgu_drm_private * arcpgu = drm - > dev_private ;
if ( arcpgu - > fbdev ) {
drm_fbdev_cma_fini ( arcpgu - > fbdev ) ;
arcpgu - > fbdev = NULL ;
}
drm_kms_helper_poll_fini ( drm ) ;
drm_mode_config_cleanup ( drm ) ;
return 0 ;
}
2017-03-03 15:30:35 +03:00
# ifdef CONFIG_DEBUG_FS
static int arcpgu_show_pxlclock ( struct seq_file * m , void * arg )
{
struct drm_info_node * node = ( struct drm_info_node * ) m - > private ;
struct drm_device * drm = node - > minor - > dev ;
struct arcpgu_drm_private * arcpgu = drm - > dev_private ;
unsigned long clkrate = clk_get_rate ( arcpgu - > clk ) ;
unsigned long mode_clock = arcpgu - > crtc . mode . crtc_clock * 1000 ;
seq_printf ( m , " hw : %lu \n " , clkrate ) ;
seq_printf ( m , " mode: %lu \n " , mode_clock ) ;
return 0 ;
}
static struct drm_info_list arcpgu_debugfs_list [ ] = {
{ " clocks " , arcpgu_show_pxlclock , 0 } ,
{ " fb " , drm_fb_cma_debugfs_show , 0 } ,
} ;
static int arcpgu_debugfs_init ( struct drm_minor * minor )
{
return drm_debugfs_create_files ( arcpgu_debugfs_list ,
ARRAY_SIZE ( arcpgu_debugfs_list ) , minor - > debugfs_root , minor ) ;
}
# endif
2016-02-19 15:30:26 +03:00
static struct drm_driver arcpgu_drm_driver = {
. driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
DRIVER_ATOMIC ,
. lastclose = arcpgu_lastclose ,
2017-04-21 09:59:03 +03:00
. name = " arcpgu " ,
2016-02-19 15:30:26 +03:00
. desc = " ARC PGU Controller " ,
. date = " 20160219 " ,
. major = 1 ,
. minor = 0 ,
. patchlevel = 0 ,
. fops = & arcpgu_drm_ops ,
. dumb_create = drm_gem_cma_dumb_create ,
. prime_handle_to_fd = drm_gem_prime_handle_to_fd ,
. prime_fd_to_handle = drm_gem_prime_fd_to_handle ,
2016-05-30 19:53:16 +02:00
. gem_free_object_unlocked = drm_gem_cma_free_object ,
2016-02-19 15:30:26 +03:00
. gem_vm_ops = & drm_gem_cma_vm_ops ,
. gem_prime_export = drm_gem_prime_export ,
. gem_prime_import = drm_gem_prime_import ,
. gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table ,
. gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table ,
. gem_prime_vmap = drm_gem_cma_prime_vmap ,
. gem_prime_vunmap = drm_gem_cma_prime_vunmap ,
. gem_prime_mmap = drm_gem_cma_prime_mmap ,
2017-03-03 15:30:35 +03:00
# ifdef CONFIG_DEBUG_FS
. debugfs_init = arcpgu_debugfs_init ,
# endif
2016-02-19 15:30:26 +03:00
} ;
static int arcpgu_probe ( struct platform_device * pdev )
{
struct drm_device * drm ;
int ret ;
drm = drm_dev_alloc ( & arcpgu_drm_driver , & pdev - > dev ) ;
2016-09-21 16:59:19 +02:00
if ( IS_ERR ( drm ) )
return PTR_ERR ( drm ) ;
2016-02-19 15:30:26 +03:00
ret = arcpgu_load ( drm ) ;
if ( ret )
goto err_unref ;
ret = drm_dev_register ( drm , 0 ) ;
if ( ret )
goto err_unload ;
return 0 ;
err_unload :
arcpgu_unload ( drm ) ;
err_unref :
drm_dev_unref ( drm ) ;
return ret ;
}
static int arcpgu_remove ( struct platform_device * pdev )
{
struct drm_device * drm = platform_get_drvdata ( pdev ) ;
drm_dev_unregister ( drm ) ;
arcpgu_unload ( drm ) ;
drm_dev_unref ( drm ) ;
return 0 ;
}
static const struct of_device_id arcpgu_of_table [ ] = {
{ . compatible = " snps,arcpgu " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , arcpgu_of_table ) ;
static struct platform_driver arcpgu_platform_driver = {
. probe = arcpgu_probe ,
. remove = arcpgu_remove ,
. driver = {
. name = " arcpgu " ,
. of_match_table = arcpgu_of_table ,
} ,
} ;
module_platform_driver ( arcpgu_platform_driver ) ;
MODULE_AUTHOR ( " Carlos Palminha <palminha@synopsys.com> " ) ;
MODULE_DESCRIPTION ( " ARC PGU DRM driver " ) ;
MODULE_LICENSE ( " GPL " ) ;