2013-10-10 16:18:45 +02:00
/*
* i . MX IPUv3 DP Overlay Planes
*
* Copyright ( C ) 2013 Philipp Zabel , Pengutronix
*
* 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-07-08 17:40:59 +08:00
# include <drm/drm_atomic.h>
2016-07-08 17:40:56 +08:00
# include <drm/drm_atomic_helper.h>
2013-10-10 16:18:45 +02:00
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_gem_cma_helper.h>
2016-07-08 17:40:55 +08:00
# include <drm/drm_plane_helper.h>
2013-10-10 16:18:45 +02:00
2013-09-30 16:13:39 +02:00
# include "video/imx-ipu-v3.h"
2013-10-10 16:18:45 +02:00
# include "ipuv3-plane.h"
2017-03-08 12:13:21 +01:00
struct ipu_plane_state {
struct drm_plane_state base ;
bool use_pre ;
} ;
static inline struct ipu_plane_state *
to_ipu_plane_state ( struct drm_plane_state * p )
{
return container_of ( p , struct ipu_plane_state , base ) ;
}
2016-07-06 15:47:11 +02:00
static inline struct ipu_plane * to_ipu_plane ( struct drm_plane * p )
{
return container_of ( p , struct ipu_plane , base ) ;
}
2013-10-10 16:18:45 +02:00
static const uint32_t ipu_plane_formats [ ] = {
2014-12-12 13:40:38 +01:00
DRM_FORMAT_ARGB1555 ,
2013-10-10 16:18:45 +02:00
DRM_FORMAT_XRGB1555 ,
2014-12-12 13:40:38 +01:00
DRM_FORMAT_ABGR1555 ,
2013-10-10 16:18:45 +02:00
DRM_FORMAT_XBGR1555 ,
2014-12-12 13:40:38 +01:00
DRM_FORMAT_RGBA5551 ,
DRM_FORMAT_BGRA5551 ,
2015-08-04 17:22:06 +02:00
DRM_FORMAT_ARGB4444 ,
2013-10-10 16:18:45 +02:00
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ABGR8888 ,
DRM_FORMAT_XBGR8888 ,
2015-04-16 15:56:40 +02:00
DRM_FORMAT_RGBA8888 ,
DRM_FORMAT_RGBX8888 ,
DRM_FORMAT_BGRA8888 ,
DRM_FORMAT_BGRA8888 ,
2016-02-12 14:35:55 +01:00
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
2013-10-10 16:18:45 +02:00
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_YUV420 ,
DRM_FORMAT_YVU420 ,
2016-10-18 12:31:40 +02:00
DRM_FORMAT_YUV422 ,
DRM_FORMAT_YVU422 ,
DRM_FORMAT_YUV444 ,
DRM_FORMAT_YVU444 ,
DRM_FORMAT_NV12 ,
DRM_FORMAT_NV16 ,
2015-11-24 16:29:22 +01:00
DRM_FORMAT_RGB565 ,
2016-07-22 12:02:45 +02:00
DRM_FORMAT_RGB565_A8 ,
DRM_FORMAT_BGR565_A8 ,
DRM_FORMAT_RGB888_A8 ,
DRM_FORMAT_BGR888_A8 ,
DRM_FORMAT_RGBX8888_A8 ,
DRM_FORMAT_BGRX8888_A8 ,
2013-10-10 16:18:45 +02:00
} ;
int ipu_plane_irq ( struct ipu_plane * ipu_plane )
{
return ipu_idmac_channel_irq ( ipu_plane - > ipu , ipu_plane - > ipu_ch ,
IPU_IRQ_EOF ) ;
}
2016-07-08 17:40:55 +08:00
static inline unsigned long
2016-07-22 12:01:11 +02:00
drm_plane_state_to_eba ( struct drm_plane_state * state , int plane )
2013-10-10 16:18:45 +02:00
{
2016-07-08 17:40:55 +08:00
struct drm_framebuffer * fb = state - > fb ;
struct drm_gem_cma_object * cma_obj ;
2016-10-19 10:50:26 +02:00
int x = state - > src . x1 > > 16 ;
int y = state - > src . y1 > > 16 ;
2013-10-10 16:18:45 +02:00
2016-07-22 12:01:11 +02:00
cma_obj = drm_fb_cma_get_gem_obj ( fb , plane ) ;
2016-07-08 17:40:55 +08:00
BUG_ON ( ! cma_obj ) ;
2013-10-10 16:18:45 +02:00
2016-07-22 12:01:11 +02:00
return cma_obj - > paddr + fb - > offsets [ plane ] + fb - > pitches [ plane ] * y +
fb - > format - > cpp [ plane ] * x ;
2016-07-08 17:40:55 +08:00
}
2016-07-08 17:40:53 +08:00
2016-07-08 17:40:55 +08:00
static inline unsigned long
drm_plane_state_to_ubo ( struct drm_plane_state * state )
{
struct drm_framebuffer * fb = state - > fb ;
struct drm_gem_cma_object * cma_obj ;
2016-07-22 12:01:11 +02:00
unsigned long eba = drm_plane_state_to_eba ( state , 0 ) ;
2016-10-19 10:50:26 +02:00
int x = state - > src . x1 > > 16 ;
int y = state - > src . y1 > > 16 ;
2013-10-10 16:18:45 +02:00
2016-07-08 17:40:55 +08:00
cma_obj = drm_fb_cma_get_gem_obj ( fb , 1 ) ;
BUG_ON ( ! cma_obj ) ;
2014-10-08 17:19:15 +02:00
2016-12-14 23:32:55 +02:00
x / = drm_format_horz_chroma_subsampling ( fb - > format - > format ) ;
y / = drm_format_vert_chroma_subsampling ( fb - > format - > format ) ;
2016-10-18 12:26:19 +02:00
return cma_obj - > paddr + fb - > offsets [ 1 ] + fb - > pitches [ 1 ] * y +
2016-12-14 23:30:57 +02:00
fb - > format - > cpp [ 1 ] * x - eba ;
2016-07-08 17:40:55 +08:00
}
2014-10-08 17:19:15 +02:00
2016-07-08 17:40:55 +08:00
static inline unsigned long
drm_plane_state_to_vbo ( struct drm_plane_state * state )
{
struct drm_framebuffer * fb = state - > fb ;
struct drm_gem_cma_object * cma_obj ;
2016-07-22 12:01:11 +02:00
unsigned long eba = drm_plane_state_to_eba ( state , 0 ) ;
2016-10-19 10:50:26 +02:00
int x = state - > src . x1 > > 16 ;
int y = state - > src . y1 > > 16 ;
2016-07-08 17:40:55 +08:00
cma_obj = drm_fb_cma_get_gem_obj ( fb , 2 ) ;
BUG_ON ( ! cma_obj ) ;
2016-12-14 23:32:55 +02:00
x / = drm_format_horz_chroma_subsampling ( fb - > format - > format ) ;
y / = drm_format_vert_chroma_subsampling ( fb - > format - > format ) ;
2016-10-18 12:26:19 +02:00
return cma_obj - > paddr + fb - > offsets [ 2 ] + fb - > pitches [ 2 ] * y +
2016-12-14 23:30:57 +02:00
fb - > format - > cpp [ 2 ] * x - eba ;
2016-07-08 17:40:55 +08:00
}
2013-10-10 16:18:45 +02:00
void ipu_plane_put_resources ( struct ipu_plane * ipu_plane )
{
if ( ! IS_ERR_OR_NULL ( ipu_plane - > dp ) )
ipu_dp_put ( ipu_plane - > dp ) ;
if ( ! IS_ERR_OR_NULL ( ipu_plane - > dmfc ) )
ipu_dmfc_put ( ipu_plane - > dmfc ) ;
if ( ! IS_ERR_OR_NULL ( ipu_plane - > ipu_ch ) )
ipu_idmac_put ( ipu_plane - > ipu_ch ) ;
2016-07-22 12:02:45 +02:00
if ( ! IS_ERR_OR_NULL ( ipu_plane - > alpha_ch ) )
ipu_idmac_put ( ipu_plane - > alpha_ch ) ;
2013-10-10 16:18:45 +02:00
}
int ipu_plane_get_resources ( struct ipu_plane * ipu_plane )
{
int ret ;
2016-07-22 12:02:45 +02:00
int alpha_ch ;
2013-10-10 16:18:45 +02:00
ipu_plane - > ipu_ch = ipu_idmac_get ( ipu_plane - > ipu , ipu_plane - > dma ) ;
if ( IS_ERR ( ipu_plane - > ipu_ch ) ) {
ret = PTR_ERR ( ipu_plane - > ipu_ch ) ;
DRM_ERROR ( " failed to get idmac channel: %d \n " , ret ) ;
return ret ;
}
2016-07-22 12:02:45 +02:00
alpha_ch = ipu_channel_alpha_channel ( ipu_plane - > dma ) ;
if ( alpha_ch > = 0 ) {
ipu_plane - > alpha_ch = ipu_idmac_get ( ipu_plane - > ipu , alpha_ch ) ;
if ( IS_ERR ( ipu_plane - > alpha_ch ) ) {
ret = PTR_ERR ( ipu_plane - > alpha_ch ) ;
DRM_ERROR ( " failed to get alpha idmac channel %d: %d \n " ,
alpha_ch , ret ) ;
return ret ;
}
}
2013-10-10 16:18:45 +02:00
ipu_plane - > dmfc = ipu_dmfc_get ( ipu_plane - > ipu , ipu_plane - > dma ) ;
if ( IS_ERR ( ipu_plane - > dmfc ) ) {
ret = PTR_ERR ( ipu_plane - > dmfc ) ;
DRM_ERROR ( " failed to get dmfc: ret %d \n " , ret ) ;
goto err_out ;
}
if ( ipu_plane - > dp_flow > = 0 ) {
ipu_plane - > dp = ipu_dp_get ( ipu_plane - > ipu , ipu_plane - > dp_flow ) ;
if ( IS_ERR ( ipu_plane - > dp ) ) {
ret = PTR_ERR ( ipu_plane - > dp ) ;
DRM_ERROR ( " failed to get dp flow: %d \n " , ret ) ;
goto err_out ;
}
}
return 0 ;
err_out :
ipu_plane_put_resources ( ipu_plane ) ;
return ret ;
}
2016-07-22 12:02:45 +02:00
static bool ipu_plane_separate_alpha ( struct ipu_plane * ipu_plane )
{
switch ( ipu_plane - > base . state - > fb - > format - > format ) {
case DRM_FORMAT_RGB565_A8 :
case DRM_FORMAT_BGR565_A8 :
case DRM_FORMAT_RGB888_A8 :
case DRM_FORMAT_BGR888_A8 :
case DRM_FORMAT_RGBX8888_A8 :
case DRM_FORMAT_BGRX8888_A8 :
return true ;
default :
return false ;
}
}
2016-07-08 17:40:55 +08:00
static void ipu_plane_enable ( struct ipu_plane * ipu_plane )
2013-10-10 16:18:45 +02:00
{
2014-04-14 23:53:20 +02:00
if ( ipu_plane - > dp )
ipu_dp_enable ( ipu_plane - > ipu ) ;
2013-10-10 16:18:45 +02:00
ipu_dmfc_enable_channel ( ipu_plane - > dmfc ) ;
ipu_idmac_enable_channel ( ipu_plane - > ipu_ch ) ;
2016-07-22 12:02:45 +02:00
if ( ipu_plane_separate_alpha ( ipu_plane ) )
ipu_idmac_enable_channel ( ipu_plane - > alpha_ch ) ;
2013-10-10 16:18:45 +02:00
if ( ipu_plane - > dp )
ipu_dp_enable_channel ( ipu_plane - > dp ) ;
}
2017-02-24 18:31:05 +01:00
void ipu_plane_disable ( struct ipu_plane * ipu_plane , bool disable_dp_channel )
2013-10-10 16:18:45 +02:00
{
2016-08-11 11:18:50 +02:00
DRM_DEBUG_KMS ( " [%d] %s \n " , __LINE__ , __func__ ) ;
2013-10-10 16:18:45 +02:00
ipu_idmac_wait_busy ( ipu_plane - > ipu_ch , 50 ) ;
2017-02-24 18:31:05 +01:00
if ( ipu_plane - > dp & & disable_dp_channel )
ipu_dp_disable_channel ( ipu_plane - > dp , false ) ;
2013-10-10 16:18:45 +02:00
ipu_idmac_disable_channel ( ipu_plane - > ipu_ch ) ;
2016-07-22 12:02:45 +02:00
if ( ipu_plane - > alpha_ch )
ipu_idmac_disable_channel ( ipu_plane - > alpha_ch ) ;
2013-10-10 16:18:45 +02:00
ipu_dmfc_disable_channel ( ipu_plane - > dmfc ) ;
2014-04-14 23:53:20 +02:00
if ( ipu_plane - > dp )
ipu_dp_disable ( ipu_plane - > ipu ) ;
2017-03-08 12:13:21 +01:00
if ( ipu_prg_present ( ipu_plane - > ipu ) )
ipu_prg_channel_disable ( ipu_plane - > ipu_ch ) ;
2017-02-24 18:31:05 +01:00
}
2013-10-10 16:18:45 +02:00
2017-02-24 18:31:05 +01:00
void ipu_plane_disable_deferred ( struct drm_plane * plane )
{
struct ipu_plane * ipu_plane = to_ipu_plane ( plane ) ;
if ( ipu_plane - > disabling ) {
ipu_plane - > disabling = false ;
ipu_plane_disable ( ipu_plane , false ) ;
}
2013-10-10 16:18:45 +02:00
}
2017-02-24 18:31:05 +01:00
EXPORT_SYMBOL_GPL ( ipu_plane_disable_deferred ) ;
2013-10-10 16:18:45 +02:00
2016-07-08 17:40:55 +08:00
static void ipu_plane_destroy ( struct drm_plane * plane )
2013-10-10 16:18:45 +02:00
{
struct ipu_plane * ipu_plane = to_ipu_plane ( plane ) ;
DRM_DEBUG_KMS ( " [%d] %s \n " , __LINE__ , __func__ ) ;
2016-07-08 17:40:55 +08:00
drm_plane_cleanup ( plane ) ;
kfree ( ipu_plane ) ;
}
2013-10-10 16:18:45 +02:00
2017-03-08 12:13:21 +01:00
void ipu_plane_state_reset ( struct drm_plane * plane )
{
struct ipu_plane_state * ipu_state ;
if ( plane - > state ) {
ipu_state = to_ipu_plane_state ( plane - > state ) ;
__drm_atomic_helper_plane_destroy_state ( plane - > state ) ;
kfree ( ipu_state ) ;
}
ipu_state = kzalloc ( sizeof ( * ipu_state ) , GFP_KERNEL ) ;
if ( ipu_state ) {
ipu_state - > base . plane = plane ;
ipu_state - > base . rotation = DRM_ROTATE_0 ;
}
plane - > state = & ipu_state - > base ;
}
struct drm_plane_state * ipu_plane_duplicate_state ( struct drm_plane * plane )
{
struct ipu_plane_state * state ;
if ( WARN_ON ( ! plane - > state ) )
return NULL ;
state = kmalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( state )
__drm_atomic_helper_plane_duplicate_state ( plane , & state - > base ) ;
return & state - > base ;
}
void ipu_plane_destroy_state ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct ipu_plane_state * ipu_state = to_ipu_plane_state ( state ) ;
__drm_atomic_helper_plane_destroy_state ( state ) ;
kfree ( ipu_state ) ;
}
2016-07-08 17:40:55 +08:00
static const struct drm_plane_funcs ipu_plane_funcs = {
2016-07-08 17:40:59 +08:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2016-07-08 17:40:55 +08:00
. destroy = ipu_plane_destroy ,
2017-03-08 12:13:21 +01:00
. reset = ipu_plane_state_reset ,
. atomic_duplicate_state = ipu_plane_duplicate_state ,
. atomic_destroy_state = ipu_plane_destroy_state ,
2016-07-08 17:40:55 +08:00
} ;
static int ipu_plane_atomic_check ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct drm_plane_state * old_state = plane - > state ;
struct drm_crtc_state * crtc_state ;
struct device * dev = plane - > dev - > dev ;
struct drm_framebuffer * fb = state - > fb ;
struct drm_framebuffer * old_fb = old_state - > fb ;
2016-07-22 12:02:45 +02:00
unsigned long eba , ubo , vbo , old_ubo , old_vbo , alpha_eba ;
2016-10-19 10:50:26 +02:00
bool can_position = ( plane - > type = = DRM_PLANE_TYPE_OVERLAY ) ;
struct drm_rect clip ;
2016-10-18 12:30:36 +02:00
int hsub , vsub ;
2016-10-19 10:50:26 +02:00
int ret ;
2016-07-08 17:40:55 +08:00
/* Ok to disable */
if ( ! fb )
2016-07-08 17:40:59 +08:00
return 0 ;
if ( ! state - > crtc )
return - EINVAL ;
crtc_state =
drm_atomic_get_existing_crtc_state ( state - > state , state - > crtc ) ;
if ( WARN_ON ( ! crtc_state ) )
return - EINVAL ;
2016-07-08 17:40:55 +08:00
2016-10-19 10:50:26 +02:00
clip . x1 = 0 ;
clip . y1 = 0 ;
clip . x2 = crtc_state - > adjusted_mode . hdisplay ;
clip . y2 = crtc_state - > adjusted_mode . vdisplay ;
ret = drm_plane_helper_check_state ( state , & clip ,
DRM_PLANE_HELPER_NO_SCALING ,
DRM_PLANE_HELPER_NO_SCALING ,
can_position , true ) ;
if ( ret )
return ret ;
2016-07-08 17:40:55 +08:00
/* CRTC should be enabled */
2016-07-08 17:40:59 +08:00
if ( ! crtc_state - > enable )
2016-07-08 17:40:55 +08:00
return - EINVAL ;
switch ( plane - > type ) {
case DRM_PLANE_TYPE_PRIMARY :
/* full plane minimum width is 13 pixels */
2016-10-19 10:50:26 +02:00
if ( drm_rect_width ( & state - > dst ) < 13 )
2016-07-08 17:40:55 +08:00
return - EINVAL ;
break ;
case DRM_PLANE_TYPE_OVERLAY :
break ;
default :
2016-10-19 10:50:26 +02:00
dev_warn ( dev , " Unsupported plane type %d \n " , plane - > type ) ;
2016-07-08 17:40:55 +08:00
return - EINVAL ;
}
2016-10-19 10:50:26 +02:00
if ( drm_rect_height ( & state - > dst ) < 2 )
2016-07-08 17:40:55 +08:00
return - EINVAL ;
/*
2016-08-26 15:30:44 +08:00
* We support resizing active plane or changing its format by
* forcing CRTC mode change in plane ' s - > atomic_check callback
* and disabling all affected active planes in CRTC ' s - > atomic_disable
* callback . The planes will be reenabled in plane ' s - > atomic_update
* callback .
2016-07-08 17:40:55 +08:00
*/
2016-10-19 10:50:26 +02:00
if ( old_fb & &
( drm_rect_width ( & state - > dst ) ! = drm_rect_width ( & old_state - > dst ) | |
drm_rect_height ( & state - > dst ) ! = drm_rect_height ( & old_state - > dst ) | |
fb - > format ! = old_fb - > format ) )
2016-08-26 15:30:44 +08:00
crtc_state - > mode_changed = true ;
2016-07-08 17:40:55 +08:00
2016-07-22 12:01:11 +02:00
eba = drm_plane_state_to_eba ( state , 0 ) ;
2016-07-08 17:40:55 +08:00
if ( eba & 0x7 )
return - EINVAL ;
if ( fb - > pitches [ 0 ] < 1 | | fb - > pitches [ 0 ] > 16384 )
return - EINVAL ;
if ( old_fb & & fb - > pitches [ 0 ] ! = old_fb - > pitches [ 0 ] )
2016-08-26 15:30:44 +08:00
crtc_state - > mode_changed = true ;
2016-07-08 17:40:55 +08:00
2016-12-14 23:32:55 +02:00
switch ( fb - > format - > format ) {
2016-07-08 17:40:55 +08:00
case DRM_FORMAT_YUV420 :
case DRM_FORMAT_YVU420 :
2016-10-18 12:31:40 +02:00
case DRM_FORMAT_YUV422 :
case DRM_FORMAT_YVU422 :
case DRM_FORMAT_YUV444 :
case DRM_FORMAT_YVU444 :
2016-07-08 17:40:55 +08:00
/*
* Multiplanar formats have to meet the following restrictions :
* - The ( up to ) three plane addresses are EBA , EBA + UBO , EBA + VBO
* - EBA , UBO and VBO are a multiple of 8
* - UBO and VBO are unsigned and not larger than 0xfffff8
* - Only EBA may be changed while scanout is active
* - The strides of U and V planes must be identical .
*/
vbo = drm_plane_state_to_vbo ( state ) ;
2016-10-18 12:31:40 +02:00
if ( vbo & 0x7 | | vbo > 0xfffff8 )
2016-07-08 17:40:55 +08:00
return - EINVAL ;
2016-11-18 21:53:10 +02:00
if ( old_fb & & ( fb - > format = = old_fb - > format ) ) {
2016-07-08 17:40:55 +08:00
old_vbo = drm_plane_state_to_vbo ( old_state ) ;
2016-10-18 12:31:40 +02:00
if ( vbo ! = old_vbo )
2016-10-18 12:13:15 +02:00
crtc_state - > mode_changed = true ;
2016-07-08 17:40:55 +08:00
}
if ( fb - > pitches [ 1 ] ! = fb - > pitches [ 2 ] )
return - EINVAL ;
2016-10-18 12:31:40 +02:00
/* fall-through */
case DRM_FORMAT_NV12 :
case DRM_FORMAT_NV16 :
ubo = drm_plane_state_to_ubo ( state ) ;
if ( ubo & 0x7 | | ubo > 0xfffff8 )
return - EINVAL ;
2016-11-18 21:53:10 +02:00
if ( old_fb & & ( fb - > format = = old_fb - > format ) ) {
2016-10-18 12:31:40 +02:00
old_ubo = drm_plane_state_to_ubo ( old_state ) ;
if ( ubo ! = old_ubo )
crtc_state - > mode_changed = true ;
}
2016-07-08 17:40:55 +08:00
if ( fb - > pitches [ 1 ] < 1 | | fb - > pitches [ 1 ] > 16384 )
return - EINVAL ;
if ( old_fb & & old_fb - > pitches [ 1 ] ! = fb - > pitches [ 1 ] )
2016-08-26 15:30:44 +08:00
crtc_state - > mode_changed = true ;
2016-10-18 12:30:36 +02:00
/*
* The x / y offsets must be even in case of horizontal / vertical
* chroma subsampling .
*/
2016-12-14 23:32:55 +02:00
hsub = drm_format_horz_chroma_subsampling ( fb - > format - > format ) ;
vsub = drm_format_vert_chroma_subsampling ( fb - > format - > format ) ;
2016-10-19 10:50:26 +02:00
if ( ( ( state - > src . x1 > > 16 ) & ( hsub - 1 ) ) | |
( ( state - > src . y1 > > 16 ) & ( vsub - 1 ) ) )
2016-10-18 12:30:36 +02:00
return - EINVAL ;
2016-07-22 12:02:45 +02:00
break ;
case DRM_FORMAT_RGB565_A8 :
case DRM_FORMAT_BGR565_A8 :
case DRM_FORMAT_RGB888_A8 :
case DRM_FORMAT_BGR888_A8 :
case DRM_FORMAT_RGBX8888_A8 :
case DRM_FORMAT_BGRX8888_A8 :
alpha_eba = drm_plane_state_to_eba ( state , 1 ) ;
if ( alpha_eba & 0x7 )
return - EINVAL ;
if ( fb - > pitches [ 1 ] < 1 | | fb - > pitches [ 1 ] > 16384 )
return - EINVAL ;
if ( old_fb & & old_fb - > pitches [ 1 ] ! = fb - > pitches [ 1 ] )
crtc_state - > mode_changed = true ;
break ;
2016-07-08 17:40:55 +08:00
}
2013-10-10 16:18:45 +02:00
return 0 ;
}
2016-07-08 17:40:55 +08:00
static void ipu_plane_atomic_disable ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
2017-02-24 18:31:05 +01:00
struct ipu_plane * ipu_plane = to_ipu_plane ( plane ) ;
if ( ipu_plane - > dp )
ipu_dp_disable_channel ( ipu_plane - > dp , true ) ;
ipu_plane - > disabling = true ;
2016-07-08 17:40:55 +08:00
}
2017-03-08 12:13:21 +01:00
static int ipu_chan_assign_axi_id ( int ipu_chan )
{
switch ( ipu_chan ) {
case IPUV3_CHANNEL_MEM_BG_SYNC :
return 1 ;
case IPUV3_CHANNEL_MEM_FG_SYNC :
return 2 ;
case IPUV3_CHANNEL_MEM_DC_SYNC :
return 3 ;
default :
return 0 ;
}
}
2016-07-08 17:40:55 +08:00
static void ipu_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
2013-10-10 16:18:45 +02:00
{
struct ipu_plane * ipu_plane = to_ipu_plane ( plane ) ;
2016-07-08 17:40:55 +08:00
struct drm_plane_state * state = plane - > state ;
2017-03-08 12:13:21 +01:00
struct ipu_plane_state * ipu_state = to_ipu_plane_state ( state ) ;
2016-10-18 11:40:25 +02:00
struct drm_crtc_state * crtc_state = state - > crtc - > state ;
struct drm_framebuffer * fb = state - > fb ;
2016-10-20 15:37:52 +02:00
struct drm_rect * dst = & state - > dst ;
2016-10-18 11:40:25 +02:00
unsigned long eba , ubo , vbo ;
2016-07-22 12:02:45 +02:00
unsigned long alpha_eba = 0 ;
2016-07-08 17:40:55 +08:00
enum ipu_color_space ics ;
2017-03-08 12:13:21 +01:00
unsigned int axi_id = 0 ;
2016-10-18 11:40:25 +02:00
int active ;
2013-10-10 16:18:45 +02:00
2016-10-20 15:37:52 +02:00
if ( ipu_plane - > dp_flow = = IPU_DP_FLOW_SYNC_FG )
ipu_dp_set_window_pos ( ipu_plane - > dp , dst - > x1 , dst - > y1 ) ;
2016-07-22 12:01:11 +02:00
eba = drm_plane_state_to_eba ( state , 0 ) ;
2016-08-26 15:30:43 +08:00
2017-03-08 12:13:21 +01:00
/*
* Configure PRG channel and attached PRE , this changes the EBA to an
* internal SRAM location .
*/
if ( ipu_state - > use_pre ) {
axi_id = ipu_chan_assign_axi_id ( ipu_plane - > dma ) ;
ipu_prg_channel_configure ( ipu_plane - > ipu_ch , axi_id ,
drm_rect_width ( & state - > src ) > > 16 ,
drm_rect_height ( & state - > src ) > > 16 ,
state - > fb - > pitches [ 0 ] ,
state - > fb - > format - > format , & eba ) ;
}
2016-10-18 11:40:25 +02:00
if ( old_state - > fb & & ! drm_atomic_crtc_needs_modeset ( crtc_state ) ) {
2017-03-08 12:13:21 +01:00
/* nothing to do if PRE is used */
if ( ipu_state - > use_pre )
return ;
2016-10-18 11:40:25 +02:00
active = ipu_idmac_get_current_buffer ( ipu_plane - > ipu_ch ) ;
ipu_cpmem_set_buffer ( ipu_plane - > ipu_ch , ! active , eba ) ;
ipu_idmac_select_buffer ( ipu_plane - > ipu_ch , ! active ) ;
2016-07-22 12:02:45 +02:00
if ( ipu_plane_separate_alpha ( ipu_plane ) ) {
active = ipu_idmac_get_current_buffer ( ipu_plane - > alpha_ch ) ;
ipu_cpmem_set_buffer ( ipu_plane - > alpha_ch , ! active ,
alpha_eba ) ;
ipu_idmac_select_buffer ( ipu_plane - > alpha_ch , ! active ) ;
}
2016-10-18 11:40:25 +02:00
return ;
2016-07-08 17:40:55 +08:00
}
2013-10-10 16:18:45 +02:00
2016-07-08 17:40:55 +08:00
switch ( ipu_plane - > dp_flow ) {
case IPU_DP_FLOW_SYNC_BG :
ipu_dp_setup_channel ( ipu_plane - > dp ,
IPUV3_COLORSPACE_RGB ,
IPUV3_COLORSPACE_RGB ) ;
ipu_dp_set_global_alpha ( ipu_plane - > dp , true , 0 , true ) ;
break ;
case IPU_DP_FLOW_SYNC_FG :
2016-12-14 23:32:55 +02:00
ics = ipu_drm_fourcc_to_colorspace ( state - > fb - > format - > format ) ;
2016-07-08 17:40:55 +08:00
ipu_dp_setup_channel ( ipu_plane - > dp , ics ,
IPUV3_COLORSPACE_UNKNOWN ) ;
/* Enable local alpha on partial plane */
2016-12-14 23:32:55 +02:00
switch ( state - > fb - > format - > format ) {
2016-07-08 17:40:55 +08:00
case DRM_FORMAT_ARGB1555 :
case DRM_FORMAT_ABGR1555 :
case DRM_FORMAT_RGBA5551 :
case DRM_FORMAT_BGRA5551 :
case DRM_FORMAT_ARGB4444 :
case DRM_FORMAT_ARGB8888 :
case DRM_FORMAT_ABGR8888 :
case DRM_FORMAT_RGBA8888 :
case DRM_FORMAT_BGRA8888 :
2016-07-22 12:02:45 +02:00
case DRM_FORMAT_RGB565_A8 :
case DRM_FORMAT_BGR565_A8 :
case DRM_FORMAT_RGB888_A8 :
case DRM_FORMAT_BGR888_A8 :
case DRM_FORMAT_RGBX8888_A8 :
case DRM_FORMAT_BGRX8888_A8 :
2016-07-08 17:40:55 +08:00
ipu_dp_set_global_alpha ( ipu_plane - > dp , false , 0 , false ) ;
break ;
default :
2016-10-18 17:09:30 +02:00
ipu_dp_set_global_alpha ( ipu_plane - > dp , true , 0 , true ) ;
2016-07-08 17:40:55 +08:00
break ;
}
}
2016-10-20 15:37:52 +02:00
ipu_dmfc_config_wait4eot ( ipu_plane - > dmfc , drm_rect_width ( dst ) ) ;
2016-07-08 17:40:55 +08:00
ipu_cpmem_zero ( ipu_plane - > ipu_ch ) ;
2016-10-19 10:50:26 +02:00
ipu_cpmem_set_resolution ( ipu_plane - > ipu_ch ,
drm_rect_width ( & state - > src ) > > 16 ,
drm_rect_height ( & state - > src ) > > 16 ) ;
2016-12-14 23:32:55 +02:00
ipu_cpmem_set_fmt ( ipu_plane - > ipu_ch , state - > fb - > format - > format ) ;
2016-07-08 17:40:55 +08:00
ipu_cpmem_set_high_priority ( ipu_plane - > ipu_ch ) ;
ipu_idmac_set_double_buffer ( ipu_plane - > ipu_ch , 1 ) ;
ipu_cpmem_set_stride ( ipu_plane - > ipu_ch , state - > fb - > pitches [ 0 ] ) ;
2017-03-08 12:13:21 +01:00
ipu_cpmem_set_axi_id ( ipu_plane - > ipu_ch , axi_id ) ;
2016-12-14 23:32:55 +02:00
switch ( fb - > format - > format ) {
2016-10-18 11:40:25 +02:00
case DRM_FORMAT_YUV420 :
case DRM_FORMAT_YVU420 :
2016-10-18 12:31:40 +02:00
case DRM_FORMAT_YUV422 :
case DRM_FORMAT_YVU422 :
case DRM_FORMAT_YUV444 :
case DRM_FORMAT_YVU444 :
2016-10-18 11:40:25 +02:00
ubo = drm_plane_state_to_ubo ( state ) ;
vbo = drm_plane_state_to_vbo ( state ) ;
2016-12-14 23:32:55 +02:00
if ( fb - > format - > format = = DRM_FORMAT_YVU420 | |
fb - > format - > format = = DRM_FORMAT_YVU422 | |
fb - > format - > format = = DRM_FORMAT_YVU444 )
2016-10-18 12:31:40 +02:00
swap ( ubo , vbo ) ;
2016-10-18 11:40:25 +02:00
2016-10-18 12:31:40 +02:00
ipu_cpmem_set_yuv_planar_full ( ipu_plane - > ipu_ch ,
fb - > pitches [ 1 ] , ubo , vbo ) ;
2016-10-18 11:40:25 +02:00
dev_dbg ( ipu_plane - > base . dev - > dev ,
" phy = %lu %lu %lu, x = %d, y = %d " , eba , ubo , vbo ,
2016-10-19 10:50:26 +02:00
state - > src . x1 > > 16 , state - > src . y1 > > 16 ) ;
2016-10-18 11:40:25 +02:00
break ;
2016-10-18 12:31:40 +02:00
case DRM_FORMAT_NV12 :
case DRM_FORMAT_NV16 :
ubo = drm_plane_state_to_ubo ( state ) ;
ipu_cpmem_set_yuv_planar_full ( ipu_plane - > ipu_ch ,
fb - > pitches [ 1 ] , ubo , ubo ) ;
dev_dbg ( ipu_plane - > base . dev - > dev ,
" phy = %lu %lu, x = %d, y = %d " , eba , ubo ,
2016-10-19 10:50:26 +02:00
state - > src . x1 > > 16 , state - > src . y1 > > 16 ) ;
2016-10-18 12:31:40 +02:00
break ;
2016-07-22 12:02:45 +02:00
case DRM_FORMAT_RGB565_A8 :
case DRM_FORMAT_BGR565_A8 :
case DRM_FORMAT_RGB888_A8 :
case DRM_FORMAT_BGR888_A8 :
case DRM_FORMAT_RGBX8888_A8 :
case DRM_FORMAT_BGRX8888_A8 :
alpha_eba = drm_plane_state_to_eba ( state , 1 ) ;
dev_dbg ( ipu_plane - > base . dev - > dev , " phys = %lu %lu, x = %d, y = %d " ,
eba , alpha_eba , state - > src . x1 > > 16 , state - > src . y1 > > 16 ) ;
ipu_cpmem_set_burstsize ( ipu_plane - > ipu_ch , 16 ) ;
ipu_cpmem_zero ( ipu_plane - > alpha_ch ) ;
ipu_cpmem_set_resolution ( ipu_plane - > alpha_ch ,
drm_rect_width ( & state - > src ) > > 16 ,
drm_rect_height ( & state - > src ) > > 16 ) ;
ipu_cpmem_set_format_passthrough ( ipu_plane - > alpha_ch , 8 ) ;
ipu_cpmem_set_high_priority ( ipu_plane - > alpha_ch ) ;
ipu_idmac_set_double_buffer ( ipu_plane - > alpha_ch , 1 ) ;
ipu_cpmem_set_stride ( ipu_plane - > alpha_ch ,
state - > fb - > pitches [ 1 ] ) ;
ipu_cpmem_set_burstsize ( ipu_plane - > alpha_ch , 16 ) ;
ipu_cpmem_set_buffer ( ipu_plane - > alpha_ch , 0 , alpha_eba ) ;
ipu_cpmem_set_buffer ( ipu_plane - > alpha_ch , 1 , alpha_eba ) ;
break ;
2016-10-18 11:40:25 +02:00
default :
dev_dbg ( ipu_plane - > base . dev - > dev , " phys = %lu, x = %d, y = %d " ,
2016-10-19 10:50:26 +02:00
eba , state - > src . x1 > > 16 , state - > src . y1 > > 16 ) ;
2016-10-18 11:40:25 +02:00
break ;
}
ipu_cpmem_set_buffer ( ipu_plane - > ipu_ch , 0 , eba ) ;
ipu_cpmem_set_buffer ( ipu_plane - > ipu_ch , 1 , eba ) ;
2016-07-08 17:40:55 +08:00
ipu_plane_enable ( ipu_plane ) ;
2013-10-10 16:18:45 +02:00
}
2016-07-08 17:40:55 +08:00
static const struct drm_plane_helper_funcs ipu_plane_helper_funcs = {
2016-11-14 11:07:32 +01:00
. prepare_fb = drm_fb_cma_prepare_fb ,
2016-07-08 17:40:55 +08:00
. atomic_check = ipu_plane_atomic_check ,
. atomic_disable = ipu_plane_atomic_disable ,
. atomic_update = ipu_plane_atomic_update ,
2013-10-10 16:18:45 +02:00
} ;
2017-03-08 12:13:21 +01:00
int ipu_planes_assign_pre ( struct drm_device * dev ,
struct drm_atomic_state * state )
{
struct drm_plane_state * plane_state ;
struct drm_plane * plane ;
int available_pres = ipu_prg_max_active_channels ( ) ;
int i ;
for_each_plane_in_state ( state , plane , plane_state , i ) {
struct ipu_plane_state * ipu_state =
to_ipu_plane_state ( plane_state ) ;
struct ipu_plane * ipu_plane = to_ipu_plane ( plane ) ;
if ( ipu_prg_present ( ipu_plane - > ipu ) & & available_pres & &
plane_state - > fb & &
ipu_prg_format_supported ( ipu_plane - > ipu ,
plane_state - > fb - > format - > format ,
plane_state - > fb - > modifier ) ) {
ipu_state - > use_pre = true ;
available_pres - - ;
} else {
ipu_state - > use_pre = false ;
}
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( ipu_planes_assign_pre ) ;
2013-10-10 16:18:45 +02:00
struct ipu_plane * ipu_plane_init ( struct drm_device * dev , struct ipu_soc * ipu ,
int dma , int dp , unsigned int possible_crtcs ,
2015-11-06 11:08:02 +01:00
enum drm_plane_type type )
2013-10-10 16:18:45 +02:00
{
struct ipu_plane * ipu_plane ;
int ret ;
DRM_DEBUG_KMS ( " channel %d, dp flow %d, possible_crtcs=0x%x \n " ,
dma , dp , possible_crtcs ) ;
ipu_plane = kzalloc ( sizeof ( * ipu_plane ) , GFP_KERNEL ) ;
if ( ! ipu_plane ) {
DRM_ERROR ( " failed to allocate plane \n " ) ;
return ERR_PTR ( - ENOMEM ) ;
}
ipu_plane - > ipu = ipu ;
ipu_plane - > dma = dma ;
ipu_plane - > dp_flow = dp ;
2015-11-06 11:08:02 +01:00
ret = drm_universal_plane_init ( dev , & ipu_plane - > base , possible_crtcs ,
& ipu_plane_funcs , ipu_plane_formats ,
drm: Pass 'name' to drm_universal_plane_init()
Done with coccinelle for the most part. It choked on
msm/mdp/mdp5/mdp5_plane.c like so:
"BAD:!!!!! enum drm_plane_type type;"
No idea how to deal with that, so I just fixed that up
by hand.
Also it thinks '...' is part of the semantic patch, so I put an
'int DOTDOTDOT' placeholder in its place and got rid of it with
sed afterwards.
I didn't convert drm_plane_init() since passing the varargs through
would mean either cpp macros or va_list, and I figured we don't
care about these legacy functions enough to warrant the extra pain.
@@
typedef uint32_t;
identifier dev, plane, possible_crtcs, funcs, formats, format_count, type;
@@
int drm_universal_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats,
unsigned int format_count,
enum drm_plane_type type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, plane, possible_crtcs, funcs, formats, format_count, type;
@@
int drm_universal_plane_init(struct drm_device *dev,
struct drm_plane *plane,
unsigned long possible_crtcs,
const struct drm_plane_funcs *funcs,
const uint32_t *formats,
unsigned int format_count,
enum drm_plane_type type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4, E5, E6, E7;
@@
drm_universal_plane_init(E1, E2, E3, E4, E5, E6, E7
+ ,NULL
)
v2: Split crtc and plane changes apart
Pass NUL for no-name instead of ""
Leave drm_plane_init() alone
v3: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670795-2853-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:19:55 +02:00
ARRAY_SIZE ( ipu_plane_formats ) , type ,
NULL ) ;
2013-10-10 16:18:45 +02:00
if ( ret ) {
DRM_ERROR ( " failed to initialize plane \n " ) ;
kfree ( ipu_plane ) ;
return ERR_PTR ( ret ) ;
}
2016-07-08 17:40:55 +08:00
drm_plane_helper_add ( & ipu_plane - > base , & ipu_plane_helper_funcs ) ;
2013-10-10 16:18:45 +02:00
return ipu_plane ;
}