2019-05-27 08:55:01 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-10-29 09:36:23 +01:00
/*
* Copyright ( C ) 2015 Free Electrons
* Copyright ( C ) 2015 NextThing Co
*
* Maxime Ripard < maxime . ripard @ free - electrons . com >
*/
# include <drm/drm_atomic_helper.h>
2018-11-22 09:44:17 +08:00
# include <drm/drm_gem_framebuffer_helper.h>
2019-07-16 08:42:06 +02:00
# include <drm/drm_plane_helper.h>
2015-10-29 09:36:23 +01:00
# include "sun4i_backend.h"
2018-01-22 10:25:23 +01:00
# include "sun4i_frontend.h"
2015-10-29 09:36:23 +01:00
# include "sun4i_layer.h"
2017-05-17 22:47:17 +08:00
# include "sunxi_engine.h"
2015-10-29 09:36:23 +01:00
2018-01-22 10:25:18 +01:00
static void sun4i_backend_layer_reset ( struct drm_plane * plane )
{
2017-12-17 17:32:21 +01:00
struct sun4i_layer * layer = plane_to_sun4i_layer ( plane ) ;
2018-01-22 10:25:18 +01:00
struct sun4i_layer_state * state ;
if ( plane - > state ) {
state = state_to_sun4i_layer_state ( plane - > state ) ;
__drm_atomic_helper_plane_destroy_state ( & state - > state ) ;
kfree ( state ) ;
plane - > state = NULL ;
}
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( state ) {
2018-08-04 17:15:28 +01:00
__drm_atomic_helper_plane_reset ( plane , & state - > state ) ;
2017-12-17 17:32:21 +01:00
plane - > state - > zpos = layer - > id ;
2018-01-22 10:25:18 +01:00
}
}
static struct drm_plane_state *
sun4i_backend_layer_duplicate_state ( struct drm_plane * plane )
{
2018-01-22 10:25:23 +01:00
struct sun4i_layer_state * orig = state_to_sun4i_layer_state ( plane - > state ) ;
2018-01-22 10:25:18 +01:00
struct sun4i_layer_state * copy ;
copy = kzalloc ( sizeof ( * copy ) , GFP_KERNEL ) ;
if ( ! copy )
return NULL ;
__drm_atomic_helper_plane_duplicate_state ( plane , & copy - > state ) ;
2018-01-22 10:25:23 +01:00
copy - > uses_frontend = orig - > uses_frontend ;
2018-01-22 10:25:18 +01:00
return & copy - > state ;
}
static void sun4i_backend_layer_destroy_state ( struct drm_plane * plane ,
struct drm_plane_state * state )
{
struct sun4i_layer_state * s_state = state_to_sun4i_layer_state ( state ) ;
__drm_atomic_helper_plane_destroy_state ( state ) ;
kfree ( s_state ) ;
}
2015-10-29 09:36:23 +01:00
static void sun4i_backend_layer_atomic_disable ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
2018-01-22 10:25:23 +01:00
struct sun4i_layer_state * layer_state = state_to_sun4i_layer_state ( old_state ) ;
2015-10-29 09:36:23 +01:00
struct sun4i_layer * layer = plane_to_sun4i_layer ( plane ) ;
2017-02-23 16:05:42 +08:00
struct sun4i_backend * backend = layer - > backend ;
2015-10-29 09:36:23 +01:00
sun4i_backend_layer_enable ( backend , layer - > id , false ) ;
2018-01-22 10:25:23 +01:00
if ( layer_state - > uses_frontend ) {
unsigned long flags ;
spin_lock_irqsave ( & backend - > frontend_lock , flags ) ;
backend - > frontend_teardown = true ;
spin_unlock_irqrestore ( & backend - > frontend_lock , flags ) ;
}
2015-10-29 09:36:23 +01:00
}
static void sun4i_backend_layer_atomic_update ( struct drm_plane * plane ,
struct drm_plane_state * old_state )
{
2018-01-22 10:25:23 +01:00
struct sun4i_layer_state * layer_state = state_to_sun4i_layer_state ( plane - > state ) ;
2015-10-29 09:36:23 +01:00
struct sun4i_layer * layer = plane_to_sun4i_layer ( plane ) ;
2017-02-23 16:05:42 +08:00
struct sun4i_backend * backend = layer - > backend ;
2018-01-22 10:25:23 +01:00
struct sun4i_frontend * frontend = backend - > frontend ;
2018-11-23 10:24:33 +01:00
sun4i_backend_cleanup_layer ( backend , layer - > id ) ;
2018-01-22 10:25:23 +01:00
if ( layer_state - > uses_frontend ) {
sun4i_frontend_init ( frontend ) ;
sun4i_frontend_update_coord ( frontend , plane ) ;
sun4i_frontend_update_buffer ( frontend , plane ) ;
sun4i_frontend_update_formats ( frontend , plane ,
2018-11-23 10:24:34 +01:00
DRM_FORMAT_XRGB8888 ) ;
2018-01-22 10:25:23 +01:00
sun4i_backend_update_layer_frontend ( backend , layer - > id ,
2018-11-23 10:24:34 +01:00
DRM_FORMAT_XRGB8888 ) ;
2018-01-22 10:25:23 +01:00
sun4i_frontend_enable ( frontend ) ;
} else {
sun4i_backend_update_layer_formats ( backend , layer - > id , plane ) ;
sun4i_backend_update_layer_buffer ( backend , layer - > id , plane ) ;
}
2015-10-29 09:36:23 +01:00
2017-12-17 17:34:26 +01:00
sun4i_backend_update_layer_coord ( backend , layer - > id , plane ) ;
2017-05-01 10:52:32 +02:00
sun4i_backend_update_layer_zpos ( backend , layer - > id , plane ) ;
2015-10-29 09:36:23 +01:00
sun4i_backend_layer_enable ( backend , layer - > id , true ) ;
}
2019-01-18 15:51:25 +01:00
static bool sun4i_layer_format_mod_supported ( struct drm_plane * plane ,
uint32_t format , uint64_t modifier )
{
2019-01-25 11:23:08 +08:00
struct sun4i_layer * layer = plane_to_sun4i_layer ( plane ) ;
if ( IS_ERR_OR_NULL ( layer - > backend - > frontend ) )
sun4i_backend_format_is_supported ( format , modifier ) ;
2019-01-18 15:51:25 +01:00
return sun4i_backend_format_is_supported ( format , modifier ) | |
sun4i_frontend_format_is_supported ( format , modifier ) ;
}
2017-07-03 21:35:20 +05:30
static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
2018-11-22 09:44:17 +08:00
. prepare_fb = drm_gem_fb_prepare_fb ,
2015-10-29 09:36:23 +01:00
. atomic_disable = sun4i_backend_layer_atomic_disable ,
. atomic_update = sun4i_backend_layer_atomic_update ,
} ;
static const struct drm_plane_funcs sun4i_backend_layer_funcs = {
2018-01-22 10:25:18 +01:00
. atomic_destroy_state = sun4i_backend_layer_destroy_state ,
. atomic_duplicate_state = sun4i_backend_layer_duplicate_state ,
2015-10-29 09:36:23 +01:00
. destroy = drm_plane_cleanup ,
. disable_plane = drm_atomic_helper_disable_plane ,
2018-01-22 10:25:18 +01:00
. reset = sun4i_backend_layer_reset ,
2015-10-29 09:36:23 +01:00
. update_plane = drm_atomic_helper_update_plane ,
2019-01-18 15:51:25 +01:00
. format_mod_supported = sun4i_layer_format_mod_supported ,
2015-10-29 09:36:23 +01:00
} ;
2018-11-23 10:24:47 +01:00
static const uint32_t sun4i_layer_formats [ ] = {
2016-09-19 22:17:50 +02:00
DRM_FORMAT_ARGB8888 ,
2016-10-18 10:46:14 +02:00
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_ARGB1555 ,
2018-11-23 10:24:53 +01:00
DRM_FORMAT_BGRX8888 ,
2016-10-18 10:46:14 +02:00
DRM_FORMAT_RGBA5551 ,
DRM_FORMAT_RGBA4444 ,
2015-10-29 09:36:23 +01:00
DRM_FORMAT_RGB888 ,
2016-10-18 10:46:14 +02:00
DRM_FORMAT_RGB565 ,
2019-01-18 15:51:19 +01:00
DRM_FORMAT_NV12 ,
DRM_FORMAT_NV16 ,
DRM_FORMAT_NV21 ,
DRM_FORMAT_NV61 ,
2018-03-01 20:18:46 +01:00
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
2016-09-19 22:17:50 +02:00
DRM_FORMAT_XRGB8888 ,
2019-01-18 15:51:20 +01:00
DRM_FORMAT_YUV411 ,
DRM_FORMAT_YUV420 ,
DRM_FORMAT_YUV422 ,
DRM_FORMAT_YUV444 ,
2018-03-01 20:18:46 +01:00
DRM_FORMAT_YUYV ,
2019-01-18 15:51:20 +01:00
DRM_FORMAT_YVU411 ,
DRM_FORMAT_YVU420 ,
DRM_FORMAT_YVU422 ,
DRM_FORMAT_YVU444 ,
2018-03-01 20:18:46 +01:00
DRM_FORMAT_YVYU ,
2016-09-19 22:17:50 +02:00
} ;
2019-01-25 11:23:08 +08:00
static const uint32_t sun4i_backend_layer_formats [ ] = {
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_RGBA5551 ,
DRM_FORMAT_RGBA4444 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_VYUY ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
} ;
2019-01-18 15:51:25 +01:00
static const uint64_t sun4i_layer_modifiers [ ] = {
DRM_FORMAT_MOD_LINEAR ,
DRM_FORMAT_MOD_ALLWINNER_TILED ,
DRM_FORMAT_MOD_INVALID
} ;
2015-10-29 09:36:23 +01:00
static struct sun4i_layer * sun4i_layer_init_one ( struct drm_device * drm ,
2017-03-09 18:05:29 +08:00
struct sun4i_backend * backend ,
2018-02-16 18:39:33 +01:00
enum drm_plane_type type )
2015-10-29 09:36:23 +01:00
{
2019-01-25 11:23:08 +08:00
const uint64_t * modifiers = sun4i_layer_modifiers ;
const uint32_t * formats = sun4i_layer_formats ;
unsigned int formats_len = ARRAY_SIZE ( sun4i_layer_formats ) ;
2015-10-29 09:36:23 +01:00
struct sun4i_layer * layer ;
int ret ;
layer = devm_kzalloc ( drm - > dev , sizeof ( * layer ) , GFP_KERNEL ) ;
if ( ! layer )
return ERR_PTR ( - ENOMEM ) ;
2019-01-25 11:23:07 +08:00
layer - > backend = backend ;
2019-01-25 11:23:08 +08:00
if ( IS_ERR_OR_NULL ( backend - > frontend ) ) {
formats = sun4i_backend_layer_formats ;
formats_len = ARRAY_SIZE ( sun4i_backend_layer_formats ) ;
modifiers = NULL ;
}
2017-02-23 16:05:39 +08:00
/* possible crtcs are set later */
ret = drm_universal_plane_init ( drm , & layer - > plane , 0 ,
2015-10-29 09:36:23 +01:00
& sun4i_backend_layer_funcs ,
2019-01-25 11:23:08 +08:00
formats , formats_len ,
modifiers , type , NULL ) ;
2015-10-29 09:36:23 +01:00
if ( ret ) {
dev_err ( drm - > dev , " Couldn't initialize layer \n " ) ;
return ERR_PTR ( ret ) ;
}
drm_plane_helper_add ( & layer - > plane ,
& sun4i_backend_layer_helper_funcs ) ;
2018-04-11 09:39:28 +02:00
drm_plane_create_alpha_property ( & layer - > plane ) ;
2018-02-16 18:39:34 +01:00
drm_plane_create_zpos_property ( & layer - > plane , 0 , 0 ,
SUN4I_BACKEND_NUM_LAYERS - 1 ) ;
2015-10-29 09:36:23 +01:00
return layer ;
}
2017-05-15 00:30:36 +08:00
struct drm_plane * * sun4i_layers_init ( struct drm_device * drm ,
2017-05-17 22:47:17 +08:00
struct sunxi_engine * engine )
2015-10-29 09:36:23 +01:00
{
2017-05-15 00:30:36 +08:00
struct drm_plane * * planes ;
2017-05-17 22:47:17 +08:00
struct sun4i_backend * backend = engine_to_sun4i_backend ( engine ) ;
2015-10-29 09:36:23 +01:00
int i ;
2017-06-26 22:51:15 +02:00
/* We need to have a sentinel at the need, hence the overallocation */
planes = devm_kcalloc ( drm - > dev , SUN4I_BACKEND_NUM_LAYERS + 1 ,
2017-05-15 00:30:36 +08:00
sizeof ( * planes ) , GFP_KERNEL ) ;
if ( ! planes )
2015-10-29 09:36:23 +01:00
return ERR_PTR ( - ENOMEM ) ;
2018-02-16 18:39:33 +01:00
for ( i = 0 ; i < SUN4I_BACKEND_NUM_LAYERS ; i + + ) {
enum drm_plane_type type = i ? DRM_PLANE_TYPE_OVERLAY : DRM_PLANE_TYPE_PRIMARY ;
2017-02-17 11:13:28 +08:00
struct sun4i_layer * layer ;
2015-10-29 09:36:23 +01:00
2018-02-16 18:39:33 +01:00
layer = sun4i_layer_init_one ( drm , backend , type ) ;
2015-10-29 09:36:23 +01:00
if ( IS_ERR ( layer ) ) {
dev_err ( drm - > dev , " Couldn't initialize %s plane \n " ,
i ? " overlay " : " primary " ) ;
return ERR_CAST ( layer ) ;
2019-12-14 17:51:31 +08:00
}
2015-10-29 09:36:23 +01:00
layer - > id = i ;
2017-05-15 00:30:36 +08:00
planes [ i ] = & layer - > plane ;
2019-12-14 17:51:31 +08:00
}
2015-10-29 09:36:23 +01:00
2017-05-15 00:30:36 +08:00
return planes ;
2015-10-29 09:36:23 +01:00
}