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 >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation ; either version 2 of
* the License , or ( at your option ) any later version .
*/
# include <drm/drm_atomic_helper.h>
# include <drm/drm_plane_helper.h>
# include <drm/drmP.h>
# 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 ;
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 ,
DRM_FORMAT_ARGB8888 ) ;
sun4i_backend_update_layer_frontend ( backend , layer - > id ,
DRM_FORMAT_ARGB8888 ) ;
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 ) ;
}
2017-07-03 21:35:20 +05:30
static const struct drm_plane_helper_funcs sun4i_backend_layer_helper_funcs = {
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 ,
} ;
2018-02-16 18:39:33 +01:00
static const uint32_t sun4i_backend_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 ,
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 ,
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 ,
2018-03-01 20:18:46 +01:00
DRM_FORMAT_YUYV ,
DRM_FORMAT_YVYU ,
2016-09-19 22:17:50 +02:00
} ;
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
{
struct sun4i_layer * layer ;
int ret ;
layer = devm_kzalloc ( drm - > dev , sizeof ( * layer ) , GFP_KERNEL ) ;
if ( ! layer )
return ERR_PTR ( - ENOMEM ) ;
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 ,
2018-02-16 18:39:33 +01:00
sun4i_backend_layer_formats ,
ARRAY_SIZE ( sun4i_backend_layer_formats ) ,
NULL , 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 ) ;
2017-03-09 18:05:29 +08:00
layer - > backend = backend ;
2015-10-29 09:36:23 +01:00
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 ) ;
} ;
layer - > id = i ;
2017-05-15 00:30:36 +08:00
planes [ i ] = & layer - > plane ;
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
}