2014-07-30 18:48:35 +02:00
/*
* Copyright ( C ) STMicroelectronics SA 2014
* Authors : Benjamin Gaignard < benjamin . gaignard @ st . com >
* Fabien Dessenne < fabien . dessenne @ st . com >
* for STMicroelectronics .
* License terms : GNU General Public License ( GPL ) , version 2
*/
2016-02-10 10:48:20 +01:00
# include <drm/drm_atomic.h>
2015-08-03 14:22:16 +02:00
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_gem_cma_helper.h>
2014-07-30 19:28:27 +02:00
# include "sti_compositor.h"
2014-07-30 18:48:35 +02:00
# include "sti_gdp.h"
2015-07-31 11:32:34 +02:00
# include "sti_plane.h"
2014-07-30 18:48:35 +02:00
# include "sti_vtg.h"
2015-02-02 15:08:45 +01:00
# define ALPHASWITCH BIT(6)
2014-07-30 18:48:35 +02:00
# define ENA_COLOR_FILL BIT(8)
2015-02-02 15:08:45 +01:00
# define BIGNOTLITTLE BIT(23)
2014-07-30 18:48:35 +02:00
# define WAIT_NEXT_VSYNC BIT(31)
/* GDP color formats */
# define GDP_RGB565 0x00
# define GDP_RGB888 0x01
# define GDP_RGB888_32 0x02
2015-02-04 18:12:53 +01:00
# define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
2014-07-30 18:48:35 +02:00
# define GDP_ARGB8565 0x04
# define GDP_ARGB8888 0x05
2015-08-03 14:22:16 +02:00
# define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
2014-07-30 18:48:35 +02:00
# define GDP_ARGB1555 0x06
# define GDP_ARGB4444 0x07
# define GAM_GDP_CTL_OFFSET 0x00
# define GAM_GDP_AGC_OFFSET 0x04
# define GAM_GDP_VPO_OFFSET 0x0C
# define GAM_GDP_VPS_OFFSET 0x10
# define GAM_GDP_PML_OFFSET 0x14
# define GAM_GDP_PMP_OFFSET 0x18
# define GAM_GDP_SIZE_OFFSET 0x1C
# define GAM_GDP_NVN_OFFSET 0x24
# define GAM_GDP_KEY1_OFFSET 0x28
# define GAM_GDP_KEY2_OFFSET 0x2C
# define GAM_GDP_PPT_OFFSET 0x34
# define GAM_GDP_CML_OFFSET 0x3C
# define GAM_GDP_MST_OFFSET 0x68
# define GAM_GDP_ALPHARANGE_255 BIT(5)
# define GAM_GDP_AGC_FULL_RANGE 0x00808080
# define GAM_GDP_PPT_IGNORE (BIT(1) | BIT(0))
# define GAM_GDP_SIZE_MAX 0x7FF
2015-08-03 14:22:16 +02:00
# define GDP_NODE_NB_BANK 2
# define GDP_NODE_PER_FIELD 2
2014-07-30 18:48:35 +02:00
struct sti_gdp_node {
u32 gam_gdp_ctl ;
u32 gam_gdp_agc ;
u32 reserved1 ;
u32 gam_gdp_vpo ;
u32 gam_gdp_vps ;
u32 gam_gdp_pml ;
u32 gam_gdp_pmp ;
u32 gam_gdp_size ;
u32 reserved2 ;
u32 gam_gdp_nvn ;
u32 gam_gdp_key1 ;
u32 gam_gdp_key2 ;
u32 reserved3 ;
u32 gam_gdp_ppt ;
u32 reserved4 ;
u32 gam_gdp_cml ;
} ;
struct sti_gdp_node_list {
struct sti_gdp_node * top_field ;
2014-12-04 11:21:48 +01:00
dma_addr_t top_field_paddr ;
2014-07-30 18:48:35 +02:00
struct sti_gdp_node * btm_field ;
2014-12-04 11:21:48 +01:00
dma_addr_t btm_field_paddr ;
2014-07-30 18:48:35 +02:00
} ;
/**
* STI GDP structure
*
2015-07-31 11:32:13 +02:00
* @ sti_plane : sti_plane structure
* @ dev : driver device
* @ regs : gdp registers
2014-07-30 18:48:35 +02:00
* @ clk_pix : pixel clock for the current gdp
2014-12-08 17:32:36 +01:00
* @ clk_main_parent : gdp parent clock if main path used
* @ clk_aux_parent : gdp parent clock if aux path used
2014-07-30 18:48:35 +02:00
* @ vtg_field_nb : callback for VTG FIELD ( top or bottom ) notification
* @ is_curr_top : true if the current node processed is the top field
2015-07-31 11:32:13 +02:00
* @ node_list : array of node list
2016-01-07 14:30:37 +01:00
* @ vtg : registered vtg
2014-07-30 18:48:35 +02:00
*/
struct sti_gdp {
2015-07-31 11:32:13 +02:00
struct sti_plane plane ;
struct device * dev ;
void __iomem * regs ;
2014-07-30 18:48:35 +02:00
struct clk * clk_pix ;
2014-12-08 17:32:36 +01:00
struct clk * clk_main_parent ;
struct clk * clk_aux_parent ;
2014-07-30 18:48:35 +02:00
struct notifier_block vtg_field_nb ;
bool is_curr_top ;
struct sti_gdp_node_list node_list [ GDP_NODE_NB_BANK ] ;
2016-01-07 14:30:37 +01:00
struct sti_vtg * vtg ;
2014-07-30 18:48:35 +02:00
} ;
2015-07-31 11:32:13 +02:00
# define to_sti_gdp(x) container_of(x, struct sti_gdp, plane)
2014-07-30 18:48:35 +02:00
static const uint32_t gdp_supported_formats [ ] = {
DRM_FORMAT_XRGB8888 ,
2015-02-04 18:12:53 +01:00
DRM_FORMAT_XBGR8888 ,
2014-07-30 18:48:35 +02:00
DRM_FORMAT_ARGB8888 ,
2015-02-02 15:08:45 +01:00
DRM_FORMAT_ABGR8888 ,
2014-07-30 18:48:35 +02:00
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_RGB888 ,
} ;
static int sti_gdp_fourcc2format ( int fourcc )
{
switch ( fourcc ) {
case DRM_FORMAT_XRGB8888 :
return GDP_RGB888_32 ;
2015-02-04 18:12:53 +01:00
case DRM_FORMAT_XBGR8888 :
return GDP_XBGR8888 ;
2014-07-30 18:48:35 +02:00
case DRM_FORMAT_ARGB8888 :
return GDP_ARGB8888 ;
2015-02-02 15:08:45 +01:00
case DRM_FORMAT_ABGR8888 :
return GDP_ABGR8888 ;
2014-07-30 18:48:35 +02:00
case DRM_FORMAT_ARGB4444 :
return GDP_ARGB4444 ;
case DRM_FORMAT_ARGB1555 :
return GDP_ARGB1555 ;
case DRM_FORMAT_RGB565 :
return GDP_RGB565 ;
case DRM_FORMAT_RGB888 :
return GDP_RGB888 ;
}
return - 1 ;
}
static int sti_gdp_get_alpharange ( int format )
{
switch ( format ) {
case GDP_ARGB8565 :
case GDP_ARGB8888 :
2015-02-02 15:08:45 +01:00
case GDP_ABGR8888 :
2014-07-30 18:48:35 +02:00
return GAM_GDP_ALPHARANGE_255 ;
}
return 0 ;
}
/**
* sti_gdp_get_free_nodes
2015-08-03 14:22:16 +02:00
* @ gdp : gdp pointer
2014-07-30 18:48:35 +02:00
*
* Look for a GDP node list that is not currently read by the HW .
*
* RETURNS :
* Pointer to the free GDP node list
*/
2015-08-03 14:22:16 +02:00
static struct sti_gdp_node_list * sti_gdp_get_free_nodes ( struct sti_gdp * gdp )
2014-07-30 18:48:35 +02:00
{
int hw_nvn ;
unsigned int i ;
2015-07-31 11:32:13 +02:00
hw_nvn = readl ( gdp - > regs + GAM_GDP_NVN_OFFSET ) ;
2014-07-30 18:48:35 +02:00
if ( ! hw_nvn )
goto end ;
for ( i = 0 ; i < GDP_NODE_NB_BANK ; i + + )
2014-12-04 11:21:48 +01:00
if ( ( hw_nvn ! = gdp - > node_list [ i ] . btm_field_paddr ) & &
( hw_nvn ! = gdp - > node_list [ i ] . top_field_paddr ) )
2014-07-30 18:48:35 +02:00
return & gdp - > node_list [ i ] ;
2014-07-30 19:28:27 +02:00
/* in hazardious cases restart with the first node */
DRM_ERROR ( " inconsistent NVN for %s: 0x%08X \n " ,
2015-08-03 14:22:16 +02:00
sti_plane_to_str ( & gdp - > plane ) , hw_nvn ) ;
2014-07-30 19:28:27 +02:00
2014-07-30 18:48:35 +02:00
end :
return & gdp - > node_list [ 0 ] ;
}
/**
* sti_gdp_get_current_nodes
2015-08-03 14:22:16 +02:00
* @ gdp : gdp pointer
2014-07-30 18:48:35 +02:00
*
* Look for GDP nodes that are currently read by the HW .
*
* RETURNS :
* Pointer to the current GDP node list
*/
static
2015-08-03 14:22:16 +02:00
struct sti_gdp_node_list * sti_gdp_get_current_nodes ( struct sti_gdp * gdp )
2014-07-30 18:48:35 +02:00
{
int hw_nvn ;
unsigned int i ;
2015-07-31 11:32:13 +02:00
hw_nvn = readl ( gdp - > regs + GAM_GDP_NVN_OFFSET ) ;
2014-07-30 18:48:35 +02:00
if ( ! hw_nvn )
goto end ;
for ( i = 0 ; i < GDP_NODE_NB_BANK ; i + + )
2014-12-04 11:21:48 +01:00
if ( ( hw_nvn = = gdp - > node_list [ i ] . btm_field_paddr ) | |
( hw_nvn = = gdp - > node_list [ i ] . top_field_paddr ) )
2014-07-30 18:48:35 +02:00
return & gdp - > node_list [ i ] ;
end :
2014-07-30 19:28:27 +02:00
DRM_DEBUG_DRIVER ( " Warning, NVN 0x%08X for %s does not match any node \n " ,
2015-08-03 14:22:16 +02:00
hw_nvn , sti_plane_to_str ( & gdp - > plane ) ) ;
2014-07-30 19:28:27 +02:00
2014-07-30 18:48:35 +02:00
return NULL ;
}
/**
2015-07-31 11:32:13 +02:00
* sti_gdp_disable
2015-08-03 14:22:16 +02:00
* @ gdp : gdp pointer
2014-07-30 18:48:35 +02:00
*
* Disable a GDP .
*/
2015-08-03 14:22:16 +02:00
static void sti_gdp_disable ( struct sti_gdp * gdp )
2014-07-30 18:48:35 +02:00
{
2015-08-03 14:22:16 +02:00
unsigned int i ;
2014-07-30 19:28:27 +02:00
2015-08-03 14:22:16 +02:00
DRM_DEBUG_DRIVER ( " %s \n " , sti_plane_to_str ( & gdp - > plane ) ) ;
2014-07-30 18:48:35 +02:00
/* Set the nodes as 'to be ignored on mixer' */
for ( i = 0 ; i < GDP_NODE_NB_BANK ; i + + ) {
gdp - > node_list [ i ] . top_field - > gam_gdp_ppt | = GAM_GDP_PPT_IGNORE ;
gdp - > node_list [ i ] . btm_field - > gam_gdp_ppt | = GAM_GDP_PPT_IGNORE ;
}
2016-01-07 14:30:37 +01:00
if ( sti_vtg_unregister_client ( gdp - > vtg , & gdp - > vtg_field_nb ) )
2014-07-30 19:28:27 +02:00
DRM_DEBUG_DRIVER ( " Warning: cannot unregister VTG notifier \n " ) ;
2014-07-30 18:48:35 +02:00
if ( gdp - > clk_pix )
clk_disable_unprepare ( gdp - > clk_pix ) ;
2015-08-03 14:22:16 +02:00
gdp - > plane . status = STI_PLANE_DISABLED ;
2014-07-30 18:48:35 +02:00
}
/**
* sti_gdp_field_cb
* @ nb : notifier block
* @ event : event message
* @ data : private data
*
* Handle VTG top field and bottom field event .
*
* RETURNS :
* 0 on success .
*/
int sti_gdp_field_cb ( struct notifier_block * nb ,
unsigned long event , void * data )
{
struct sti_gdp * gdp = container_of ( nb , struct sti_gdp , vtg_field_nb ) ;
2015-08-03 14:22:16 +02:00
if ( gdp - > plane . status = = STI_PLANE_FLUSHING ) {
/* disable need to be synchronize on vsync event */
DRM_DEBUG_DRIVER ( " Vsync event received => disable %s \n " ,
sti_plane_to_str ( & gdp - > plane ) ) ;
sti_gdp_disable ( gdp ) ;
}
2014-07-30 18:48:35 +02:00
switch ( event ) {
case VTG_TOP_FIELD_EVENT :
gdp - > is_curr_top = true ;
break ;
case VTG_BOTTOM_FIELD_EVENT :
gdp - > is_curr_top = false ;
break ;
default :
DRM_ERROR ( " unsupported event: %lu \n " , event ) ;
break ;
}
return 0 ;
}
2015-07-31 11:32:13 +02:00
static void sti_gdp_init ( struct sti_gdp * gdp )
2014-07-30 18:48:35 +02:00
{
2015-07-31 11:32:13 +02:00
struct device_node * np = gdp - > dev - > of_node ;
2014-12-04 11:21:48 +01:00
dma_addr_t dma_addr ;
2014-07-30 18:48:35 +02:00
void * base ;
unsigned int i , size ;
/* Allocate all the nodes within a single memory page */
size = sizeof ( struct sti_gdp_node ) *
GDP_NODE_PER_FIELD * GDP_NODE_NB_BANK ;
2015-07-31 11:32:13 +02:00
base = dma_alloc_writecombine ( gdp - > dev ,
size , & dma_addr , GFP_KERNEL | GFP_DMA ) ;
2014-12-04 11:21:48 +01:00
2014-07-30 18:48:35 +02:00
if ( ! base ) {
DRM_ERROR ( " Failed to allocate memory for GDP node \n " ) ;
return ;
}
memset ( base , 0 , size ) ;
for ( i = 0 ; i < GDP_NODE_NB_BANK ; i + + ) {
2014-12-04 11:21:48 +01:00
if ( dma_addr & 0xF ) {
2014-07-30 18:48:35 +02:00
DRM_ERROR ( " Mem alignment failed \n " ) ;
return ;
}
gdp - > node_list [ i ] . top_field = base ;
2014-12-04 11:21:48 +01:00
gdp - > node_list [ i ] . top_field_paddr = dma_addr ;
2014-07-30 18:48:35 +02:00
DRM_DEBUG_DRIVER ( " node[%d].top_field=%p \n " , i , base ) ;
base + = sizeof ( struct sti_gdp_node ) ;
2014-12-04 11:21:48 +01:00
dma_addr + = sizeof ( struct sti_gdp_node ) ;
2014-07-30 18:48:35 +02:00
2014-12-04 11:21:48 +01:00
if ( dma_addr & 0xF ) {
2014-07-30 18:48:35 +02:00
DRM_ERROR ( " Mem alignment failed \n " ) ;
return ;
}
gdp - > node_list [ i ] . btm_field = base ;
2014-12-04 11:21:48 +01:00
gdp - > node_list [ i ] . btm_field_paddr = dma_addr ;
2014-07-30 18:48:35 +02:00
DRM_DEBUG_DRIVER ( " node[%d].btm_field=%p \n " , i , base ) ;
base + = sizeof ( struct sti_gdp_node ) ;
2014-12-04 11:21:48 +01:00
dma_addr + = sizeof ( struct sti_gdp_node ) ;
2014-07-30 18:48:35 +02:00
}
if ( of_device_is_compatible ( np , " st,stih407-compositor " ) ) {
/* GDP of STiH407 chip have its own pixel clock */
char * clk_name ;
2015-07-31 11:32:13 +02:00
switch ( gdp - > plane . desc ) {
2014-07-30 18:48:35 +02:00
case STI_GDP_0 :
clk_name = " pix_gdp1 " ;
break ;
case STI_GDP_1 :
clk_name = " pix_gdp2 " ;
break ;
case STI_GDP_2 :
clk_name = " pix_gdp3 " ;
break ;
case STI_GDP_3 :
clk_name = " pix_gdp4 " ;
break ;
default :
DRM_ERROR ( " GDP id not recognized \n " ) ;
return ;
}
2015-07-31 11:32:13 +02:00
gdp - > clk_pix = devm_clk_get ( gdp - > dev , clk_name ) ;
2014-07-30 18:48:35 +02:00
if ( IS_ERR ( gdp - > clk_pix ) )
DRM_ERROR ( " Cannot get %s clock \n " , clk_name ) ;
2014-12-08 17:32:36 +01:00
2015-07-31 11:32:13 +02:00
gdp - > clk_main_parent = devm_clk_get ( gdp - > dev , " main_parent " ) ;
2014-12-08 17:32:36 +01:00
if ( IS_ERR ( gdp - > clk_main_parent ) )
DRM_ERROR ( " Cannot get main_parent clock \n " ) ;
2015-07-31 11:32:13 +02:00
gdp - > clk_aux_parent = devm_clk_get ( gdp - > dev , " aux_parent " ) ;
2014-12-08 17:32:36 +01:00
if ( IS_ERR ( gdp - > clk_aux_parent ) )
DRM_ERROR ( " Cannot get aux_parent clock \n " ) ;
2014-07-30 18:48:35 +02:00
}
}
2016-01-22 16:17:36 +01:00
/**
* sti_gdp_get_dst
* @ dev : device
* @ dst : requested destination size
* @ src : source size
*
* Return the cropped / clamped destination size
*
* RETURNS :
* cropped / clamped destination size
*/
static int sti_gdp_get_dst ( struct device * dev , int dst , int src )
{
if ( dst = = src )
return dst ;
if ( dst < src ) {
dev_dbg ( dev , " WARNING: GDP scale not supported, will crop \n " ) ;
return dst ;
}
dev_dbg ( dev , " WARNING: GDP scale not supported, will clamp \n " ) ;
return src ;
}
2016-02-10 10:48:20 +01:00
static int sti_gdp_atomic_check ( struct drm_plane * drm_plane ,
struct drm_plane_state * state )
2015-08-03 14:22:16 +02:00
{
struct sti_plane * plane = to_sti_plane ( drm_plane ) ;
struct sti_gdp * gdp = to_sti_gdp ( plane ) ;
struct drm_crtc * crtc = state - > crtc ;
struct sti_compositor * compo = dev_get_drvdata ( gdp - > dev ) ;
struct drm_framebuffer * fb = state - > fb ;
bool first_prepare = plane - > status = = STI_PLANE_DISABLED ? true : false ;
2016-02-10 10:48:20 +01:00
struct drm_crtc_state * crtc_state ;
2015-08-03 14:22:16 +02:00
struct sti_mixer * mixer ;
struct drm_display_mode * mode ;
int dst_x , dst_y , dst_w , dst_h ;
int src_x , src_y , src_w , src_h ;
2016-02-10 10:48:20 +01:00
int format ;
/* no need for further checks if the plane is being disabled */
if ( ! crtc | | ! fb )
return 0 ;
mixer = to_sti_mixer ( crtc ) ;
crtc_state = drm_atomic_get_crtc_state ( state - > state , crtc ) ;
mode = & crtc_state - > mode ;
dst_x = state - > crtc_x ;
dst_y = state - > crtc_y ;
dst_w = clamp_val ( state - > crtc_w , 0 , mode - > crtc_hdisplay - dst_x ) ;
dst_h = clamp_val ( state - > crtc_h , 0 , mode - > crtc_vdisplay - dst_y ) ;
/* src_x are in 16.16 format */
src_x = state - > src_x > > 16 ;
src_y = state - > src_y > > 16 ;
src_w = clamp_val ( state - > src_w > > 16 , 0 , GAM_GDP_SIZE_MAX ) ;
src_h = clamp_val ( state - > src_h > > 16 , 0 , GAM_GDP_SIZE_MAX ) ;
format = sti_gdp_fourcc2format ( fb - > pixel_format ) ;
if ( format = = - 1 ) {
DRM_ERROR ( " Format not supported by GDP %.4s \n " ,
( char * ) & fb - > pixel_format ) ;
return - EINVAL ;
}
if ( ! drm_fb_cma_get_gem_obj ( fb , 0 ) ) {
DRM_ERROR ( " Can't get CMA GEM object for fb \n " ) ;
return - EINVAL ;
}
if ( first_prepare ) {
/* Register gdp callback */
gdp - > vtg = mixer - > id = = STI_MIXER_MAIN ?
compo - > vtg_main : compo - > vtg_aux ;
if ( sti_vtg_register_client ( gdp - > vtg ,
& gdp - > vtg_field_nb , crtc ) ) {
DRM_ERROR ( " Cannot register VTG notifier \n " ) ;
return - EINVAL ;
}
/* Set and enable gdp clock */
if ( gdp - > clk_pix ) {
struct clk * clkp ;
int rate = mode - > clock * 1000 ;
int res ;
/*
* According to the mixer used , the gdp pixel clock
* should have a different parent clock .
*/
if ( mixer - > id = = STI_MIXER_MAIN )
clkp = gdp - > clk_main_parent ;
else
clkp = gdp - > clk_aux_parent ;
if ( clkp )
clk_set_parent ( gdp - > clk_pix , clkp ) ;
res = clk_set_rate ( gdp - > clk_pix , rate ) ;
if ( res < 0 ) {
DRM_ERROR ( " Cannot set rate (%dHz) for gdp \n " ,
rate ) ;
return - EINVAL ;
}
if ( clk_prepare_enable ( gdp - > clk_pix ) ) {
DRM_ERROR ( " Failed to prepare/enable gdp \n " ) ;
return - EINVAL ;
}
}
}
DRM_DEBUG_KMS ( " CRTC:%d (%s) drm plane:%d (%s) \n " ,
crtc - > base . id , sti_mixer_to_str ( mixer ) ,
drm_plane - > base . id , sti_plane_to_str ( plane ) ) ;
DRM_DEBUG_KMS ( " %s dst=(%dx%d)@(%d,%d) - src=(%dx%d)@(%d,%d) \n " ,
sti_plane_to_str ( plane ) ,
dst_w , dst_h , dst_x , dst_y ,
src_w , src_h , src_x , src_y ) ;
return 0 ;
}
static void sti_gdp_atomic_update ( struct drm_plane * drm_plane ,
struct drm_plane_state * oldstate )
{
struct drm_plane_state * state = drm_plane - > state ;
struct sti_plane * plane = to_sti_plane ( drm_plane ) ;
struct sti_gdp * gdp = to_sti_gdp ( plane ) ;
struct drm_crtc * crtc = state - > crtc ;
struct drm_framebuffer * fb = state - > fb ;
struct drm_display_mode * mode ;
int dst_x , dst_y , dst_w , dst_h ;
int src_x , src_y , src_w , src_h ;
2015-08-03 14:22:16 +02:00
struct drm_gem_cma_object * cma_obj ;
struct sti_gdp_node_list * list ;
struct sti_gdp_node_list * curr_list ;
struct sti_gdp_node * top_field , * btm_field ;
u32 dma_updated_top ;
u32 dma_updated_btm ;
int format ;
unsigned int depth , bpp ;
u32 ydo , xdo , yds , xds ;
2016-02-10 10:48:20 +01:00
if ( ! crtc | | ! fb )
2015-08-03 14:22:16 +02:00
return ;
mode = & crtc - > mode ;
dst_x = state - > crtc_x ;
dst_y = state - > crtc_y ;
dst_w = clamp_val ( state - > crtc_w , 0 , mode - > crtc_hdisplay - dst_x ) ;
dst_h = clamp_val ( state - > crtc_h , 0 , mode - > crtc_vdisplay - dst_y ) ;
/* src_x are in 16.16 format */
src_x = state - > src_x > > 16 ;
src_y = state - > src_y > > 16 ;
2016-01-22 16:17:36 +01:00
src_w = clamp_val ( state - > src_w > > 16 , 0 , GAM_GDP_SIZE_MAX ) ;
src_h = clamp_val ( state - > src_h > > 16 , 0 , GAM_GDP_SIZE_MAX ) ;
2015-08-03 14:22:16 +02:00
list = sti_gdp_get_free_nodes ( gdp ) ;
top_field = list - > top_field ;
btm_field = list - > btm_field ;
dev_dbg ( gdp - > dev , " %s %s top_node:0x%p btm_node:0x%p \n " , __func__ ,
sti_plane_to_str ( plane ) , top_field , btm_field ) ;
/* build the top field */
top_field - > gam_gdp_agc = GAM_GDP_AGC_FULL_RANGE ;
top_field - > gam_gdp_ctl = WAIT_NEXT_VSYNC ;
format = sti_gdp_fourcc2format ( fb - > pixel_format ) ;
top_field - > gam_gdp_ctl | = format ;
top_field - > gam_gdp_ctl | = sti_gdp_get_alpharange ( format ) ;
top_field - > gam_gdp_ppt & = ~ GAM_GDP_PPT_IGNORE ;
cma_obj = drm_fb_cma_get_gem_obj ( fb , 0 ) ;
DRM_DEBUG_DRIVER ( " drm FB:%d format:%.4s phys@:0x%lx \n " , fb - > base . id ,
( char * ) & fb - > pixel_format ,
( unsigned long ) cma_obj - > paddr ) ;
/* pixel memory location */
drm_fb_get_bpp_depth ( fb - > pixel_format , & depth , & bpp ) ;
top_field - > gam_gdp_pml = ( u32 ) cma_obj - > paddr + fb - > offsets [ 0 ] ;
top_field - > gam_gdp_pml + = src_x * ( bpp > > 3 ) ;
top_field - > gam_gdp_pml + = src_y * fb - > pitches [ 0 ] ;
2016-01-22 16:17:36 +01:00
/* output parameters (clamped / cropped) */
dst_w = sti_gdp_get_dst ( gdp - > dev , dst_w , src_w ) ;
dst_h = sti_gdp_get_dst ( gdp - > dev , dst_h , src_h ) ;
2015-08-03 14:22:16 +02:00
ydo = sti_vtg_get_line_number ( * mode , dst_y ) ;
yds = sti_vtg_get_line_number ( * mode , dst_y + dst_h - 1 ) ;
xdo = sti_vtg_get_pixel_number ( * mode , dst_x ) ;
xds = sti_vtg_get_pixel_number ( * mode , dst_x + dst_w - 1 ) ;
top_field - > gam_gdp_vpo = ( ydo < < 16 ) | xdo ;
top_field - > gam_gdp_vps = ( yds < < 16 ) | xds ;
2016-02-09 17:08:56 +01:00
/* input parameters */
src_w = dst_w ;
top_field - > gam_gdp_pmp = fb - > pitches [ 0 ] ;
top_field - > gam_gdp_size = src_h < < 16 | src_w ;
2015-08-03 14:22:16 +02:00
/* Same content and chained together */
memcpy ( btm_field , top_field , sizeof ( * btm_field ) ) ;
top_field - > gam_gdp_nvn = list - > btm_field_paddr ;
btm_field - > gam_gdp_nvn = list - > top_field_paddr ;
/* Interlaced mode */
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE )
btm_field - > gam_gdp_pml = top_field - > gam_gdp_pml +
fb - > pitches [ 0 ] ;
/* Update the NVN field of the 'right' field of the current GDP node
* ( being used by the HW ) with the address of the updated ( ' free ' ) top
* field GDP node .
* - In interlaced mode the ' right ' field is the bottom field as we
* update frames starting from their top field
* - In progressive mode , we update both bottom and top fields which
* are equal nodes .
* At the next VSYNC , the updated node list will be used by the HW .
*/
curr_list = sti_gdp_get_current_nodes ( gdp ) ;
dma_updated_top = list - > top_field_paddr ;
dma_updated_btm = list - > btm_field_paddr ;
dev_dbg ( gdp - > dev , " Current NVN:0x%X \n " ,
readl ( gdp - > regs + GAM_GDP_NVN_OFFSET ) ) ;
dev_dbg ( gdp - > dev , " Posted buff: %lx current buff: %x \n " ,
( unsigned long ) cma_obj - > paddr ,
readl ( gdp - > regs + GAM_GDP_PML_OFFSET ) ) ;
if ( ! curr_list ) {
/* First update or invalid node should directly write in the
* hw register */
DRM_DEBUG_DRIVER ( " %s first update (or invalid node) " ,
sti_plane_to_str ( plane ) ) ;
writel ( gdp - > is_curr_top ?
dma_updated_btm : dma_updated_top ,
gdp - > regs + GAM_GDP_NVN_OFFSET ) ;
goto end ;
}
if ( mode - > flags & DRM_MODE_FLAG_INTERLACE ) {
if ( gdp - > is_curr_top ) {
/* Do not update in the middle of the frame, but
* postpone the update after the bottom field has
* been displayed */
curr_list - > btm_field - > gam_gdp_nvn = dma_updated_top ;
} else {
/* Direct update to avoid one frame delay */
writel ( dma_updated_top ,
gdp - > regs + GAM_GDP_NVN_OFFSET ) ;
}
} else {
/* Direct update for progressive to avoid one frame delay */
writel ( dma_updated_top , gdp - > regs + GAM_GDP_NVN_OFFSET ) ;
}
end :
plane - > status = STI_PLANE_UPDATED ;
}
static void sti_gdp_atomic_disable ( struct drm_plane * drm_plane ,
struct drm_plane_state * oldstate )
{
struct sti_plane * plane = to_sti_plane ( drm_plane ) ;
if ( ! drm_plane - > crtc ) {
DRM_DEBUG_DRIVER ( " drm plane:%d not enabled \n " ,
drm_plane - > base . id ) ;
return ;
}
DRM_DEBUG_DRIVER ( " CRTC:%d (%s) drm plane:%d (%s) \n " ,
2016-02-10 10:48:20 +01:00
drm_plane - > crtc - > base . id ,
sti_mixer_to_str ( to_sti_mixer ( drm_plane - > crtc ) ) ,
2015-08-03 14:22:16 +02:00
drm_plane - > base . id , sti_plane_to_str ( plane ) ) ;
plane - > status = STI_PLANE_DISABLING ;
}
static const struct drm_plane_helper_funcs sti_gdp_helpers_funcs = {
2016-02-10 10:48:20 +01:00
. atomic_check = sti_gdp_atomic_check ,
2015-08-03 14:22:16 +02:00
. atomic_update = sti_gdp_atomic_update ,
. atomic_disable = sti_gdp_atomic_disable ,
2014-07-30 18:48:35 +02:00
} ;
2015-08-03 14:22:16 +02:00
struct drm_plane * sti_gdp_create ( struct drm_device * drm_dev ,
struct device * dev , int desc ,
void __iomem * baseaddr ,
unsigned int possible_crtcs ,
enum drm_plane_type type )
2014-07-30 18:48:35 +02:00
{
struct sti_gdp * gdp ;
2015-08-03 14:22:16 +02:00
int res ;
2014-07-30 18:48:35 +02:00
gdp = devm_kzalloc ( dev , sizeof ( * gdp ) , GFP_KERNEL ) ;
if ( ! gdp ) {
DRM_ERROR ( " Failed to allocate memory for GDP \n " ) ;
return NULL ;
}
2015-07-31 11:32:13 +02:00
gdp - > dev = dev ;
gdp - > regs = baseaddr ;
gdp - > plane . desc = desc ;
2015-08-03 14:22:16 +02:00
gdp - > plane . status = STI_PLANE_DISABLED ;
2015-07-31 11:32:13 +02:00
2014-07-30 18:48:35 +02:00
gdp - > vtg_field_nb . notifier_call = sti_gdp_field_cb ;
2015-07-31 11:32:13 +02:00
sti_gdp_init ( gdp ) ;
2015-08-03 14:22:16 +02:00
res = drm_universal_plane_init ( drm_dev , & gdp - > plane . drm_plane ,
possible_crtcs ,
& sti_plane_helpers_funcs ,
gdp_supported_formats ,
ARRAY_SIZE ( gdp_supported_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
type , NULL ) ;
2015-08-03 14:22:16 +02:00
if ( res ) {
DRM_ERROR ( " Failed to initialize universal plane \n " ) ;
goto err ;
}
drm_plane_helper_add ( & gdp - > plane . drm_plane , & sti_gdp_helpers_funcs ) ;
sti_plane_init_property ( & gdp - > plane , type ) ;
return & gdp - > plane . drm_plane ;
err :
devm_kfree ( dev , gdp ) ;
return NULL ;
2014-07-30 18:48:35 +02:00
}