2019-02-06 12:01:16 -02:00
// SPDX-License-Identifier: GPL-2.0+
2018-05-16 20:56:21 -03:00
2018-07-24 19:30:22 +03:00
# include <drm/drm_atomic.h>
2018-05-16 20:56:21 -03:00
# include <drm/drm_atomic_helper.h>
2019-06-30 08:19:01 +02:00
# include <drm/drm_fourcc.h>
2018-07-24 19:29:23 +03:00
# include <drm/drm_gem_framebuffer_helper.h>
2019-06-30 08:19:01 +02:00
# include <drm/drm_plane_helper.h>
# include "vkms_drv.h"
2018-05-16 20:56:21 -03:00
2019-06-07 00:27:45 +02:00
static const u32 vkms_formats [ ] = {
DRM_FORMAT_XRGB8888 ,
} ;
static const u32 vkms_cursor_formats [ ] = {
DRM_FORMAT_ARGB8888 ,
} ;
2018-08-02 04:08:22 +03:00
static struct drm_plane_state *
vkms_plane_duplicate_state ( struct drm_plane * plane )
{
struct vkms_plane_state * vkms_state ;
2019-06-25 22:37:05 -03:00
struct vkms_composer * composer ;
2018-08-02 04:08:22 +03:00
vkms_state = kzalloc ( sizeof ( * vkms_state ) , GFP_KERNEL ) ;
if ( ! vkms_state )
return NULL ;
2019-06-25 22:37:05 -03:00
composer = kzalloc ( sizeof ( * composer ) , GFP_KERNEL ) ;
if ( ! composer ) {
DRM_DEBUG_KMS ( " Couldn't allocate composer \n " ) ;
2018-11-28 11:10:33 +01:00
kfree ( vkms_state ) ;
return NULL ;
}
2018-08-02 04:10:26 +03:00
2019-06-25 22:37:05 -03:00
vkms_state - > composer = composer ;
2018-08-02 04:10:26 +03:00
2018-08-02 04:08:22 +03:00
__drm_atomic_helper_plane_duplicate_state ( plane ,
& vkms_state - > base ) ;
return & vkms_state - > base ;
}
static void vkms_plane_destroy_state ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct vkms_plane_state * vkms_state = to_vkms_plane_state ( old_state ) ;
2018-08-02 04:10:26 +03:00
struct drm_crtc * crtc = vkms_state - > base . crtc ;
if ( crtc ) {
/* dropping the reference we acquired in
* vkms_primary_plane_update ( )
*/
2019-06-25 22:37:05 -03:00
if ( drm_framebuffer_read_refcount ( & vkms_state - > composer - > fb ) )
drm_framebuffer_put ( & vkms_state - > composer - > fb ) ;
2018-08-02 04:10:26 +03:00
}
2019-06-25 22:37:05 -03:00
kfree ( vkms_state - > composer ) ;
vkms_state - > composer = NULL ;
2018-08-02 04:08:22 +03:00
__drm_atomic_helper_plane_destroy_state ( old_state ) ;
kfree ( vkms_state ) ;
}
static void vkms_plane_reset ( struct drm_plane * plane )
{
struct vkms_plane_state * vkms_state ;
if ( plane - > state )
vkms_plane_destroy_state ( plane , plane - > state ) ;
vkms_state = kzalloc ( sizeof ( * vkms_state ) , GFP_KERNEL ) ;
if ( ! vkms_state ) {
DRM_ERROR ( " Cannot allocate vkms_plane_state \n " ) ;
return ;
}
plane - > state = & vkms_state - > base ;
plane - > state - > plane = plane ;
}
2018-05-16 20:56:21 -03:00
static const struct drm_plane_funcs vkms_plane_funcs = {
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
. destroy = drm_plane_cleanup ,
2018-08-02 04:08:22 +03:00
. reset = vkms_plane_reset ,
. atomic_duplicate_state = vkms_plane_duplicate_state ,
. atomic_destroy_state = vkms_plane_destroy_state ,
2018-05-16 20:56:21 -03:00
} ;
2018-09-06 08:17:16 +03:00
static void vkms_plane_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
2018-07-12 10:41:02 -03:00
{
2018-08-02 04:10:26 +03:00
struct vkms_plane_state * vkms_plane_state ;
2018-09-06 08:18:26 +03:00
struct drm_framebuffer * fb = plane - > state - > fb ;
2019-06-25 22:37:05 -03:00
struct vkms_composer * composer ;
2018-08-02 04:10:26 +03:00
2018-09-06 08:18:26 +03:00
if ( ! plane - > state - > crtc | | ! fb )
2018-08-02 04:10:26 +03:00
return ;
vkms_plane_state = to_vkms_plane_state ( plane - > state ) ;
2018-09-06 08:18:26 +03:00
2019-06-25 22:37:05 -03:00
composer = vkms_plane_state - > composer ;
memcpy ( & composer - > src , & plane - > state - > src , sizeof ( struct drm_rect ) ) ;
memcpy ( & composer - > dst , & plane - > state - > dst , sizeof ( struct drm_rect ) ) ;
memcpy ( & composer - > fb , fb , sizeof ( struct drm_framebuffer ) ) ;
drm_framebuffer_get ( & composer - > fb ) ;
composer - > offset = fb - > offsets [ 0 ] ;
composer - > pitch = fb - > pitches [ 0 ] ;
composer - > cpp = fb - > format - > cpp [ 0 ] ;
2018-07-12 10:41:02 -03:00
}
2018-07-24 19:30:22 +03:00
static int vkms_plane_atomic_check ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct drm_crtc_state * crtc_state ;
2018-09-06 08:17:16 +03:00
bool can_position = false ;
2018-07-24 19:30:22 +03:00
int ret ;
2019-12-13 18:26:11 +01:00
if ( ! state - > fb | | WARN_ON ( ! state - > crtc ) )
2018-07-24 19:30:22 +03:00
return 0 ;
crtc_state = drm_atomic_get_crtc_state ( state - > state , state - > crtc ) ;
if ( IS_ERR ( crtc_state ) )
return PTR_ERR ( crtc_state ) ;
2018-09-06 08:17:16 +03:00
if ( plane - > type = = DRM_PLANE_TYPE_CURSOR )
can_position = true ;
2018-07-24 19:30:22 +03:00
ret = drm_atomic_helper_check_plane_state ( state , crtc_state ,
DRM_PLANE_HELPER_NO_SCALING ,
DRM_PLANE_HELPER_NO_SCALING ,
2018-09-06 08:17:16 +03:00
can_position , true ) ;
2018-07-24 19:30:22 +03:00
if ( ret ! = 0 )
return ret ;
/* for now primary plane must be visible and full screen */
2018-09-06 08:17:16 +03:00
if ( ! state - > visible & & ! can_position )
2018-07-24 19:30:22 +03:00
return - EINVAL ;
return 0 ;
}
2018-07-24 19:29:23 +03:00
static int vkms_prepare_fb ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct drm_gem_object * gem_obj ;
int ret ;
if ( ! state - > fb )
return 0 ;
gem_obj = drm_gem_fb_get_obj ( state - > fb , 0 ) ;
ret = vkms_gem_vmap ( gem_obj ) ;
if ( ret )
DRM_ERROR ( " vmap failed: %d \n " , ret ) ;
return drm_gem_fb_prepare_fb ( plane , state ) ;
}
static void vkms_cleanup_fb ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
struct drm_gem_object * gem_obj ;
if ( ! old_state - > fb )
return ;
gem_obj = drm_gem_fb_get_obj ( old_state - > fb , 0 ) ;
vkms_gem_vunmap ( gem_obj ) ;
}
2018-07-12 10:41:02 -03:00
static const struct drm_plane_helper_funcs vkms_primary_helper_funcs = {
2018-09-06 08:17:16 +03:00
. atomic_update = vkms_plane_atomic_update ,
2018-07-24 19:30:22 +03:00
. atomic_check = vkms_plane_atomic_check ,
2018-07-24 19:29:23 +03:00
. prepare_fb = vkms_prepare_fb ,
. cleanup_fb = vkms_cleanup_fb ,
2018-07-12 10:41:02 -03:00
} ;
2018-09-06 08:17:16 +03:00
struct drm_plane * vkms_plane_init ( struct vkms_device * vkmsdev ,
2019-06-25 22:36:18 -03:00
enum drm_plane_type type , int index )
2018-05-16 20:56:21 -03:00
{
struct drm_device * dev = & vkmsdev - > drm ;
2018-09-06 08:17:16 +03:00
const struct drm_plane_helper_funcs * funcs ;
2018-05-16 20:56:21 -03:00
struct drm_plane * plane ;
const u32 * formats ;
int ret , nformats ;
plane = kzalloc ( sizeof ( * plane ) , GFP_KERNEL ) ;
if ( ! plane )
return ERR_PTR ( - ENOMEM ) ;
2018-09-06 08:17:16 +03:00
if ( type = = DRM_PLANE_TYPE_CURSOR ) {
formats = vkms_cursor_formats ;
nformats = ARRAY_SIZE ( vkms_cursor_formats ) ;
funcs = & vkms_primary_helper_funcs ;
} else {
formats = vkms_formats ;
nformats = ARRAY_SIZE ( vkms_formats ) ;
funcs = & vkms_primary_helper_funcs ;
}
2018-05-16 20:56:21 -03:00
2019-06-25 22:36:18 -03:00
ret = drm_universal_plane_init ( dev , plane , 1 < < index ,
2018-05-16 20:56:21 -03:00
& vkms_plane_funcs ,
formats , nformats ,
2018-09-06 08:17:16 +03:00
NULL , type , NULL ) ;
2018-05-16 20:56:21 -03:00
if ( ret ) {
kfree ( plane ) ;
return ERR_PTR ( ret ) ;
}
2018-09-06 08:17:16 +03:00
drm_plane_helper_add ( plane , funcs ) ;
2018-07-12 10:41:02 -03:00
2018-05-16 20:56:21 -03:00
return plane ;
}