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/>.
*/
2015-06-16 14:54:51 +03:00
# include <drm/drm_atomic.h>
2015-03-05 21:38:16 +02:00
# include <drm/drm_atomic_helper.h>
2015-03-05 13:39:56 +02:00
# include <drm/drm_plane_helper.h>
2015-03-05 21:38:16 +02:00
2012-08-15 15:18:01 -05:00
# include "omap_dmm_tiler.h"
2015-03-05 21:31:37 +02:00
# include "omap_drv.h"
2012-01-16 12:51:16 -06:00
/*
* plane funcs
*/
# define to_omap_plane(x) container_of(x, struct omap_plane, base)
struct omap_plane {
struct drm_plane base ;
2017-03-24 16:47:54 +02:00
enum omap_plane_id id ;
2012-12-04 13:59:12 -06:00
const char * name ;
2012-03-05 10:48:31 -06:00
} ;
2012-01-16 12:51:16 -06:00
2015-05-29 11:05:37 +03:00
static int omap_plane_prepare_fb ( struct drm_plane * plane ,
2016-08-18 19:00:16 +01:00
struct drm_plane_state * new_state )
2015-05-29 11:05:37 +03:00
{
2015-09-02 10:42:40 +02:00
if ( ! new_state - > fb )
return 0 ;
return omap_framebuffer_pin ( new_state - > fb ) ;
2015-05-29 11:05:37 +03:00
}
static void omap_plane_cleanup_fb ( struct drm_plane * plane ,
2016-08-18 19:00:16 +01:00
struct drm_plane_state * old_state )
2015-05-29 11:05:37 +03:00
{
2015-09-02 10:42:40 +02:00
if ( old_state - > fb )
omap_framebuffer_unpin ( old_state - > fb ) ;
2015-05-29 11:05:37 +03:00
}
static void omap_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
2015-03-06 18:35:16 +02:00
{
2015-11-05 18:39:52 +02:00
struct omap_drm_private * priv = plane - > dev - > dev_private ;
2015-03-06 19:18:56 +02:00
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
struct drm_plane_state * state = plane - > state ;
2015-03-06 19:00:18 +02:00
struct omap_overlay_info info ;
2012-01-16 12:51:17 -06:00
int ret ;
2012-01-16 12:51:16 -06:00
2015-03-06 19:18:56 +02:00
DBG ( " %s, crtc=%p fb=%p " , omap_plane - > name , state - > crtc , state - > fb ) ;
2012-12-04 13:59:12 -06:00
2015-03-06 19:00:18 +02:00
memset ( & info , 0 , sizeof ( info ) ) ;
2017-05-03 14:14:27 +03:00
info . rotation_type = OMAP_DSS_ROT_NONE ;
2017-05-16 11:05:09 +03:00
info . rotation = DRM_MODE_ROTATE_0 ;
2015-03-06 19:00:18 +02:00
info . global_alpha = 0xff ;
2017-05-09 01:27:12 +03:00
info . zorder = state - > zpos ;
2015-03-06 19:00:18 +02:00
2012-12-04 13:59:12 -06:00
/* update scanout: */
2017-05-15 13:40:08 +03:00
omap_framebuffer_update_scanout ( state - > fb , state , & info ) ;
2012-01-16 12:51:16 -06:00
2015-03-06 19:00:18 +02:00
DBG ( " %dx%d -> %dx%d (%d) " , info . width , info . height ,
info . out_width , info . out_height ,
info . screen_width ) ;
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
/* and finally, update omapdss: */
2016-08-29 13:15:02 +03:00
ret = priv - > dispc_ops - > ovl_setup ( omap_plane - > id , & info ,
2017-02-17 12:30:07 +02:00
omap_crtc_timings ( state - > crtc ) , false ,
omap_crtc_channel ( state - > crtc ) ) ;
2016-06-10 12:44:31 +03:00
if ( ret ) {
dev_err ( plane - > dev - > dev , " Failed to setup plane %s \n " ,
omap_plane - > name ) ;
2015-11-05 18:39:52 +02:00
priv - > dispc_ops - > ovl_enable ( omap_plane - > id , false ) ;
2015-05-29 11:03:15 +03:00
return ;
2015-05-29 11:06:07 +03:00
}
2012-12-04 13:59:12 -06:00
2015-11-05 18:39:52 +02:00
priv - > dispc_ops - > ovl_enable ( omap_plane - > id , true ) ;
2015-03-05 13:39:56 +02:00
}
static void omap_plane_atomic_disable ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
2012-01-16 12:51:16 -06:00
{
2015-11-05 18:39:52 +02:00
struct omap_drm_private * priv = plane - > dev - > dev_private ;
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
2017-05-19 16:50:17 -04:00
plane - > state - > rotation = DRM_MODE_ROTATE_0 ;
2017-05-09 01:27:12 +03:00
plane - > state - > zpos = plane - > type = = DRM_PLANE_TYPE_PRIMARY
2015-03-06 18:35:16 +02:00
? 0 : omap_plane - > id ;
2015-01-12 23:56:57 +02:00
2015-11-05 18:39:52 +02:00
priv - > dispc_ops - > ovl_enable ( omap_plane - > id , false ) ;
2012-01-16 12:51:16 -06:00
}
2015-06-16 14:54:51 +03:00
static int omap_plane_atomic_check ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct drm_crtc_state * crtc_state ;
2016-06-10 12:50:53 +03:00
if ( ! state - > fb )
2015-06-16 14:54:51 +03:00
return 0 ;
2016-06-10 12:50:53 +03:00
/* crtc should only be NULL when disabling (i.e., !state->fb) */
if ( WARN_ON ( ! state - > crtc ) )
return 0 ;
crtc_state = drm_atomic_get_existing_crtc_state ( state - > state , state - > crtc ) ;
/* we should have a crtc state if the plane is attached to a crtc */
if ( WARN_ON ( ! crtc_state ) )
return 0 ;
2015-06-16 14:54:51 +03:00
2016-06-10 12:50:39 +03:00
if ( ! crtc_state - > enable )
return 0 ;
2015-06-16 14:54:51 +03:00
if ( state - > crtc_x < 0 | | state - > crtc_y < 0 )
return - EINVAL ;
if ( state - > crtc_x + state - > crtc_w > crtc_state - > adjusted_mode . hdisplay )
return - EINVAL ;
if ( state - > crtc_y + state - > crtc_h > crtc_state - > adjusted_mode . vdisplay )
return - EINVAL ;
2017-05-19 16:50:17 -04:00
if ( state - > rotation ! = DRM_MODE_ROTATE_0 & &
2016-06-10 12:50:53 +03:00
! omap_framebuffer_supports_rotation ( state - > fb ) )
return - EINVAL ;
2015-08-27 13:09:22 +03:00
2015-06-16 14:54:51 +03:00
return 0 ;
}
2015-03-05 13:39:56 +02:00
static const struct drm_plane_helper_funcs omap_plane_helper_funcs = {
. prepare_fb = omap_plane_prepare_fb ,
. cleanup_fb = omap_plane_cleanup_fb ,
2015-06-16 14:54:51 +03:00
. atomic_check = omap_plane_atomic_check ,
2015-03-05 13:39:56 +02:00
. atomic_update = omap_plane_atomic_update ,
. atomic_disable = omap_plane_atomic_disable ,
} ;
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 ) ;
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 ) {
2016-09-26 19:30:52 +03:00
if ( ! plane - > rotation_property )
drm_plane_create_rotation_property ( plane ,
2017-05-19 16:50:17 -04:00
DRM_MODE_ROTATE_0 ,
DRM_MODE_ROTATE_0 | DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 | DRM_MODE_ROTATE_270 |
DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y ) ;
2016-09-26 19:30:52 +03:00
/* Attach the rotation property also to the crtc object */
if ( plane - > rotation_property & & obj ! = & plane - > base )
drm_object_attach_property ( obj , plane - > rotation_property ,
2017-05-19 16:50:17 -04:00
DRM_MODE_ROTATE_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
}
2015-12-15 11:33:23 +02:00
static void omap_plane_reset ( struct drm_plane * plane )
{
struct omap_plane * omap_plane = to_omap_plane ( plane ) ;
2017-05-09 01:27:13 +03:00
drm_atomic_helper_plane_reset ( plane ) ;
if ( ! plane - > state )
2015-12-15 11:33:23 +02:00
return ;
/*
2017-05-09 01:27:12 +03:00
* Set the zpos default depending on whether we are a primary or overlay
2015-12-15 11:33:23 +02:00
* plane .
*/
2017-05-09 01:27:13 +03:00
plane - > state - > zpos = plane - > type = = DRM_PLANE_TYPE_PRIMARY
? 0 : omap_plane - > id ;
2015-12-15 11:33:23 +02:00
}
2015-03-06 18:35:16 +02:00
static int omap_plane_atomic_set_property ( struct drm_plane * plane ,
struct drm_plane_state * state ,
struct drm_property * property ,
uint64_t val )
2012-08-15 15:18:01 -05:00
{
struct omap_drm_private * priv = plane - > dev - > dev_private ;
2015-03-06 18:35:16 +02:00
if ( property = = priv - > zorder_prop )
2017-05-09 01:27:12 +03:00
state - > zpos = val ;
2015-03-06 18:35:16 +02:00
else
2015-01-17 19:09:26 +02:00
return - EINVAL ;
2012-08-15 15:18:01 -05:00
2015-03-06 18:35:16 +02:00
return 0 ;
}
2015-01-17 19:09:26 +02:00
2015-03-06 18:35:16 +02:00
static int omap_plane_atomic_get_property ( struct drm_plane * plane ,
const struct drm_plane_state * state ,
struct drm_property * property ,
uint64_t * val )
{
struct omap_drm_private * priv = plane - > dev - > dev_private ;
if ( property = = priv - > zorder_prop )
2017-05-09 01:27:12 +03:00
* val = state - > zpos ;
2015-03-06 18:35:16 +02:00
else
return - EINVAL ;
2015-01-17 19:09:26 +02:00
2015-03-06 18:35:16 +02:00
return 0 ;
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-03-05 21:50:00 +02:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2015-03-06 18:35:16 +02:00
. reset = omap_plane_reset ,
2015-01-11 00:02:07 +02:00
. destroy = omap_plane_destroy ,
2017-05-09 01:27:13 +03:00
. atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_plane_destroy_state ,
2015-03-06 18:35:16 +02:00
. atomic_set_property = omap_plane_atomic_set_property ,
. atomic_get_property = omap_plane_atomic_get_property ,
2012-01-16 12:51:16 -06:00
} ;
2017-03-24 16:47:55 +02:00
static const char * plane_id_to_name [ ] = {
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
} ;
2017-03-24 16:47:55 +02:00
static const enum omap_plane_id plane_idx_to_id [ ] = {
OMAP_DSS_GFX ,
OMAP_DSS_VIDEO1 ,
OMAP_DSS_VIDEO2 ,
OMAP_DSS_VIDEO3 ,
} ;
2012-01-16 12:51:16 -06:00
/* initialize plane */
struct drm_plane * omap_plane_init ( struct drm_device * dev ,
2017-03-24 16:47:55 +02:00
int idx , enum drm_plane_type type ,
2016-12-02 16:07:11 +02:00
u32 possible_crtcs )
2012-01-16 12:51:16 -06:00
{
2015-11-05 18:39:52 +02:00
struct omap_drm_private * priv = dev - > dev_private ;
2017-05-09 01:27:14 +03:00
unsigned int num_planes = priv - > dispc_ops - > get_num_ovls ( ) ;
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 ;
2017-03-24 16:47:55 +02:00
enum omap_plane_id id ;
2015-01-11 00:11:18 +02:00
int ret ;
2017-05-04 11:27:49 +03:00
u32 nformats ;
const u32 * formats ;
2012-01-16 12:51:16 -06:00
2017-03-24 16:47:55 +02:00
if ( WARN_ON ( idx > = ARRAY_SIZE ( plane_idx_to_id ) ) )
return ERR_PTR ( - EINVAL ) ;
id = plane_idx_to_id [ idx ] ;
DBG ( " %s: type=%d " , plane_id_to_name [ 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
2017-05-04 11:27:49 +03:00
formats = priv - > dispc_ops - > ovl_get_color_modes ( id ) ;
for ( nformats = 0 ; formats [ nformats ] ; + + nformats )
;
2012-12-04 13:59:12 -06:00
omap_plane - > id = id ;
2017-03-24 16:47:55 +02:00
omap_plane - > name = plane_id_to_name [ id ] ;
2012-12-04 13:59:12 -06:00
2012-01-16 12:51:16 -06:00
plane = & omap_plane - > base ;
2016-12-02 16:07:11 +02:00
ret = drm_universal_plane_init ( dev , plane , possible_crtcs ,
2017-05-04 11:27:49 +03:00
& omap_plane_funcs , formats ,
2017-07-23 20:46:38 -07:00
nformats , NULL , type , NULL ) ;
2015-01-11 00:11:18 +02:00
if ( ret < 0 )
goto error ;
2012-01-16 12:51:16 -06:00
2015-03-05 13:39:56 +02:00
drm_plane_helper_add ( plane , & omap_plane_helper_funcs ) ;
2012-08-15 15:18:01 -05:00
omap_plane_install_properties ( plane , & plane - > base ) ;
2017-05-09 01:27:14 +03:00
drm_plane_create_zpos_property ( plane , 0 , 0 , num_planes - 1 ) ;
2012-08-15 15:18:01 -05:00
2012-01-16 12:51:16 -06:00
return plane ;
2015-01-11 00:11:18 +02:00
error :
2017-03-24 16:47:55 +02:00
dev_err ( dev - > dev , " %s(): could not create plane: %s \n " ,
__func__ , plane_id_to_name [ id ] ) ;
2015-01-11 00:11:18 +02:00
kfree ( omap_plane ) ;
return NULL ;
2012-01-16 12:51:16 -06:00
}