2012-01-16 12:51:16 -06:00
/*
2013-02-11 12:43:09 -05:00
* drivers / gpu / drm / omapdrm / omap_plane . c
2012-01-16 12:51:16 -06:00
*
* Copyright ( C ) 2011 Texas Instruments
* Author : Rob Clark < rob . clark @ linaro . org >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* 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 .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "omap_drv.h"
2012-08-15 15:18:01 -05:00
# include "omap_dmm_tiler.h"
2012-01-16 12:51:16 -06:00
/* some hackery because omapdss has an 'enum omap_plane' (which would be
* better named omap_plane_id ) . . and compiler seems unhappy about having
* both a ' struct omap_plane ' and ' enum omap_plane '
*/
# define omap_plane _omap_plane
/*
* plane funcs
*/
# define to_omap_plane(x) container_of(x, struct omap_plane, base)
struct omap_plane {
struct drm_plane base ;
2012-12-04 13:59:12 -06:00
int id ; /* TODO rename omap_plane -> omap_plane_id in omapdss so I can use the enum */
const char * name ;
2012-01-16 12:51:16 -06:00
struct omap_overlay_info info ;
2012-08-15 15:18:01 -05:00
/* position/orientation of scanout within the fb: */
struct omap_drm_window win ;
2012-12-04 13:59:12 -06:00
bool enabled ;
2012-01-16 12:51:17 -06:00
/* last fb that we pinned: */
struct drm_framebuffer * pinned_fb ;
2012-01-16 12:51:16 -06:00
2012-03-05 10:48:31 -06:00
uint32_t nformats ;
uint32_t formats [ 32 ] ;
2012-03-05 10:48:35 -06:00
2012-12-04 13:59:12 -06:00
struct omap_drm_irq error_irq ;
2012-03-05 10:48:31 -06:00
} ;
2012-01-16 12:51:16 -06:00
2012-01-16 12:51:17 -06:00
/* update which fb (if any) is pinned for scanout */
2015-01-17 19:09:26 +02:00
static int omap_plane_update_pin ( struct drm_plane * plane )
2012-01-16 12:51:17 -06:00
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2012-03-05 10:48:35 -06:00
struct drm_framebuffer * pinned_fb = omap_plane - > pinned_fb ;
2015-01-17 19:09:26 +02:00
struct drm_framebuffer * fb = omap_plane - > enabled ? plane - > fb : NULL ;
int ret = 0 ;
2012-03-05 10:48:35 -06:00
2015-01-17 19:09:26 +02:00
if ( pinned_fb = = fb )
return 0 ;
2012-03-05 10:48:35 -06:00
2015-01-17 19:09:26 +02:00
DBG ( " %p -> %p " , pinned_fb , fb ) ;
2012-12-04 13:59:12 -06:00
2015-01-17 19:09:26 +02:00
if ( fb ) {
drm_framebuffer_reference ( fb ) ;
ret = omap_framebuffer_pin ( fb ) ;
}
2012-03-05 10:48:35 -06:00
2015-01-17 19:09:26 +02:00
if ( pinned_fb )
omap_crtc_queue_unpin ( plane - > crtc , pinned_fb ) ;
2012-01-16 12:51:17 -06:00
2015-01-17 19:09:26 +02:00
if ( ret ) {
dev_err ( plane - > dev - > dev , " could not swap %p -> %p \n " ,
omap_plane - > pinned_fb , fb ) ;
drm_framebuffer_unreference ( fb ) ;
omap_plane - > pinned_fb = NULL ;
return ret ;
2012-01-16 12:51:17 -06:00
}
2015-01-17 19:09:26 +02:00
omap_plane - > pinned_fb = fb ;
2012-03-05 10:48:35 -06:00
return 0 ;
2012-01-16 12:51:17 -06:00
}
2015-01-17 19:09:26 +02:00
static int omap_plane_setup ( struct omap_plane * omap_plane )
2012-01-16 12:51:16 -06:00
{
2015-01-17 19:09:26 +02:00
struct omap_overlay_info * info = & omap_plane - > info ;
2012-12-04 13:59:12 -06:00
struct drm_plane * plane = & omap_plane - > base ;
struct drm_device * dev = plane - > dev ;
struct drm_crtc * crtc = plane - > crtc ;
2012-01-16 12:51:17 -06:00
int ret ;
2012-01-16 12:51:16 -06:00
2015-01-17 19:09:26 +02:00
DBG ( " %s, enabled=%d " , omap_plane - > name , omap_plane - > enabled ) ;
2012-12-04 13:59:12 -06:00
/* if fb has changed, pin new fb: */
2015-01-17 19:09:26 +02:00
ret = omap_plane_update_pin ( plane ) ;
if ( ret )
return ret ;
2012-12-04 13:59:12 -06:00
2015-01-17 19:09:26 +02:00
dispc_runtime_get ( ) ;
if ( ! omap_plane - > enabled ) {
2012-12-04 13:59:12 -06:00
dispc_ovl_enable ( omap_plane - > id , false ) ;
2015-01-17 19:09:26 +02:00
goto done ;
2012-01-16 12:51:17 -06:00
}
2012-01-16 12:51:16 -06:00
2012-12-04 13:59:12 -06:00
/* update scanout: */
2015-01-17 19:09:26 +02:00
omap_framebuffer_update_scanout ( plane - > fb , & omap_plane - > win , info ) ;
2012-01-16 12:51:16 -06:00
2012-12-04 13:59:12 -06:00
DBG ( " %dx%d -> %dx%d (%d) " , info - > width , info - > height ,
info - > out_width , info - > out_height ,
2012-01-16 12:51:17 -06:00
info - > screen_width ) ;
2014-07-12 10:53:41 +01:00
DBG ( " %d,%d %pad %pad " , info - > pos_x , info - > pos_y ,
& info - > paddr , & info - > p_uv_addr ) ;
2012-12-04 13:59:12 -06:00
2015-01-17 19:09:26 +02:00
dispc_ovl_set_channel_out ( omap_plane - > id ,
omap_crtc_channel ( crtc ) ) ;
2014-10-03 15:14:08 +00:00
2012-12-04 13:59:12 -06:00
/* and finally, update omapdss: */
2015-01-12 16:44:03 +02:00
ret = dispc_ovl_setup ( omap_plane - > id , info , false ,
omap_crtc_timings ( crtc ) , false ) ;
2012-12-04 13:59:12 -06:00
if ( ret ) {
dev_err ( dev - > dev , " dispc_ovl_setup failed: %d \n " , ret ) ;
2015-01-17 19:09:26 +02:00
goto done ;
2012-12-04 13:59:12 -06:00
}
dispc_ovl_enable ( omap_plane - > id , true ) ;
2015-01-17 19:09:26 +02:00
done :
dispc_runtime_put ( ) ;
return ret ;
2012-01-16 12:51:16 -06:00
}
2012-01-16 12:51:18 -06:00
int omap_plane_mode_set ( struct drm_plane * plane ,
2015-01-17 22:31:42 +02:00
struct drm_crtc * crtc , struct drm_framebuffer * fb ,
int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
unsigned int src_x , unsigned int src_y ,
2015-01-17 19:09:26 +02:00
unsigned int src_w , unsigned int src_h )
2012-01-16 12:51:16 -06:00
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2012-08-15 15:18:01 -05:00
struct omap_drm_window * win = & omap_plane - > win ;
win - > crtc_x = crtc_x ;
win - > crtc_y = crtc_y ;
win - > crtc_w = crtc_w ;
win - > crtc_h = crtc_h ;
2012-01-16 12:51:16 -06:00
2015-01-17 22:31:42 +02:00
win - > src_x = src_x ;
win - > src_y = src_y ;
win - > src_w = src_w ;
win - > src_h = src_h ;
2012-01-16 12:51:16 -06:00
2015-01-17 19:09:26 +02:00
return omap_plane_setup ( omap_plane ) ;
}
2012-12-04 13:59:12 -06:00
2015-01-17 19:09:26 +02:00
int omap_plane_set_enable ( struct drm_plane * plane , bool enable )
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
if ( enable = = omap_plane - > enabled )
return 0 ;
2012-12-04 13:59:12 -06:00
2015-01-17 19:09:26 +02:00
omap_plane - > enabled = enable ;
return omap_plane_setup ( omap_plane ) ;
2012-01-16 12:51:16 -06:00
}
2012-01-16 12:51:18 -06:00
static int omap_plane_update ( struct drm_plane * plane ,
struct drm_crtc * crtc , struct drm_framebuffer * fb ,
int crtc_x , int crtc_y ,
unsigned int crtc_w , unsigned int crtc_h ,
uint32_t src_x , uint32_t src_y ,
uint32_t src_w , uint32_t src_h )
{
2012-12-04 13:59:12 -06:00
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2015-01-17 19:09:26 +02:00
int ret ;
2012-12-04 13:59:12 -06:00
omap_plane - > enabled = true ;
2013-04-09 15:26:00 +03:00
2014-04-05 21:33:51 +03:00
/* omap_plane_mode_set() takes adjusted src */
switch ( omap_plane - > win . rotation & 0xf ) {
case BIT ( DRM_ROTATE_90 ) :
case BIT ( DRM_ROTATE_270 ) :
swap ( src_w , src_h ) ;
break ;
}
2015-01-11 00:11:18 +02:00
/*
* We don ' t need to take a reference to the framebuffer as the DRM core
* has already done so for the purpose of setting plane - > fb .
*/
plane - > fb = fb ;
plane - > crtc = crtc ;
2015-01-17 22:31:42 +02:00
/* src values are in Q16 fixed point, convert to integer: */
2015-01-17 19:09:26 +02:00
ret = omap_plane_mode_set ( plane , crtc , fb ,
crtc_x , crtc_y , crtc_w , crtc_h ,
src_x > > 16 , src_y > > 16 ,
src_w > > 16 , src_h > > 16 ) ;
if ( ret < 0 )
return ret ;
return omap_crtc_flush ( plane - > crtc ) ;
2012-01-16 12:51:18 -06:00
}
2012-01-16 12:51:16 -06:00
static int omap_plane_disable ( struct drm_plane * plane )
{
2012-08-15 15:18:01 -05:00
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2015-01-12 22:38:16 +02:00
2012-08-15 15:18:01 -05:00
omap_plane - > win . rotation = BIT ( DRM_ROTATE_0 ) ;
2015-01-12 23:56:57 +02:00
omap_plane - > info . zorder = plane - > type = = DRM_PLANE_TYPE_PRIMARY
? 0 : omap_plane - > id ;
2015-01-17 19:09:26 +02:00
if ( ! omap_plane - > enabled )
return 0 ;
/* Disabling a plane never fails. */
omap_plane - > enabled = false ;
omap_plane_setup ( omap_plane ) ;
return omap_crtc_flush ( plane - > crtc ) ;
2012-01-16 12:51:16 -06:00
}
static void omap_plane_destroy ( struct drm_plane * plane )
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2012-12-04 13:59:12 -06:00
DBG ( " %s " , omap_plane - > name ) ;
omap_irq_unregister ( plane - > dev , & omap_plane - > error_irq ) ;
2012-01-16 12:51:16 -06:00
drm_plane_cleanup ( plane ) ;
2012-12-04 13:59:12 -06:00
2012-01-16 12:51:16 -06:00
kfree ( omap_plane ) ;
}
2012-08-15 15:18:01 -05:00
/* helper to install properties which are common to planes and crtcs */
void omap_plane_install_properties ( struct drm_plane * plane ,
struct drm_mode_object * obj )
{
struct drm_device * dev = plane - > dev ;
struct omap_drm_private * priv = dev - > dev_private ;
2012-10-25 17:14:13 -05:00
if ( priv - > has_dmm ) {
2015-03-06 17:16:43 +02:00
struct drm_property * prop = dev - > mode_config . rotation_property ;
2012-10-25 17:14:13 -05:00
drm_object_attach_property ( obj , prop , 0 ) ;
2012-08-15 15:18:01 -05:00
}
2012-08-15 15:18:02 -05:00
2015-03-06 17:16:43 +02:00
drm_object_attach_property ( obj , priv - > zorder_prop , 0 ) ;
2012-08-15 15:18:01 -05:00
}
int omap_plane_set_property ( struct drm_plane * plane ,
struct drm_property * property , uint64_t val )
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
struct omap_drm_private * priv = plane - > dev - > dev_private ;
2015-01-17 19:09:26 +02:00
int ret ;
2012-08-15 15:18:01 -05:00
2015-03-06 17:16:43 +02:00
if ( property = = plane - > dev - > mode_config . rotation_property ) {
2012-12-04 13:59:12 -06:00
DBG ( " %s: rotation: %02x " , omap_plane - > name , ( uint32_t ) val ) ;
2012-08-15 15:18:01 -05:00
omap_plane - > win . rotation = val ;
2012-08-15 15:18:02 -05:00
} else if ( property = = priv - > zorder_prop ) {
2012-12-04 13:59:12 -06:00
DBG ( " %s: zorder: %02x " , omap_plane - > name , ( uint32_t ) val ) ;
2012-08-15 15:18:02 -05:00
omap_plane - > info . zorder = val ;
2015-01-17 19:09:26 +02:00
} else {
return - EINVAL ;
2012-08-15 15:18:01 -05:00
}
2015-01-17 19:09:26 +02:00
/*
* We ' re done if the plane is disabled , properties will be applied the
* next time it becomes enabled .
*/
if ( ! omap_plane - > enabled )
return 0 ;
ret = omap_plane_setup ( omap_plane ) ;
if ( ret < 0 )
return ret ;
return omap_crtc_flush ( plane - > crtc ) ;
2012-08-15 15:18:01 -05:00
}
2012-01-16 12:51:16 -06:00
static const struct drm_plane_funcs omap_plane_funcs = {
2015-01-11 00:02:07 +02:00
. update_plane = omap_plane_update ,
. disable_plane = omap_plane_disable ,
. destroy = omap_plane_destroy ,
. set_property = omap_plane_set_property ,
2012-01-16 12:51:16 -06:00
} ;
2012-12-04 13:59:12 -06:00
static void omap_plane_error_irq ( struct omap_drm_irq * irq , uint32_t irqstatus )
{
struct omap_plane * omap_plane =
container_of ( irq , struct omap_plane , error_irq ) ;
2014-11-19 12:50:13 +02:00
DRM_ERROR_RATELIMITED ( " %s: errors: %08x \n " , omap_plane - > name ,
irqstatus ) ;
2012-12-04 13:59:12 -06:00
}
static const char * plane_names [ ] = {
2015-01-11 00:02:07 +02:00
[ OMAP_DSS_GFX ] = " gfx " ,
[ OMAP_DSS_VIDEO1 ] = " vid1 " ,
[ OMAP_DSS_VIDEO2 ] = " vid2 " ,
[ OMAP_DSS_VIDEO3 ] = " vid3 " ,
2012-12-04 13:59:12 -06:00
} ;
static const uint32_t error_irqs [ ] = {
2015-01-11 00:02:07 +02:00
[ OMAP_DSS_GFX ] = DISPC_IRQ_GFX_FIFO_UNDERFLOW ,
[ OMAP_DSS_VIDEO1 ] = DISPC_IRQ_VID1_FIFO_UNDERFLOW ,
[ OMAP_DSS_VIDEO2 ] = DISPC_IRQ_VID2_FIFO_UNDERFLOW ,
[ OMAP_DSS_VIDEO3 ] = DISPC_IRQ_VID3_FIFO_UNDERFLOW ,
2012-12-04 13:59:12 -06:00
} ;
2012-01-16 12:51:16 -06:00
/* initialize plane */
struct drm_plane * omap_plane_init ( struct drm_device * dev ,
2015-01-11 00:11:18 +02:00
int id , enum drm_plane_type type )
2012-01-16 12:51:16 -06:00
{
2012-12-04 13:59:12 -06:00
struct omap_drm_private * priv = dev - > dev_private ;
2015-01-11 00:11:18 +02:00
struct drm_plane * plane ;
2012-01-16 12:51:16 -06:00
struct omap_plane * omap_plane ;
2012-12-04 13:59:12 -06:00
struct omap_overlay_info * info ;
2015-01-11 00:11:18 +02:00
int ret ;
2012-01-16 12:51:16 -06:00
2015-01-11 00:11:18 +02:00
DBG ( " %s: type=%d " , plane_names [ id ] , type ) ;
2012-03-05 10:48:35 -06:00
2012-01-16 12:51:16 -06:00
omap_plane = kzalloc ( sizeof ( * omap_plane ) , GFP_KERNEL ) ;
2013-02-11 09:41:29 -08:00
if ( ! omap_plane )
2015-01-11 16:30:44 +02:00
return ERR_PTR ( - ENOMEM ) ;
2012-01-16 12:51:16 -06:00
2012-03-05 10:48:31 -06:00
omap_plane - > nformats = omap_framebuffer_get_formats (
omap_plane - > formats , ARRAY_SIZE ( omap_plane - > formats ) ,
2012-12-04 13:59:12 -06:00
dss_feat_get_supported_color_modes ( id ) ) ;
omap_plane - > id = id ;
omap_plane - > name = plane_names [ id ] ;
2012-01-16 12:51:16 -06:00
plane = & omap_plane - > base ;
2012-12-04 13:59:12 -06:00
omap_plane - > error_irq . irqmask = error_irqs [ id ] ;
omap_plane - > error_irq . irq = omap_plane_error_irq ;
omap_irq_register ( dev , & omap_plane - > error_irq ) ;
2015-01-11 00:11:18 +02:00
ret = drm_universal_plane_init ( dev , plane , ( 1 < < priv - > num_crtcs ) - 1 ,
& omap_plane_funcs , omap_plane - > formats ,
omap_plane - > nformats , type ) ;
if ( ret < 0 )
goto error ;
2012-01-16 12:51:16 -06:00
2012-08-15 15:18:01 -05:00
omap_plane_install_properties ( plane , & plane - > base ) ;
2012-01-16 12:51:16 -06:00
/* get our starting configuration, set defaults for parameters
* we don ' t currently use , etc :
*/
2012-12-04 13:59:12 -06:00
info = & omap_plane - > info ;
info - > rotation_type = OMAP_DSS_ROT_DMA ;
info - > rotation = OMAP_DSS_ROT_0 ;
info - > global_alpha = 0xff ;
info - > mirror = 0 ;
2012-01-16 12:51:16 -06:00
/* Set defaults depending on whether we are a CRTC or overlay
* layer .
* TODO add ioctl to give userspace an API to change this . . this
* will come in a subsequent patch .
*/
2015-01-11 00:11:18 +02:00
if ( type = = DRM_PLANE_TYPE_PRIMARY )
2012-01-16 12:51:16 -06:00
omap_plane - > info . zorder = 0 ;
else
2012-12-04 13:59:12 -06:00
omap_plane - > info . zorder = id ;
2012-01-16 12:51:16 -06:00
return plane ;
2015-01-11 00:11:18 +02:00
error :
omap_irq_unregister ( plane - > dev , & omap_plane - > error_irq ) ;
kfree ( omap_plane ) ;
return NULL ;
2012-01-16 12:51:16 -06:00
}