2013-06-04 11:22:30 -03:00
/*
* vsp1_drv . c - - R - Car VSP1 Driver
*
2015-03-15 11:33:07 -03:00
* Copyright ( C ) 2013 - 2015 Renesas Electronics Corporation
2013-06-04 11:22:30 -03:00
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . com )
*
* 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 .
*/
# include <linux/clk.h>
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/interrupt.h>
# include <linux/module.h>
2014-04-08 13:40:13 -03:00
# include <linux/of.h>
2015-08-03 09:46:26 -03:00
# include <linux/of_device.h>
2013-06-04 11:22:30 -03:00
# include <linux/platform_device.h>
# include <linux/videodev2.h>
2015-08-05 17:14:41 -03:00
# include <media/v4l2-subdev.h>
2013-06-04 11:22:30 -03:00
# include "vsp1.h"
2013-07-10 18:03:46 -03:00
# include "vsp1_bru.h"
2015-09-07 01:40:25 -03:00
# include "vsp1_dl.h"
2015-08-02 18:37:01 -03:00
# include "vsp1_drm.h"
2013-07-10 17:30:14 -03:00
# include "vsp1_hsit.h"
2013-06-04 11:22:30 -03:00
# include "vsp1_lif.h"
2013-07-10 12:03:30 -03:00
# include "vsp1_lut.h"
2013-06-04 11:22:30 -03:00
# include "vsp1_rwpf.h"
2013-07-10 12:03:30 -03:00
# include "vsp1_sru.h"
2013-06-04 11:22:30 -03:00
# include "vsp1_uds.h"
2015-07-28 15:46:00 -03:00
# include "vsp1_video.h"
2013-06-04 11:22:30 -03:00
/* -----------------------------------------------------------------------------
* Interrupt Handling
*/
static irqreturn_t vsp1_irq_handler ( int irq , void * data )
{
u32 mask = VI6_WFP_IRQ_STA_DFE | VI6_WFP_IRQ_STA_FRE ;
struct vsp1_device * vsp1 = data ;
irqreturn_t ret = IRQ_NONE ;
unsigned int i ;
2015-09-07 01:40:25 -03:00
u32 status ;
2013-06-04 11:22:30 -03:00
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > wpf_count ; + + i ) {
2013-06-04 11:22:30 -03:00
struct vsp1_rwpf * wpf = vsp1 - > wpf [ i ] ;
struct vsp1_pipeline * pipe ;
if ( wpf = = NULL )
continue ;
pipe = to_vsp1_pipeline ( & wpf - > entity . subdev . entity ) ;
status = vsp1_read ( vsp1 , VI6_WPF_IRQ_STA ( i ) ) ;
vsp1_write ( vsp1 , VI6_WPF_IRQ_STA ( i ) , ~ status & mask ) ;
if ( status & VI6_WFP_IRQ_STA_FRE ) {
vsp1_pipeline_frame_end ( pipe ) ;
ret = IRQ_HANDLED ;
}
}
2015-09-07 01:40:25 -03:00
status = vsp1_read ( vsp1 , VI6_DISP_IRQ_STA ) ;
vsp1_write ( vsp1 , VI6_DISP_IRQ_STA , ~ status & VI6_DISP_IRQ_STA_DST ) ;
if ( status & VI6_DISP_IRQ_STA_DST ) {
2015-11-08 20:06:57 -02:00
vsp1_drm_display_start ( vsp1 ) ;
2015-09-07 01:40:25 -03:00
ret = IRQ_HANDLED ;
}
2013-06-04 11:22:30 -03:00
return ret ;
}
/* -----------------------------------------------------------------------------
* Entities
*/
/*
2015-08-02 18:21:12 -03:00
* vsp1_create_sink_links - Create links from all sources to the given sink
2013-06-04 11:22:30 -03:00
*
* This function creates media links from all valid sources to the given sink
* pad . Links that would be invalid according to the VSP1 hardware capabilities
* are skipped . Those include all links
*
* - from a UDS to a UDS ( UDS entities can ' t be chained )
* - from an entity to itself ( no loops are allowed )
*/
2015-08-02 18:21:12 -03:00
static int vsp1_create_sink_links ( struct vsp1_device * vsp1 ,
struct vsp1_entity * sink )
2013-06-04 11:22:30 -03:00
{
struct media_entity * entity = & sink - > subdev . entity ;
struct vsp1_entity * source ;
unsigned int pad ;
int ret ;
list_for_each_entry ( source , & vsp1 - > entities , list_dev ) {
u32 flags ;
if ( source - > type = = sink - > type )
continue ;
if ( source - > type = = VSP1_ENTITY_LIF | |
source - > type = = VSP1_ENTITY_WPF )
continue ;
flags = source - > type = = VSP1_ENTITY_RPF & &
sink - > type = = VSP1_ENTITY_WPF & &
source - > index = = sink - > index
? MEDIA_LNK_FL_ENABLED : 0 ;
for ( pad = 0 ; pad < entity - > num_pads ; + + pad ) {
if ( ! ( entity - > pads [ pad ] . flags & MEDIA_PAD_FL_SINK ) )
continue ;
2015-08-07 08:14:38 -03:00
ret = media_create_pad_link ( & source - > subdev . entity ,
2013-06-04 11:22:30 -03:00
source - > source_pad ,
entity , pad , flags ) ;
if ( ret < 0 )
return ret ;
2013-07-26 06:32:11 -03:00
if ( flags & MEDIA_LNK_FL_ENABLED )
source - > sink = entity ;
2013-06-04 11:22:30 -03:00
}
}
2015-08-02 18:21:12 -03:00
return 0 ;
}
2016-01-31 11:34:28 -02:00
2015-08-02 18:37:01 -03:00
static int vsp1_uapi_create_links ( struct vsp1_device * vsp1 )
2015-08-02 18:21:12 -03:00
{
struct vsp1_entity * entity ;
unsigned int i ;
int ret ;
list_for_each_entry ( entity , & vsp1 - > entities , list_dev ) {
if ( entity - > type = = VSP1_ENTITY_LIF | |
entity - > type = = VSP1_ENTITY_RPF )
continue ;
ret = vsp1_create_sink_links ( vsp1 , entity ) ;
if ( ret < 0 )
return ret ;
}
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > features & VSP1_HAS_LIF ) {
2015-08-02 18:21:12 -03:00
ret = media_create_pad_link ( & vsp1 - > wpf [ 0 ] - > entity . subdev . entity ,
RWPF_PAD_SOURCE ,
& vsp1 - > lif - > entity . subdev . entity ,
LIF_PAD_SINK , 0 ) ;
if ( ret < 0 )
return ret ;
}
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > rpf_count ; + + i ) {
2015-08-02 18:21:12 -03:00
struct vsp1_rwpf * rpf = vsp1 - > rpf [ i ] ;
ret = media_create_pad_link ( & rpf - > video - > video . entity , 0 ,
& rpf - > entity . subdev . entity ,
RWPF_PAD_SINK ,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE ) ;
if ( ret < 0 )
return ret ;
}
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > wpf_count ; + + i ) {
2016-01-31 11:34:28 -02:00
/* Connect the video device to the WPF. All connections are
* immutable except for the WPF0 source link if a LIF is
* present .
*/
2015-08-02 18:21:12 -03:00
struct vsp1_rwpf * wpf = vsp1 - > wpf [ i ] ;
unsigned int flags = MEDIA_LNK_FL_ENABLED ;
2015-12-05 20:17:10 -02:00
if ( ! ( vsp1 - > info - > features & VSP1_HAS_LIF ) | | i ! = 0 )
2016-01-31 11:34:28 -02:00
flags | = MEDIA_LNK_FL_IMMUTABLE ;
2015-08-02 18:21:12 -03:00
ret = media_create_pad_link ( & wpf - > entity . subdev . entity ,
RWPF_PAD_SOURCE ,
& wpf - > video - > video . entity , 0 ,
flags ) ;
if ( ret < 0 )
return ret ;
2016-01-31 11:34:28 -02:00
}
2013-06-04 11:22:30 -03:00
return 0 ;
}
static void vsp1_destroy_entities ( struct vsp1_device * vsp1 )
{
2015-07-28 15:46:00 -03:00
struct vsp1_entity * entity , * _entity ;
struct vsp1_video * video , * _video ;
2013-06-04 11:22:30 -03:00
2015-07-28 15:46:00 -03:00
list_for_each_entry_safe ( entity , _entity , & vsp1 - > entities , list_dev ) {
2013-06-04 11:22:30 -03:00
list_del ( & entity - > list_dev ) ;
vsp1_entity_destroy ( entity ) ;
}
2015-07-28 15:46:00 -03:00
list_for_each_entry_safe ( video , _video , & vsp1 - > videos , list ) {
list_del ( & video - > list ) ;
vsp1_video_cleanup ( video ) ;
}
2013-06-04 11:22:30 -03:00
v4l2_device_unregister ( & vsp1 - > v4l2_dev ) ;
media_device_unregister ( & vsp1 - > media_dev ) ;
2015-12-11 20:57:08 -02:00
media_device_cleanup ( & vsp1 - > media_dev ) ;
2015-09-07 01:40:25 -03:00
2015-12-05 20:17:10 -02:00
if ( ! vsp1 - > info - > uapi )
2015-09-07 01:40:25 -03:00
vsp1_drm_cleanup ( vsp1 ) ;
2013-06-04 11:22:30 -03:00
}
static int vsp1_create_entities ( struct vsp1_device * vsp1 )
{
struct media_device * mdev = & vsp1 - > media_dev ;
struct v4l2_device * vdev = & vsp1 - > v4l2_dev ;
struct vsp1_entity * entity ;
unsigned int i ;
int ret ;
mdev - > dev = vsp1 - > dev ;
strlcpy ( mdev - > model , " VSP1 " , sizeof ( mdev - > model ) ) ;
2013-08-22 14:11:47 -03:00
snprintf ( mdev - > bus_info , sizeof ( mdev - > bus_info ) , " platform:%s " ,
dev_name ( mdev - > dev ) ) ;
2015-12-11 20:57:08 -02:00
media_device_init ( mdev ) ;
2013-06-04 11:22:30 -03:00
2015-08-05 17:14:41 -03:00
vsp1 - > media_ops . link_setup = vsp1_entity_link_setup ;
/* Don't perform link validation when the userspace API is disabled as
* the pipeline is configured internally by the driver in that case , and
* its configuration can thus be trusted .
*/
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > uapi )
2015-08-05 17:14:41 -03:00
vsp1 - > media_ops . link_validate = v4l2_subdev_link_validate ;
2013-06-04 11:22:30 -03:00
vdev - > mdev = mdev ;
ret = v4l2_device_register ( vsp1 - > dev , vdev ) ;
if ( ret < 0 ) {
dev_err ( vsp1 - > dev , " V4L2 device registration failed (%d) \n " ,
ret ) ;
goto done ;
}
/* Instantiate all the entities. */
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > features & VSP1_HAS_BRU ) {
2015-08-14 13:53:45 -03:00
vsp1 - > bru = vsp1_bru_create ( vsp1 ) ;
if ( IS_ERR ( vsp1 - > bru ) ) {
ret = PTR_ERR ( vsp1 - > bru ) ;
goto done ;
}
2013-07-10 18:03:46 -03:00
2015-08-14 13:53:45 -03:00
list_add_tail ( & vsp1 - > bru - > entity . list_dev , & vsp1 - > entities ) ;
}
2013-07-10 18:03:46 -03:00
2013-07-10 17:30:14 -03:00
vsp1 - > hsi = vsp1_hsit_create ( vsp1 , true ) ;
if ( IS_ERR ( vsp1 - > hsi ) ) {
ret = PTR_ERR ( vsp1 - > hsi ) ;
goto done ;
}
list_add_tail ( & vsp1 - > hsi - > entity . list_dev , & vsp1 - > entities ) ;
vsp1 - > hst = vsp1_hsit_create ( vsp1 , false ) ;
if ( IS_ERR ( vsp1 - > hst ) ) {
ret = PTR_ERR ( vsp1 - > hst ) ;
goto done ;
}
list_add_tail ( & vsp1 - > hst - > entity . list_dev , & vsp1 - > entities ) ;
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > features & VSP1_HAS_LIF ) {
2013-06-04 11:22:30 -03:00
vsp1 - > lif = vsp1_lif_create ( vsp1 ) ;
if ( IS_ERR ( vsp1 - > lif ) ) {
ret = PTR_ERR ( vsp1 - > lif ) ;
goto done ;
}
list_add_tail ( & vsp1 - > lif - > entity . list_dev , & vsp1 - > entities ) ;
}
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > features & VSP1_HAS_LUT ) {
2013-07-10 12:03:30 -03:00
vsp1 - > lut = vsp1_lut_create ( vsp1 ) ;
if ( IS_ERR ( vsp1 - > lut ) ) {
ret = PTR_ERR ( vsp1 - > lut ) ;
goto done ;
}
list_add_tail ( & vsp1 - > lut - > entity . list_dev , & vsp1 - > entities ) ;
}
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > rpf_count ; + + i ) {
2013-06-04 11:22:30 -03:00
struct vsp1_rwpf * rpf ;
rpf = vsp1_rpf_create ( vsp1 , i ) ;
if ( IS_ERR ( rpf ) ) {
ret = PTR_ERR ( rpf ) ;
goto done ;
}
vsp1 - > rpf [ i ] = rpf ;
list_add_tail ( & rpf - > entity . list_dev , & vsp1 - > entities ) ;
2015-07-28 15:46:00 -03:00
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > uapi ) {
2015-07-28 16:16:05 -03:00
struct vsp1_video * video = vsp1_video_create ( vsp1 , rpf ) ;
2015-07-28 15:46:00 -03:00
2015-07-28 16:16:05 -03:00
if ( IS_ERR ( video ) ) {
ret = PTR_ERR ( video ) ;
goto done ;
}
list_add_tail ( & video - > list , & vsp1 - > videos ) ;
}
2013-06-04 11:22:30 -03:00
}
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > features & VSP1_HAS_SRU ) {
2013-07-10 12:03:30 -03:00
vsp1 - > sru = vsp1_sru_create ( vsp1 ) ;
if ( IS_ERR ( vsp1 - > sru ) ) {
ret = PTR_ERR ( vsp1 - > sru ) ;
goto done ;
}
list_add_tail ( & vsp1 - > sru - > entity . list_dev , & vsp1 - > entities ) ;
}
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > uds_count ; + + i ) {
2013-06-04 11:22:30 -03:00
struct vsp1_uds * uds ;
uds = vsp1_uds_create ( vsp1 , i ) ;
if ( IS_ERR ( uds ) ) {
ret = PTR_ERR ( uds ) ;
goto done ;
}
vsp1 - > uds [ i ] = uds ;
list_add_tail ( & uds - > entity . list_dev , & vsp1 - > entities ) ;
}
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > wpf_count ; + + i ) {
2013-06-04 11:22:30 -03:00
struct vsp1_rwpf * wpf ;
wpf = vsp1_wpf_create ( vsp1 , i ) ;
if ( IS_ERR ( wpf ) ) {
ret = PTR_ERR ( wpf ) ;
goto done ;
}
vsp1 - > wpf [ i ] = wpf ;
list_add_tail ( & wpf - > entity . list_dev , & vsp1 - > entities ) ;
2015-07-28 15:46:00 -03:00
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > uapi ) {
2015-07-28 16:16:05 -03:00
struct vsp1_video * video = vsp1_video_create ( vsp1 , wpf ) ;
2015-07-28 15:46:00 -03:00
2015-07-28 16:16:05 -03:00
if ( IS_ERR ( video ) ) {
ret = PTR_ERR ( video ) ;
goto done ;
}
list_add_tail ( & video - > list , & vsp1 - > videos ) ;
wpf - > entity . sink = & video - > video . entity ;
}
2013-06-04 11:22:30 -03:00
}
2015-09-03 11:20:34 -03:00
/* Register all subdevs. */
list_for_each_entry ( entity , & vsp1 - > entities , list_dev ) {
ret = v4l2_device_register_subdev ( & vsp1 - > v4l2_dev ,
& entity - > subdev ) ;
if ( ret < 0 )
goto done ;
}
2013-06-04 11:22:30 -03:00
/* Create links. */
2015-12-05 20:17:10 -02:00
if ( vsp1 - > info - > uapi )
2015-08-02 18:37:01 -03:00
ret = vsp1_uapi_create_links ( vsp1 ) ;
else
ret = vsp1_drm_create_links ( vsp1 ) ;
2015-08-02 18:21:12 -03:00
if ( ret < 0 )
goto done ;
2013-06-04 11:22:30 -03:00
2015-08-02 18:37:01 -03:00
/* Register subdev nodes if the userspace API is enabled or initialize
* the DRM pipeline otherwise .
*/
2015-11-01 10:46:25 -02:00
if ( vsp1 - > info - > uapi )
2015-07-28 16:16:05 -03:00
ret = v4l2_device_register_subdev_nodes ( & vsp1 - > v4l2_dev ) ;
2015-11-01 10:46:25 -02:00
else
2015-08-02 18:37:01 -03:00
ret = vsp1_drm_init ( vsp1 ) ;
if ( ret < 0 )
goto done ;
2015-12-11 20:57:08 -02:00
ret = media_device_register ( mdev ) ;
2013-06-04 11:22:30 -03:00
done :
if ( ret < 0 )
vsp1_destroy_entities ( vsp1 ) ;
return ret ;
}
2015-09-07 01:40:25 -03:00
int vsp1_reset_wpf ( struct vsp1_device * vsp1 , unsigned int index )
2013-06-04 11:22:30 -03:00
{
2015-09-07 01:40:25 -03:00
unsigned int timeout ;
2013-06-04 11:22:30 -03:00
u32 status ;
status = vsp1_read ( vsp1 , VI6_STATUS ) ;
2015-09-07 01:40:25 -03:00
if ( ! ( status & VI6_STATUS_SYS_ACT ( index ) ) )
return 0 ;
2013-06-04 11:22:30 -03:00
2015-09-07 01:40:25 -03:00
vsp1_write ( vsp1 , VI6_SRESET , VI6_SRESET_SRTS ( index ) ) ;
for ( timeout = 10 ; timeout > 0 ; - - timeout ) {
status = vsp1_read ( vsp1 , VI6_STATUS ) ;
if ( ! ( status & VI6_STATUS_SYS_ACT ( index ) ) )
break ;
2013-06-04 11:22:30 -03:00
2015-09-07 01:40:25 -03:00
usleep_range ( 1000 , 2000 ) ;
}
2013-06-04 11:22:30 -03:00
2015-09-07 01:40:25 -03:00
if ( ! timeout ) {
dev_err ( vsp1 - > dev , " failed to reset wpf.%u \n " , index ) ;
return - ETIMEDOUT ;
}
2013-06-04 11:22:30 -03:00
2015-09-07 01:40:25 -03:00
return 0 ;
}
2013-06-04 11:22:30 -03:00
2015-09-07 01:40:25 -03:00
static int vsp1_device_init ( struct vsp1_device * vsp1 )
{
unsigned int i ;
int ret ;
/* Reset any channel that might be running. */
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > wpf_count ; + + i ) {
2015-09-07 01:40:25 -03:00
ret = vsp1_reset_wpf ( vsp1 , i ) ;
if ( ret < 0 )
return ret ;
2013-06-04 11:22:30 -03:00
}
vsp1_write ( vsp1 , VI6_CLK_DCSWT , ( 8 < < VI6_CLK_DCSWT_CSTPW_SHIFT ) |
( 8 < < VI6_CLK_DCSWT_CSTRW_SHIFT ) ) ;
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > rpf_count ; + + i )
2013-06-04 11:22:30 -03:00
vsp1_write ( vsp1 , VI6_DPR_RPF_ROUTE ( i ) , VI6_DPR_NODE_UNUSED ) ;
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < vsp1 - > info - > uds_count ; + + i )
2013-06-04 11:22:30 -03:00
vsp1_write ( vsp1 , VI6_DPR_UDS_ROUTE ( i ) , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_SRU_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_LUT_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_CLU_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_HST_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_HSI_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_BRU_ROUTE , VI6_DPR_NODE_UNUSED ) ;
vsp1_write ( vsp1 , VI6_DPR_HGO_SMPPT , ( 7 < < VI6_DPR_SMPPT_TGW_SHIFT ) |
( VI6_DPR_NODE_UNUSED < < VI6_DPR_SMPPT_PT_SHIFT ) ) ;
vsp1_write ( vsp1 , VI6_DPR_HGT_SMPPT , ( 7 < < VI6_DPR_SMPPT_TGW_SHIFT ) |
( VI6_DPR_NODE_UNUSED < < VI6_DPR_SMPPT_PT_SHIFT ) ) ;
2015-11-08 20:06:57 -02:00
vsp1_dlm_setup ( vsp1 ) ;
2015-09-07 01:40:25 -03:00
2013-06-04 11:22:30 -03:00
return 0 ;
}
/*
* vsp1_device_get - Acquire the VSP1 device
*
* Increment the VSP1 reference count and initialize the device if the first
* reference is taken .
*
2014-05-31 08:50:32 -03:00
* Return 0 on success or a negative error code otherwise .
2013-06-04 11:22:30 -03:00
*/
2014-05-31 08:50:32 -03:00
int vsp1_device_get ( struct vsp1_device * vsp1 )
2013-06-04 11:22:30 -03:00
{
2014-05-31 08:50:32 -03:00
int ret = 0 ;
2013-06-04 11:22:30 -03:00
mutex_lock ( & vsp1 - > lock ) ;
if ( vsp1 - > ref_count > 0 )
goto done ;
2014-04-02 11:21:56 -03:00
ret = clk_prepare_enable ( vsp1 - > clock ) ;
2014-05-31 08:50:32 -03:00
if ( ret < 0 )
2013-06-04 11:22:30 -03:00
goto done ;
ret = vsp1_device_init ( vsp1 ) ;
if ( ret < 0 ) {
2014-04-02 11:21:56 -03:00
clk_disable_unprepare ( vsp1 - > clock ) ;
2013-06-04 11:22:30 -03:00
goto done ;
}
done :
2014-05-31 08:50:32 -03:00
if ( ! ret )
2013-06-04 11:22:30 -03:00
vsp1 - > ref_count + + ;
mutex_unlock ( & vsp1 - > lock ) ;
2014-05-31 08:50:32 -03:00
return ret ;
2013-06-04 11:22:30 -03:00
}
/*
* vsp1_device_put - Release the VSP1 device
*
* Decrement the VSP1 reference count and cleanup the device if the last
* reference is released .
*/
void vsp1_device_put ( struct vsp1_device * vsp1 )
{
mutex_lock ( & vsp1 - > lock ) ;
if ( - - vsp1 - > ref_count = = 0 )
2014-04-02 11:21:56 -03:00
clk_disable_unprepare ( vsp1 - > clock ) ;
2013-06-04 11:22:30 -03:00
mutex_unlock ( & vsp1 - > lock ) ;
}
/* -----------------------------------------------------------------------------
* Power Management
*/
# ifdef CONFIG_PM_SLEEP
static int vsp1_pm_suspend ( struct device * dev )
{
struct vsp1_device * vsp1 = dev_get_drvdata ( dev ) ;
WARN_ON ( mutex_is_locked ( & vsp1 - > lock ) ) ;
if ( vsp1 - > ref_count = = 0 )
return 0 ;
2015-03-15 11:33:07 -03:00
vsp1_pipelines_suspend ( vsp1 ) ;
2014-04-02 11:21:56 -03:00
clk_disable_unprepare ( vsp1 - > clock ) ;
2015-03-15 11:33:07 -03:00
2013-06-04 11:22:30 -03:00
return 0 ;
}
static int vsp1_pm_resume ( struct device * dev )
{
struct vsp1_device * vsp1 = dev_get_drvdata ( dev ) ;
WARN_ON ( mutex_is_locked ( & vsp1 - > lock ) ) ;
2015-03-15 11:33:07 -03:00
if ( vsp1 - > ref_count = = 0 )
2013-06-04 11:22:30 -03:00
return 0 ;
2015-03-15 11:33:07 -03:00
clk_prepare_enable ( vsp1 - > clock ) ;
vsp1_pipelines_resume ( vsp1 ) ;
return 0 ;
2013-06-04 11:22:30 -03:00
}
# endif
static const struct dev_pm_ops vsp1_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( vsp1_pm_suspend , vsp1_pm_resume )
} ;
/* -----------------------------------------------------------------------------
* Platform Driver
*/
2015-12-05 20:17:10 -02:00
static const struct vsp1_device_info vsp1_device_infos [ ] = {
{
. version = VI6_IP_VERSION_MODEL_VSPS_H2 ,
. features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU ,
. rpf_count = 5 ,
. uds_count = 3 ,
. wpf_count = 4 ,
. num_bru_inputs = 4 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPR_H2 ,
. features = VSP1_HAS_BRU | VSP1_HAS_SRU ,
. rpf_count = 5 ,
. uds_count = 1 ,
. wpf_count = 4 ,
. num_bru_inputs = 4 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPD_GEN2 ,
. features = VSP1_HAS_BRU | VSP1_HAS_LIF | VSP1_HAS_LUT ,
. rpf_count = 4 ,
. uds_count = 1 ,
. wpf_count = 4 ,
. num_bru_inputs = 4 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPS_M2 ,
. features = VSP1_HAS_BRU | VSP1_HAS_LUT | VSP1_HAS_SRU ,
. rpf_count = 5 ,
. uds_count = 3 ,
. wpf_count = 4 ,
. num_bru_inputs = 4 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPI_GEN3 ,
. features = VSP1_HAS_LUT | VSP1_HAS_SRU ,
. rpf_count = 1 ,
. uds_count = 1 ,
. wpf_count = 1 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPBD_GEN3 ,
. features = VSP1_HAS_BRU ,
. rpf_count = 5 ,
. wpf_count = 1 ,
. num_bru_inputs = 5 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPBC_GEN3 ,
. features = VSP1_HAS_BRU | VSP1_HAS_LUT ,
. rpf_count = 5 ,
. wpf_count = 1 ,
. num_bru_inputs = 5 ,
. uapi = true ,
} , {
. version = VI6_IP_VERSION_MODEL_VSPD_GEN3 ,
2016-02-11 19:32:00 -02:00
. features = VSP1_HAS_BRU | VSP1_HAS_LIF ,
2015-12-05 20:17:10 -02:00
. rpf_count = 5 ,
. wpf_count = 2 ,
. num_bru_inputs = 5 ,
} ,
} ;
2014-04-08 13:40:13 -03:00
2013-06-04 11:22:30 -03:00
static int vsp1_probe ( struct platform_device * pdev )
{
struct vsp1_device * vsp1 ;
struct resource * irq ;
struct resource * io ;
2015-12-05 20:17:10 -02:00
unsigned int i ;
2015-09-07 08:05:39 -03:00
u32 version ;
2013-06-04 11:22:30 -03:00
int ret ;
vsp1 = devm_kzalloc ( & pdev - > dev , sizeof ( * vsp1 ) , GFP_KERNEL ) ;
if ( vsp1 = = NULL )
return - ENOMEM ;
vsp1 - > dev = & pdev - > dev ;
mutex_init ( & vsp1 - > lock ) ;
INIT_LIST_HEAD ( & vsp1 - > entities ) ;
2015-07-28 15:46:00 -03:00
INIT_LIST_HEAD ( & vsp1 - > videos ) ;
2013-06-04 11:22:30 -03:00
/* I/O, IRQ and clock resources */
io = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
vsp1 - > mmio = devm_ioremap_resource ( & pdev - > dev , io ) ;
2013-08-24 08:47:51 -03:00
if ( IS_ERR ( vsp1 - > mmio ) )
return PTR_ERR ( vsp1 - > mmio ) ;
2013-06-04 11:22:30 -03:00
vsp1 - > clock = devm_clk_get ( & pdev - > dev , NULL ) ;
if ( IS_ERR ( vsp1 - > clock ) ) {
dev_err ( & pdev - > dev , " failed to get clock \n " ) ;
return PTR_ERR ( vsp1 - > clock ) ;
}
irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( ! irq ) {
dev_err ( & pdev - > dev , " missing IRQ \n " ) ;
return - EINVAL ;
}
ret = devm_request_irq ( & pdev - > dev , irq - > start , vsp1_irq_handler ,
IRQF_SHARED , dev_name ( & pdev - > dev ) , vsp1 ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to request IRQ \n " ) ;
return ret ;
}
2015-09-07 08:05:39 -03:00
/* Configure device parameters based on the version register. */
ret = clk_prepare_enable ( vsp1 - > clock ) ;
if ( ret < 0 )
return ret ;
version = vsp1_read ( vsp1 , VI6_IP_VERSION ) ;
clk_disable_unprepare ( vsp1 - > clock ) ;
2015-12-05 20:17:10 -02:00
for ( i = 0 ; i < ARRAY_SIZE ( vsp1_device_infos ) ; + + i ) {
if ( ( version & VI6_IP_VERSION_MODEL_MASK ) = =
vsp1_device_infos [ i ] . version ) {
vsp1 - > info = & vsp1_device_infos [ i ] ;
break ;
}
}
2015-09-07 08:05:39 -03:00
2015-12-05 20:17:10 -02:00
if ( ! vsp1 - > info ) {
dev_err ( & pdev - > dev , " unsupported IP version 0x%08x \n " , version ) ;
return - ENXIO ;
2015-09-07 08:05:39 -03:00
}
2015-12-05 20:17:10 -02:00
dev_dbg ( & pdev - > dev , " IP version 0x%08x \n " , version ) ;
2013-06-04 11:22:30 -03:00
/* Instanciate entities */
ret = vsp1_create_entities ( vsp1 ) ;
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " failed to create entities \n " ) ;
return ret ;
}
platform_set_drvdata ( pdev , vsp1 ) ;
return 0 ;
}
static int vsp1_remove ( struct platform_device * pdev )
{
struct vsp1_device * vsp1 = platform_get_drvdata ( pdev ) ;
vsp1_destroy_entities ( vsp1 ) ;
return 0 ;
}
2014-04-08 13:40:13 -03:00
static const struct of_device_id vsp1_of_match [ ] = {
{ . compatible = " renesas,vsp1 " } ,
2015-09-07 08:05:39 -03:00
{ . compatible = " renesas,vsp2 " } ,
2014-04-08 13:40:13 -03:00
{ } ,
} ;
2013-06-04 11:22:30 -03:00
static struct platform_driver vsp1_platform_driver = {
. probe = vsp1_probe ,
. remove = vsp1_remove ,
. driver = {
. name = " vsp1 " ,
. pm = & vsp1_pm_ops ,
2014-04-08 13:40:13 -03:00
. of_match_table = vsp1_of_match ,
2013-06-04 11:22:30 -03:00
} ,
} ;
module_platform_driver ( vsp1_platform_driver ) ;
MODULE_ALIAS ( " vsp1 " ) ;
MODULE_AUTHOR ( " Laurent Pinchart <laurent.pinchart@ideasonboard.com> " ) ;
MODULE_DESCRIPTION ( " Renesas VSP1 Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;