2017-12-06 12:29:47 +01:00
// SPDX-License-Identifier: GPL-2.0
2014-07-30 19:28:27 +02:00
/*
* Copyright ( C ) STMicroelectronics SA 2014
* Authors : Benjamin Gaignard < benjamin . gaignard @ st . com >
* Fabien Dessenne < fabien . dessenne @ st . com >
* for STMicroelectronics .
*/
# include <linux/component.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/reset.h>
# include <drm/drmP.h>
# include "sti_compositor.h"
2015-07-31 11:32:34 +02:00
# include "sti_crtc.h"
2015-07-31 11:32:13 +02:00
# include "sti_cursor.h"
2015-07-31 11:32:34 +02:00
# include "sti_drv.h"
2014-07-30 19:28:27 +02:00
# include "sti_gdp.h"
2015-07-31 11:32:34 +02:00
# include "sti_plane.h"
2015-07-31 11:32:13 +02:00
# include "sti_vid.h"
2014-07-30 19:28:27 +02:00
# include "sti_vtg.h"
/*
* stiH407 compositor properties
*/
2016-09-19 16:33:53 +03:00
static const struct sti_compositor_data stih407_compositor_data = {
2014-12-11 13:34:42 +01:00
. nb_subdev = 8 ,
2014-07-30 19:28:27 +02:00
. subdev_desc = {
2014-12-11 13:34:42 +01:00
{ STI_CURSOR_SUBDEV , ( int ) STI_CURSOR , 0x000 } ,
2014-07-30 19:28:27 +02:00
{ STI_GPD_SUBDEV , ( int ) STI_GDP_0 , 0x100 } ,
{ STI_GPD_SUBDEV , ( int ) STI_GDP_1 , 0x200 } ,
{ STI_GPD_SUBDEV , ( int ) STI_GDP_2 , 0x300 } ,
{ STI_GPD_SUBDEV , ( int ) STI_GDP_3 , 0x400 } ,
2015-07-31 11:32:13 +02:00
{ STI_VID_SUBDEV , ( int ) STI_HQVDP_0 , 0x700 } ,
2014-12-08 17:32:36 +01:00
{ STI_MIXER_MAIN_SUBDEV , STI_MIXER_MAIN , 0xC00 } ,
{ STI_MIXER_AUX_SUBDEV , STI_MIXER_AUX , 0xD00 } ,
2014-07-30 19:28:27 +02:00
} ,
} ;
2016-09-15 17:11:07 +02:00
int sti_compositor_debugfs_init ( struct sti_compositor * compo ,
struct drm_minor * minor )
2016-06-21 15:09:39 +02:00
{
2016-09-15 17:11:07 +02:00
unsigned int i ;
2016-06-21 15:09:39 +02:00
2016-09-15 17:11:07 +02:00
for ( i = 0 ; i < STI_MAX_VID ; i + + )
if ( compo - > vid [ i ] )
vid_debugfs_init ( compo - > vid [ i ] , minor ) ;
2016-06-21 15:09:39 +02:00
2016-09-15 17:11:07 +02:00
for ( i = 0 ; i < STI_MAX_MIXER ; i + + )
if ( compo - > mixer [ i ] )
sti_mixer_debugfs_init ( compo - > mixer [ i ] , minor ) ;
2016-06-21 15:09:39 +02:00
return 0 ;
}
2015-07-31 11:32:13 +02:00
static int sti_compositor_bind ( struct device * dev ,
struct device * master ,
void * data )
2014-07-30 19:28:27 +02:00
{
2015-07-31 11:32:13 +02:00
struct sti_compositor * compo = dev_get_drvdata ( dev ) ;
struct drm_device * drm_dev = data ;
2015-08-03 14:22:16 +02:00
unsigned int i , mixer_id = 0 , vid_id = 0 , crtc_id = 0 ;
2015-07-31 11:32:34 +02:00
struct sti_private * dev_priv = drm_dev - > dev_private ;
2015-07-31 11:32:13 +02:00
struct drm_plane * cursor = NULL ;
struct drm_plane * primary = NULL ;
struct sti_compositor_subdev_descriptor * desc = compo - > data . subdev_desc ;
unsigned int array_size = compo - > data . nb_subdev ;
dev_priv - > compo = compo ;
/* Register mixer subdev and video subdev first */
2014-07-30 19:28:27 +02:00
for ( i = 0 ; i < array_size ; i + + ) {
switch ( desc [ i ] . type ) {
2015-07-31 11:32:13 +02:00
case STI_VID_SUBDEV :
compo - > vid [ vid_id + + ] =
2016-02-04 16:58:45 +01:00
sti_vid_create ( compo - > dev , drm_dev , desc [ i ] . id ,
2015-07-31 11:32:13 +02:00
compo - > regs + desc [ i ] . offset ) ;
break ;
2014-07-30 19:28:27 +02:00
case STI_MIXER_MAIN_SUBDEV :
case STI_MIXER_AUX_SUBDEV :
compo - > mixer [ mixer_id + + ] =
2016-02-04 17:44:50 +01:00
sti_mixer_create ( compo - > dev , drm_dev , desc [ i ] . id ,
2014-07-30 19:28:27 +02:00
compo - > regs + desc [ i ] . offset ) ;
break ;
case STI_GPD_SUBDEV :
2014-12-11 13:34:42 +01:00
case STI_CURSOR_SUBDEV :
2015-07-31 11:32:13 +02:00
/* Nothing to do, wait for the second round */
2014-07-30 19:28:27 +02:00
break ;
default :
2016-11-23 22:44:47 +09:00
DRM_ERROR ( " Unknown subdev component type \n " ) ;
2014-07-30 19:28:27 +02:00
return 1 ;
}
}
2015-07-31 11:32:13 +02:00
/* Register the other subdevs, create crtc and planes */
for ( i = 0 ; i < array_size ; i + + ) {
enum drm_plane_type plane_type = DRM_PLANE_TYPE_OVERLAY ;
2014-07-31 09:39:11 +02:00
2015-07-31 11:32:13 +02:00
if ( crtc_id < mixer_id )
plane_type = DRM_PLANE_TYPE_PRIMARY ;
2014-07-31 09:39:11 +02:00
2015-07-31 11:32:13 +02:00
switch ( desc [ i ] . type ) {
case STI_MIXER_MAIN_SUBDEV :
case STI_MIXER_AUX_SUBDEV :
case STI_VID_SUBDEV :
/* Nothing to do, already done at the first round */
break ;
case STI_CURSOR_SUBDEV :
2015-08-03 14:22:16 +02:00
cursor = sti_cursor_create ( drm_dev , compo - > dev ,
desc [ i ] . id ,
compo - > regs + desc [ i ] . offset ,
1 ) ;
if ( ! cursor ) {
2015-07-31 11:32:13 +02:00
DRM_ERROR ( " Can't create CURSOR plane \n " ) ;
2014-07-31 09:39:11 +02:00
break ;
2015-07-31 11:32:13 +02:00
}
break ;
case STI_GPD_SUBDEV :
2015-08-03 14:22:16 +02:00
primary = sti_gdp_create ( drm_dev , compo - > dev ,
desc [ i ] . id ,
compo - > regs + desc [ i ] . offset ,
( 1 < < mixer_id ) - 1 ,
plane_type ) ;
if ( ! primary ) {
2015-07-31 11:32:13 +02:00
DRM_ERROR ( " Can't create GDP plane \n " ) ;
2014-08-05 09:41:42 +10:00
break ;
2014-07-31 09:39:11 +02:00
}
2015-07-31 11:32:13 +02:00
break ;
default :
2017-05-13 23:41:50 +01:00
DRM_ERROR ( " Unknown subdev component type \n " ) ;
2015-07-31 11:32:13 +02:00
return 1 ;
}
2014-07-31 09:39:11 +02:00
2015-07-31 11:32:13 +02:00
/* The first planes are reserved for primary planes*/
if ( crtc_id < mixer_id & & primary ) {
2015-07-31 11:32:34 +02:00
sti_crtc_init ( drm_dev , compo - > mixer [ crtc_id ] ,
primary , cursor ) ;
2015-07-31 11:32:13 +02:00
crtc_id + + ;
cursor = NULL ;
primary = NULL ;
2014-07-31 09:39:11 +02:00
}
}
2014-07-30 19:28:27 +02:00
2015-07-31 11:32:13 +02:00
drm_vblank_init ( drm_dev , crtc_id ) ;
2014-07-30 19:28:27 +02:00
/* Allow usage of vblank without having to call drm_irq_install */
drm_dev - > irq_enabled = 1 ;
return 0 ;
}
static void sti_compositor_unbind ( struct device * dev , struct device * master ,
void * data )
{
/* do nothing */
}
static const struct component_ops sti_compositor_ops = {
. bind = sti_compositor_bind ,
. unbind = sti_compositor_unbind ,
} ;
static const struct of_device_id compositor_of_match [ ] = {
{
. compatible = " st,stih407-compositor " ,
. data = & stih407_compositor_data ,
} , {
/* end node */
}
} ;
MODULE_DEVICE_TABLE ( of , compositor_of_match ) ;
static int sti_compositor_probe ( struct platform_device * pdev )
{
struct device * dev = & pdev - > dev ;
struct device_node * np = dev - > of_node ;
struct device_node * vtg_np ;
struct sti_compositor * compo ;
struct resource * res ;
2016-09-06 09:42:13 +02:00
unsigned int i ;
2014-07-30 19:28:27 +02:00
compo = devm_kzalloc ( dev , sizeof ( * compo ) , GFP_KERNEL ) ;
if ( ! compo ) {
DRM_ERROR ( " Failed to allocate compositor context \n " ) ;
return - ENOMEM ;
}
compo - > dev = dev ;
2016-09-06 09:42:13 +02:00
for ( i = 0 ; i < STI_MAX_MIXER ; i + + )
compo - > vtg_vblank_nb [ i ] . notifier_call = sti_crtc_vblank_cb ;
2014-07-30 19:28:27 +02:00
/* populate data structure depending on compatibility */
BUG_ON ( ! of_match_node ( compositor_of_match , np ) - > data ) ;
memcpy ( & compo - > data , of_match_node ( compositor_of_match , np ) - > data ,
sizeof ( struct sti_compositor_data ) ) ;
/* Get Memory ressources */
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( res = = NULL ) {
DRM_ERROR ( " Get memory resource failed \n " ) ;
return - ENXIO ;
}
compo - > regs = devm_ioremap ( dev , res - > start , resource_size ( res ) ) ;
if ( compo - > regs = = NULL ) {
DRM_ERROR ( " Register mapping failed \n " ) ;
return - ENXIO ;
}
/* Get clock resources */
compo - > clk_compo_main = devm_clk_get ( dev , " compo_main " ) ;
if ( IS_ERR ( compo - > clk_compo_main ) ) {
DRM_ERROR ( " Cannot get compo_main clock \n " ) ;
return PTR_ERR ( compo - > clk_compo_main ) ;
}
compo - > clk_compo_aux = devm_clk_get ( dev , " compo_aux " ) ;
if ( IS_ERR ( compo - > clk_compo_aux ) ) {
DRM_ERROR ( " Cannot get compo_aux clock \n " ) ;
return PTR_ERR ( compo - > clk_compo_aux ) ;
}
compo - > clk_pix_main = devm_clk_get ( dev , " pix_main " ) ;
if ( IS_ERR ( compo - > clk_pix_main ) ) {
DRM_ERROR ( " Cannot get pix_main clock \n " ) ;
return PTR_ERR ( compo - > clk_pix_main ) ;
}
compo - > clk_pix_aux = devm_clk_get ( dev , " pix_aux " ) ;
if ( IS_ERR ( compo - > clk_pix_aux ) ) {
DRM_ERROR ( " Cannot get pix_aux clock \n " ) ;
return PTR_ERR ( compo - > clk_pix_aux ) ;
}
/* Get reset resources */
2016-07-25 11:09:33 +01:00
compo - > rst_main = devm_reset_control_get_shared ( dev , " compo-main " ) ;
2014-07-30 19:28:27 +02:00
/* Take compo main out of reset */
if ( ! IS_ERR ( compo - > rst_main ) )
reset_control_deassert ( compo - > rst_main ) ;
2016-07-25 11:09:33 +01:00
compo - > rst_aux = devm_reset_control_get_shared ( dev , " compo-aux " ) ;
2014-07-30 19:28:27 +02:00
/* Take compo aux out of reset */
if ( ! IS_ERR ( compo - > rst_aux ) )
reset_control_deassert ( compo - > rst_aux ) ;
vtg_np = of_parse_phandle ( pdev - > dev . of_node , " st,vtg " , 0 ) ;
if ( vtg_np )
2016-09-06 09:42:25 +02:00
compo - > vtg [ STI_MIXER_MAIN ] = of_vtg_find ( vtg_np ) ;
2016-07-05 10:04:49 +08:00
of_node_put ( vtg_np ) ;
2014-07-30 19:28:27 +02:00
vtg_np = of_parse_phandle ( pdev - > dev . of_node , " st,vtg " , 1 ) ;
if ( vtg_np )
2016-09-06 09:42:25 +02:00
compo - > vtg [ STI_MIXER_AUX ] = of_vtg_find ( vtg_np ) ;
2016-07-05 10:04:49 +08:00
of_node_put ( vtg_np ) ;
2014-07-30 19:28:27 +02:00
platform_set_drvdata ( pdev , compo ) ;
return component_add ( & pdev - > dev , & sti_compositor_ops ) ;
}
static int sti_compositor_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & sti_compositor_ops ) ;
return 0 ;
}
2015-09-24 19:02:40 +02:00
struct platform_driver sti_compositor_driver = {
2014-07-30 19:28:27 +02:00
. driver = {
. name = " sti-compositor " ,
. of_match_table = compositor_of_match ,
} ,
. probe = sti_compositor_probe ,
. remove = sti_compositor_remove ,
} ;
MODULE_AUTHOR ( " Benjamin Gaignard <benjamin.gaignard@st.com> " ) ;
MODULE_DESCRIPTION ( " STMicroelectronics SoC DRM driver " ) ;
MODULE_LICENSE ( " GPL " ) ;