2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-01-04 18:36:34 +01:00
/*
* Copyright ( c ) 2015 MediaTek Inc .
* Author : CK Hu < ck . hu @ mediatek . com >
*/
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
2019-07-16 08:42:20 +02:00
# include <drm/drm_fourcc.h>
2016-01-04 18:36:34 +01:00
# include <drm/drm_plane_helper.h>
2019-06-14 22:36:00 +02:00
# include <drm/drm_gem_framebuffer_helper.h>
2016-01-04 18:36:34 +01:00
# include "mtk_drm_crtc.h"
# include "mtk_drm_ddp_comp.h"
# include "mtk_drm_drv.h"
# include "mtk_drm_gem.h"
# include "mtk_drm_plane.h"
static const u32 formats [ ] = {
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_RGB565 ,
2017-01-24 12:40:58 +08:00
DRM_FORMAT_UYVY ,
DRM_FORMAT_YUYV ,
2016-01-04 18:36:34 +01:00
} ;
static void mtk_plane_reset ( struct drm_plane * plane )
{
struct mtk_plane_state * state ;
if ( plane - > state ) {
2016-08-04 10:59:54 +08:00
__drm_atomic_helper_plane_destroy_state ( plane - > state ) ;
2016-01-04 18:36:34 +01:00
state = to_mtk_plane_state ( plane - > state ) ;
memset ( state , 0 , sizeof ( * state ) ) ;
} else {
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return ;
plane - > state = & state - > base ;
}
state - > base . plane = plane ;
state - > pending . format = DRM_FORMAT_RGB565 ;
}
static struct drm_plane_state * mtk_plane_duplicate_state ( struct drm_plane * plane )
{
struct mtk_plane_state * old_state = to_mtk_plane_state ( plane - > state ) ;
struct mtk_plane_state * state ;
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return NULL ;
__drm_atomic_helper_plane_duplicate_state ( plane , & state - > base ) ;
WARN_ON ( state - > base . plane ! = plane ) ;
state - > pending = old_state - > pending ;
return & state - > base ;
}
static void mtk_drm_plane_destroy_state ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
2016-05-09 16:34:10 +02:00
__drm_atomic_helper_plane_destroy_state ( state ) ;
2016-01-04 18:36:34 +01:00
kfree ( to_mtk_plane_state ( state ) ) ;
}
static const struct drm_plane_funcs mtk_plane_funcs = {
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
. destroy = drm_plane_cleanup ,
. reset = mtk_plane_reset ,
. atomic_duplicate_state = mtk_plane_duplicate_state ,
. atomic_destroy_state = mtk_drm_plane_destroy_state ,
} ;
static int mtk_plane_atomic_check ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct drm_framebuffer * fb = state - > fb ;
struct drm_crtc_state * crtc_state ;
if ( ! fb )
return 0 ;
if ( ! state - > crtc )
return 0 ;
crtc_state = drm_atomic_get_crtc_state ( state - > state , state - > crtc ) ;
if ( IS_ERR ( crtc_state ) )
return PTR_ERR ( crtc_state ) ;
2018-01-23 19:08:57 +02:00
return drm_atomic_helper_check_plane_state ( state , crtc_state ,
2017-11-01 22:16:19 +02:00
DRM_PLANE_HELPER_NO_SCALING ,
DRM_PLANE_HELPER_NO_SCALING ,
true , true ) ;
2016-01-04 18:36:34 +01:00
}
static void mtk_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct mtk_plane_state * state = to_mtk_plane_state ( plane - > state ) ;
2016-08-04 10:59:55 +08:00
struct drm_crtc * crtc = plane - > state - > crtc ;
struct drm_framebuffer * fb = plane - > state - > fb ;
2016-01-04 18:36:34 +01:00
struct drm_gem_object * gem ;
struct mtk_drm_gem_obj * mtk_gem ;
2016-08-04 10:59:55 +08:00
unsigned int pitch , format ;
dma_addr_t addr ;
2016-01-04 18:36:34 +01:00
2016-08-04 10:59:55 +08:00
if ( ! crtc | | WARN_ON ( ! fb ) )
2016-01-04 18:36:34 +01:00
return ;
2018-05-18 14:47:04 +01:00
gem = fb - > obj [ 0 ] ;
2016-01-04 18:36:34 +01:00
mtk_gem = to_mtk_gem_obj ( gem ) ;
2016-08-04 10:59:55 +08:00
addr = mtk_gem - > dma_addr ;
pitch = fb - > pitches [ 0 ] ;
2016-12-14 23:32:55 +02:00
format = fb - > format - > format ;
2016-08-04 10:59:55 +08:00
2016-12-14 23:30:57 +02:00
addr + = ( plane - > state - > src . x1 > > 16 ) * fb - > format - > cpp [ 0 ] ;
2016-08-04 10:59:55 +08:00
addr + = ( plane - > state - > src . y1 > > 16 ) * pitch ;
state - > pending . enable = true ;
state - > pending . pitch = pitch ;
state - > pending . format = format ;
state - > pending . addr = addr ;
state - > pending . x = plane - > state - > dst . x1 ;
state - > pending . y = plane - > state - > dst . y1 ;
state - > pending . width = drm_rect_width ( & plane - > state - > dst ) ;
state - > pending . height = drm_rect_height ( & plane - > state - > dst ) ;
wmb ( ) ; /* Make sure the above parameters are set before update */
state - > pending . dirty = true ;
2016-01-04 18:36:34 +01:00
}
static void mtk_plane_atomic_disable ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct mtk_plane_state * state = to_mtk_plane_state ( plane - > state ) ;
state - > pending . enable = false ;
wmb ( ) ; /* Make sure the above parameter is set before update */
state - > pending . dirty = true ;
}
static const struct drm_plane_helper_funcs mtk_plane_helper_funcs = {
2019-06-14 22:36:00 +02:00
. prepare_fb = drm_gem_fb_prepare_fb ,
2016-01-04 18:36:34 +01:00
. atomic_check = mtk_plane_atomic_check ,
. atomic_update = mtk_plane_atomic_update ,
. atomic_disable = mtk_plane_atomic_disable ,
} ;
2016-08-04 10:59:53 +08:00
int mtk_plane_init ( struct drm_device * dev , struct drm_plane * plane ,
2016-08-04 10:59:52 +08:00
unsigned long possible_crtcs , enum drm_plane_type type )
2016-01-04 18:36:34 +01:00
{
int err ;
2016-08-04 10:59:53 +08:00
err = drm_universal_plane_init ( dev , plane , possible_crtcs ,
2016-01-04 18:36:34 +01:00
& mtk_plane_funcs , formats ,
2017-07-23 20:46:38 -07:00
ARRAY_SIZE ( formats ) , NULL , type , NULL ) ;
2016-01-04 18:36:34 +01:00
if ( err ) {
DRM_ERROR ( " failed to initialize plane \n " ) ;
return err ;
}
2016-08-04 10:59:53 +08:00
drm_plane_helper_add ( plane , & mtk_plane_helper_funcs ) ;
2016-01-04 18:36:34 +01:00
return 0 ;
}