2018-09-28 16:13:25 -03:00
// SPDX-License-Identifier: GPL-2.0+
2012-09-21 10:07:50 +02:00
/*
* i . MX IPUv3 Graphics driver
*
* Copyright ( C ) 2011 Sascha Hauer , Pengutronix
*/
2019-07-16 08:42:18 +02:00
2019-01-17 22:03:34 +01:00
# include <linux/clk.h>
2013-11-03 11:23:34 +00:00
# include <linux/component.h>
2012-09-21 10:07:50 +02:00
# include <linux/device.h>
2019-07-16 08:42:18 +02:00
# include <linux/dma-mapping.h>
2019-01-17 22:03:34 +01:00
# include <linux/errno.h>
# include <linux/export.h>
# include <linux/module.h>
2012-09-21 10:07:50 +02:00
# include <linux/platform_device.h>
2019-07-16 08:42:18 +02:00
# include <video/imx-ipu-v3.h>
2016-07-08 17:40:57 +08:00
# include <drm/drm_atomic.h>
2016-07-08 17:40:56 +08:00
# include <drm/drm_atomic_helper.h>
2012-09-21 10:07:50 +02:00
# include <drm/drm_fb_cma_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_gem_cma_helper.h>
# include <drm/drm_probe_helper.h>
2019-07-16 08:42:18 +02:00
# include <drm/drm_vblank.h>
2012-09-21 10:07:50 +02:00
# include "imx-drm.h"
2013-10-10 16:18:45 +02:00
# include "ipuv3-plane.h"
2012-09-21 10:07:50 +02:00
# define DRIVER_DESC "i.MX IPUv3 Graphics"
struct ipu_crtc {
struct device * dev ;
struct drm_crtc base ;
2013-10-10 16:18:45 +02:00
/* plane[0] is the full plane, plane[1] is the partial plane */
struct ipu_plane * plane [ 2 ] ;
2012-09-21 10:07:50 +02:00
struct ipu_dc * dc ;
struct ipu_di * di ;
int irq ;
2018-09-11 16:03:16 +02:00
struct drm_pending_vblank_event * event ;
2012-09-21 10:07:50 +02:00
} ;
2016-07-06 15:47:11 +02:00
static inline struct ipu_crtc * to_ipu_crtc ( struct drm_crtc * crtc )
{
return container_of ( crtc , struct ipu_crtc , base ) ;
}
2012-09-21 10:07:50 +02:00
2017-06-30 12:36:44 +03:00
static void ipu_crtc_atomic_enable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_state )
2012-09-21 10:07:50 +02:00
{
2016-07-08 17:41:01 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2014-04-14 23:53:23 +02:00
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
2017-03-08 12:13:20 +01:00
ipu_prg_enable ( ipu ) ;
2014-04-14 23:53:23 +02:00
ipu_dc_enable ( ipu ) ;
2014-04-14 23:53:22 +02:00
ipu_dc_enable_channel ( ipu_crtc - > dc ) ;
ipu_di_enable ( ipu_crtc - > di ) ;
2012-09-21 10:07:50 +02:00
}
2017-02-24 18:31:05 +01:00
static void ipu_crtc_disable_planes ( struct ipu_crtc * ipu_crtc ,
struct drm_crtc_state * old_crtc_state )
{
bool disable_partial = false ;
bool disable_full = false ;
struct drm_plane * plane ;
drm_atomic_crtc_state_for_each_plane ( plane , old_crtc_state ) {
if ( plane = = & ipu_crtc - > plane [ 0 ] - > base )
disable_full = true ;
if ( & ipu_crtc - > plane [ 1 ] & & plane = = & ipu_crtc - > plane [ 1 ] - > base )
disable_partial = true ;
}
if ( disable_partial )
ipu_plane_disable ( ipu_crtc - > plane [ 1 ] , true ) ;
if ( disable_full )
2019-04-12 17:59:41 +02:00
ipu_plane_disable ( ipu_crtc - > plane [ 0 ] , true ) ;
2017-02-24 18:31:05 +01:00
}
2016-08-26 15:30:42 +08:00
static void ipu_crtc_atomic_disable ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
2012-09-21 10:07:50 +02:00
{
2016-07-08 17:41:01 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2014-04-14 23:53:23 +02:00
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
2012-09-21 10:07:50 +02:00
ipu_dc_disable_channel ( ipu_crtc - > dc ) ;
ipu_di_disable ( ipu_crtc - > di ) ;
2016-11-08 17:04:10 +01:00
/*
* Planes must be disabled before DC clock is removed , as otherwise the
* attached IDMACs will be left in undefined state , possibly hanging
* the IPU or even system .
*/
2017-02-24 18:31:05 +01:00
ipu_crtc_disable_planes ( ipu_crtc , old_crtc_state ) ;
2014-04-14 23:53:23 +02:00
ipu_dc_disable ( ipu ) ;
2017-03-08 12:13:20 +01:00
ipu_prg_disable ( ipu ) ;
2016-07-08 17:40:55 +08:00
2019-06-25 18:59:13 +01:00
drm_crtc_vblank_off ( crtc ) ;
2016-07-08 17:40:59 +08:00
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
2019-06-25 18:59:15 +01:00
if ( crtc - > state - > event & & ! crtc - > state - > active ) {
2016-07-08 17:40:59 +08:00
drm_crtc_send_vblank_event ( crtc , crtc - > state - > event ) ;
crtc - > state - > event = NULL ;
}
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
2012-09-21 10:07:50 +02:00
}
2016-07-06 14:49:24 +02:00
static void imx_drm_crtc_reset ( struct drm_crtc * crtc )
{
struct imx_crtc_state * state ;
if ( crtc - > state ) {
if ( crtc - > state - > mode_blob )
2017-08-11 15:32:58 +03:00
drm_property_blob_put ( crtc - > state - > mode_blob ) ;
2016-07-06 14:49:24 +02:00
state = to_imx_crtc_state ( crtc - > state ) ;
memset ( state , 0 , sizeof ( * state ) ) ;
} else {
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return ;
crtc - > state = & state - > base ;
}
state - > base . crtc = crtc ;
}
static struct drm_crtc_state * imx_drm_crtc_duplicate_state ( struct drm_crtc * crtc )
{
struct imx_crtc_state * state ;
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return NULL ;
__drm_atomic_helper_crtc_duplicate_state ( crtc , & state - > base ) ;
WARN_ON ( state - > base . crtc ! = crtc ) ;
state - > base . crtc = crtc ;
return & state - > base ;
}
static void imx_drm_crtc_destroy_state ( struct drm_crtc * crtc ,
struct drm_crtc_state * state )
{
__drm_atomic_helper_crtc_destroy_state ( state ) ;
kfree ( to_imx_crtc_state ( state ) ) ;
}
2017-02-07 17:16:24 +08:00
static int ipu_enable_vblank ( struct drm_crtc * crtc )
{
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
enable_irq ( ipu_crtc - > irq ) ;
return 0 ;
}
static void ipu_disable_vblank ( struct drm_crtc * crtc )
2016-08-11 11:18:49 +02:00
{
2017-02-07 17:16:24 +08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
disable_irq_nosync ( ipu_crtc - > irq ) ;
2016-08-11 11:18:49 +02:00
}
2012-09-21 10:07:50 +02:00
static const struct drm_crtc_funcs ipu_crtc_funcs = {
2016-07-08 17:40:59 +08:00
. set_config = drm_atomic_helper_set_config ,
2017-02-07 17:16:24 +08:00
. destroy = drm_crtc_cleanup ,
2016-07-08 17:40:59 +08:00
. page_flip = drm_atomic_helper_page_flip ,
2016-07-06 14:49:24 +02:00
. reset = imx_drm_crtc_reset ,
. atomic_duplicate_state = imx_drm_crtc_duplicate_state ,
. atomic_destroy_state = imx_drm_crtc_destroy_state ,
2017-02-07 17:16:24 +08:00
. enable_vblank = ipu_enable_vblank ,
. disable_vblank = ipu_disable_vblank ,
2012-09-21 10:07:50 +02:00
} ;
static irqreturn_t ipu_irq_handler ( int irq , void * dev_id )
{
struct ipu_crtc * ipu_crtc = dev_id ;
2018-09-11 16:03:16 +02:00
struct drm_crtc * crtc = & ipu_crtc - > base ;
unsigned long flags ;
int i ;
drm_crtc_handle_vblank ( crtc ) ;
if ( ipu_crtc - > event ) {
for ( i = 0 ; i < ARRAY_SIZE ( ipu_crtc - > plane ) ; i + + ) {
struct ipu_plane * plane = ipu_crtc - > plane [ i ] ;
if ( ! plane )
continue ;
if ( ipu_plane_atomic_update_pending ( & plane - > base ) )
break ;
}
if ( i = = ARRAY_SIZE ( ipu_crtc - > plane ) ) {
spin_lock_irqsave ( & crtc - > dev - > event_lock , flags ) ;
drm_crtc_send_vblank_event ( crtc , ipu_crtc - > event ) ;
ipu_crtc - > event = NULL ;
drm_crtc_vblank_put ( crtc ) ;
spin_unlock_irqrestore ( & crtc - > dev - > event_lock , flags ) ;
}
}
2012-09-21 10:07:50 +02:00
return IRQ_HANDLED ;
}
static bool ipu_crtc_mode_fixup ( struct drm_crtc * crtc ,
const struct drm_display_mode * mode ,
struct drm_display_mode * adjusted_mode )
{
2014-12-18 18:00:23 -08:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
struct videomode vm ;
int ret ;
drm_display_mode_to_videomode ( adjusted_mode , & vm ) ;
ret = ipu_di_adjust_videomode ( ipu_crtc - > di , & vm ) ;
if ( ret )
return false ;
2016-07-08 17:40:55 +08:00
if ( ( vm . vsync_len = = 0 ) | | ( vm . hsync_len = = 0 ) )
return false ;
2014-12-18 18:00:23 -08:00
drm_display_mode_from_videomode ( & vm , adjusted_mode ) ;
2012-09-21 10:07:50 +02:00
return true ;
}
2016-07-08 17:40:55 +08:00
static int ipu_crtc_atomic_check ( struct drm_crtc * crtc ,
struct drm_crtc_state * state )
{
2018-06-26 22:47:12 +03:00
u32 primary_plane_mask = drm_plane_mask ( crtc - > primary ) ;
2016-07-08 17:40:59 +08:00
if ( state - > active & & ( primary_plane_mask & state - > plane_mask ) = = 0 )
return - EINVAL ;
2016-07-08 17:40:55 +08:00
return 0 ;
}
2016-07-08 17:40:59 +08:00
static void ipu_crtc_atomic_begin ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
{
2016-08-29 17:51:24 +02:00
drm_crtc_vblank_on ( crtc ) ;
2018-03-15 10:11:59 +01:00
}
2016-08-29 17:51:24 +02:00
2018-03-15 10:11:59 +01:00
static void ipu_crtc_atomic_flush ( struct drm_crtc * crtc ,
struct drm_crtc_state * old_crtc_state )
{
2016-07-08 17:40:59 +08:00
spin_lock_irq ( & crtc - > dev - > event_lock ) ;
if ( crtc - > state - > event ) {
2018-09-11 16:03:16 +02:00
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
2016-07-08 17:40:59 +08:00
WARN_ON ( drm_crtc_vblank_get ( crtc ) ) ;
2018-09-11 16:03:16 +02:00
ipu_crtc - > event = crtc - > state - > event ;
2016-07-08 17:40:59 +08:00
crtc - > state - > event = NULL ;
}
spin_unlock_irq ( & crtc - > dev - > event_lock ) ;
}
2016-07-08 17:40:55 +08:00
static void ipu_crtc_mode_set_nofb ( struct drm_crtc * crtc )
{
struct drm_device * dev = crtc - > dev ;
struct drm_encoder * encoder ;
struct ipu_crtc * ipu_crtc = to_ipu_crtc ( crtc ) ;
struct drm_display_mode * mode = & crtc - > state - > adjusted_mode ;
2016-07-06 14:49:24 +02:00
struct imx_crtc_state * imx_crtc_state = to_imx_crtc_state ( crtc - > state ) ;
2016-07-08 17:40:55 +08:00
struct ipu_di_signal_cfg sig_cfg = { } ;
unsigned long encoder_types = 0 ;
dev_dbg ( ipu_crtc - > dev , " %s: mode->hdisplay: %d \n " , __func__ ,
mode - > hdisplay ) ;
dev_dbg ( ipu_crtc - > dev , " %s: mode->vdisplay: %d \n " , __func__ ,
mode - > vdisplay ) ;
2016-07-08 17:40:58 +08:00
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
2016-07-06 14:49:24 +02:00
if ( encoder - > crtc = = crtc )
2016-07-08 17:40:55 +08:00
encoder_types | = BIT ( encoder - > encoder_type ) ;
2016-07-08 17:40:58 +08:00
}
2016-07-08 17:40:55 +08:00
dev_dbg ( ipu_crtc - > dev , " %s: attached to encoder types 0x%lx \n " ,
__func__ , encoder_types ) ;
/*
* If we have DAC or LDB , then we need the IPU DI clock to be
* the same as the LDB DI clock . For TVDAC , derive the IPU DI
* clock from 27 MHz TVE_DI clock , but allow to divide it .
*/
if ( encoder_types & ( BIT ( DRM_MODE_ENCODER_DAC ) |
BIT ( DRM_MODE_ENCODER_LVDS ) ) )
sig_cfg . clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT ;
else if ( encoder_types & BIT ( DRM_MODE_ENCODER_TVDAC ) )
sig_cfg . clkflags = IPU_DI_CLKMODE_EXT ;
else
sig_cfg . clkflags = 0 ;
2016-07-06 14:49:24 +02:00
sig_cfg . enable_pol = ! ( imx_crtc_state - > bus_flags & DRM_BUS_FLAG_DE_LOW ) ;
2016-07-08 17:40:55 +08:00
/* Default to driving pixel data on negative clock edges */
2016-07-06 14:49:24 +02:00
sig_cfg . clk_pol = ! ! ( imx_crtc_state - > bus_flags &
2018-09-22 15:02:42 +03:00
DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE ) ;
2016-07-06 14:49:24 +02:00
sig_cfg . bus_format = imx_crtc_state - > bus_format ;
2016-07-08 17:40:55 +08:00
sig_cfg . v_to_h_sync = 0 ;
2016-07-06 14:49:24 +02:00
sig_cfg . hsync_pin = imx_crtc_state - > di_hsync_pin ;
sig_cfg . vsync_pin = imx_crtc_state - > di_vsync_pin ;
2016-07-08 17:40:55 +08:00
drm_display_mode_to_videomode ( mode , & sig_cfg . mode ) ;
ipu_dc_init_sync ( ipu_crtc - > dc , ipu_crtc - > di ,
mode - > flags & DRM_MODE_FLAG_INTERLACE ,
2016-07-06 14:49:24 +02:00
imx_crtc_state - > bus_format , mode - > hdisplay ) ;
2016-07-08 17:40:55 +08:00
ipu_di_init_sync_panel ( ipu_crtc - > di , & sig_cfg ) ;
2012-09-21 10:07:50 +02:00
}
2015-12-15 12:21:09 +01:00
static const struct drm_crtc_helper_funcs ipu_helper_funcs = {
2012-09-21 10:07:50 +02:00
. mode_fixup = ipu_crtc_mode_fixup ,
2016-07-08 17:40:55 +08:00
. mode_set_nofb = ipu_crtc_mode_set_nofb ,
. atomic_check = ipu_crtc_atomic_check ,
2016-07-08 17:40:59 +08:00
. atomic_begin = ipu_crtc_atomic_begin ,
2018-03-15 10:11:59 +01:00
. atomic_flush = ipu_crtc_atomic_flush ,
2016-08-26 15:30:42 +08:00
. atomic_disable = ipu_crtc_atomic_disable ,
2017-06-30 12:36:44 +03:00
. atomic_enable = ipu_crtc_atomic_enable ,
2012-09-21 10:07:50 +02:00
} ;
static void ipu_put_resources ( struct ipu_crtc * ipu_crtc )
{
2013-10-10 16:18:45 +02:00
if ( ! IS_ERR_OR_NULL ( ipu_crtc - > dc ) )
ipu_dc_put ( ipu_crtc - > dc ) ;
2012-09-21 10:07:50 +02:00
if ( ! IS_ERR_OR_NULL ( ipu_crtc - > di ) )
ipu_di_put ( ipu_crtc - > di ) ;
}
static int ipu_get_resources ( struct ipu_crtc * ipu_crtc ,
struct ipu_client_platformdata * pdata )
{
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
int ret ;
ipu_crtc - > dc = ipu_dc_get ( ipu , pdata - > dc ) ;
if ( IS_ERR ( ipu_crtc - > dc ) ) {
ret = PTR_ERR ( ipu_crtc - > dc ) ;
goto err_out ;
}
ipu_crtc - > di = ipu_di_get ( ipu , pdata - > di ) ;
if ( IS_ERR ( ipu_crtc - > di ) ) {
ret = PTR_ERR ( ipu_crtc - > di ) ;
goto err_out ;
}
return 0 ;
err_out :
ipu_put_resources ( ipu_crtc ) ;
return ret ;
}
static int ipu_crtc_init ( struct ipu_crtc * ipu_crtc ,
2013-11-03 12:26:23 +00:00
struct ipu_client_platformdata * pdata , struct drm_device * drm )
2012-09-21 10:07:50 +02:00
{
2013-02-20 10:57:01 +08:00
struct ipu_soc * ipu = dev_get_drvdata ( ipu_crtc - > dev - > parent ) ;
2017-02-07 17:16:24 +08:00
struct drm_crtc * crtc = & ipu_crtc - > base ;
2013-10-10 16:18:45 +02:00
int dp = - EINVAL ;
2012-09-21 10:07:50 +02:00
int ret ;
ret = ipu_get_resources ( ipu_crtc , pdata ) ;
if ( ret ) {
dev_err ( ipu_crtc - > dev , " getting resources failed with %d. \n " ,
ret ) ;
return ret ;
}
2015-11-06 11:08:02 +01:00
if ( pdata - > dp > = 0 )
dp = IPU_DP_FLOW_SYNC_BG ;
ipu_crtc - > plane [ 0 ] = ipu_plane_init ( drm , ipu , pdata - > dma [ 0 ] , dp , 0 ,
DRM_PLANE_TYPE_PRIMARY ) ;
2015-11-06 22:42:45 +08:00
if ( IS_ERR ( ipu_crtc - > plane [ 0 ] ) ) {
ret = PTR_ERR ( ipu_crtc - > plane [ 0 ] ) ;
goto err_put_resources ;
}
2015-11-06 11:08:02 +01:00
2017-02-07 17:16:24 +08:00
crtc - > port = pdata - > of_node ;
drm_crtc_helper_add ( crtc , & ipu_helper_funcs ) ;
drm_crtc_init_with_planes ( drm , crtc , & ipu_crtc - > plane [ 0 ] - > base , NULL ,
& ipu_crtc_funcs , NULL ) ;
2012-09-21 10:07:50 +02:00
2013-10-10 16:18:45 +02:00
ret = ipu_plane_get_resources ( ipu_crtc - > plane [ 0 ] ) ;
if ( ret ) {
dev_err ( ipu_crtc - > dev , " getting plane 0 resources failed with %d. \n " ,
ret ) ;
2017-02-07 17:16:24 +08:00
goto err_put_resources ;
2013-10-10 16:18:45 +02:00
}
/* If this crtc is using the DP, add an overlay plane */
if ( pdata - > dp > = 0 & & pdata - > dma [ 1 ] > 0 ) {
2015-11-06 11:08:02 +01:00
ipu_crtc - > plane [ 1 ] = ipu_plane_init ( drm , ipu , pdata - > dma [ 1 ] ,
IPU_DP_FLOW_SYNC_FG ,
drm_crtc_mask ( & ipu_crtc - > base ) ,
DRM_PLANE_TYPE_OVERLAY ) ;
2016-07-08 17:40:55 +08:00
if ( IS_ERR ( ipu_crtc - > plane [ 1 ] ) ) {
2013-10-10 16:18:45 +02:00
ipu_crtc - > plane [ 1 ] = NULL ;
2016-07-08 17:40:55 +08:00
} else {
ret = ipu_plane_get_resources ( ipu_crtc - > plane [ 1 ] ) ;
if ( ret ) {
dev_err ( ipu_crtc - > dev , " getting plane 1 "
" resources failed with %d. \n " , ret ) ;
goto err_put_plane0_res ;
}
}
2013-10-10 16:18:45 +02:00
}
ipu_crtc - > irq = ipu_plane_irq ( ipu_crtc - > plane [ 0 ] ) ;
2013-02-20 10:57:01 +08:00
ret = devm_request_irq ( ipu_crtc - > dev , ipu_crtc - > irq , ipu_irq_handler , 0 ,
" imx_drm " , ipu_crtc ) ;
if ( ret < 0 ) {
dev_err ( ipu_crtc - > dev , " irq request failed with %d. \n " , ret ) ;
2016-07-08 17:40:55 +08:00
goto err_put_plane1_res ;
2013-02-20 10:57:01 +08:00
}
2016-02-09 11:43:08 +01:00
/* Only enable IRQ when we actually need it to trigger work. */
disable_irq ( ipu_crtc - > irq ) ;
2013-02-20 10:57:01 +08:00
2012-09-21 10:07:50 +02:00
return 0 ;
2016-07-08 17:40:55 +08:00
err_put_plane1_res :
if ( ipu_crtc - > plane [ 1 ] )
ipu_plane_put_resources ( ipu_crtc - > plane [ 1 ] ) ;
err_put_plane0_res :
2013-10-10 16:18:45 +02:00
ipu_plane_put_resources ( ipu_crtc - > plane [ 0 ] ) ;
2012-09-21 10:07:50 +02:00
err_put_resources :
ipu_put_resources ( ipu_crtc ) ;
return ret ;
}
2013-11-03 11:23:34 +00:00
static int ipu_drm_bind ( struct device * dev , struct device * master , void * data )
2012-09-21 10:07:50 +02:00
{
2013-11-03 11:23:34 +00:00
struct ipu_client_platformdata * pdata = dev - > platform_data ;
2013-11-03 12:26:23 +00:00
struct drm_device * drm = data ;
2012-09-21 10:07:50 +02:00
struct ipu_crtc * ipu_crtc ;
int ret ;
2013-11-03 11:23:34 +00:00
ipu_crtc = devm_kzalloc ( dev , sizeof ( * ipu_crtc ) , GFP_KERNEL ) ;
2012-09-21 10:07:50 +02:00
if ( ! ipu_crtc )
return - ENOMEM ;
2013-11-03 11:23:34 +00:00
ipu_crtc - > dev = dev ;
2012-09-21 10:07:50 +02:00
2013-11-03 12:26:23 +00:00
ret = ipu_crtc_init ( ipu_crtc , pdata , drm ) ;
2012-12-25 15:58:38 +01:00
if ( ret )
return ret ;
2012-09-21 10:07:50 +02:00
2013-11-03 11:23:34 +00:00
dev_set_drvdata ( dev , ipu_crtc ) ;
2012-09-21 10:07:50 +02:00
return 0 ;
}
2013-11-03 11:23:34 +00:00
static void ipu_drm_unbind ( struct device * dev , struct device * master ,
void * data )
2012-09-21 10:07:50 +02:00
{
2013-11-03 11:23:34 +00:00
struct ipu_crtc * ipu_crtc = dev_get_drvdata ( dev ) ;
2012-09-21 10:07:50 +02:00
ipu_put_resources ( ipu_crtc ) ;
2016-07-08 17:40:55 +08:00
if ( ipu_crtc - > plane [ 1 ] )
ipu_plane_put_resources ( ipu_crtc - > plane [ 1 ] ) ;
ipu_plane_put_resources ( ipu_crtc - > plane [ 0 ] ) ;
2013-11-03 11:23:34 +00:00
}
static const struct component_ops ipu_crtc_ops = {
. bind = ipu_drm_bind ,
. unbind = ipu_drm_unbind ,
} ;
2012-09-21 10:07:50 +02:00
2013-11-03 11:23:34 +00:00
static int ipu_drm_probe ( struct platform_device * pdev )
{
2014-03-05 10:20:52 +01:00
struct device * dev = & pdev - > dev ;
2013-11-03 11:23:34 +00:00
int ret ;
2014-03-05 10:20:52 +01:00
if ( ! dev - > platform_data )
2013-11-03 11:23:34 +00:00
return - EINVAL ;
2014-03-05 10:20:52 +01:00
ret = dma_set_coherent_mask ( dev , DMA_BIT_MASK ( 32 ) ) ;
2013-11-03 11:23:34 +00:00
if ( ret )
return ret ;
2014-03-05 10:20:52 +01:00
return component_add ( dev , & ipu_crtc_ops ) ;
2013-11-03 11:23:34 +00:00
}
static int ipu_drm_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & ipu_crtc_ops ) ;
2012-09-21 10:07:50 +02:00
return 0 ;
}
2017-03-23 17:18:37 +01:00
struct platform_driver ipu_drm_driver = {
2012-09-21 10:07:50 +02:00
. driver = {
. name = " imx-ipuv3-crtc " ,
} ,
. probe = ipu_drm_probe ,
2012-11-19 13:20:51 -05:00
. remove = ipu_drm_remove ,
2012-09-21 10:07:50 +02:00
} ;