2021-11-17 15:19:23 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright ( C ) 2018 Texas Instruments Incorporated - http : //www.ti.com/
* Author : Benoit Parrot < bparrot @ ti . com >
*/
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
# include "omap_dmm_tiler.h"
# include "omap_drv.h"
/*
* overlay funcs
*/
static const char * const overlay_id_to_name [ ] = {
[ OMAP_DSS_GFX ] = " gfx " ,
[ OMAP_DSS_VIDEO1 ] = " vid1 " ,
[ OMAP_DSS_VIDEO2 ] = " vid2 " ,
[ OMAP_DSS_VIDEO3 ] = " vid3 " ,
} ;
2021-11-17 15:19:26 +01:00
/*
* Find a free overlay with the required caps and supported fourcc
*/
static struct omap_hw_overlay *
omap_plane_find_free_overlay ( struct drm_device * dev , struct drm_plane * hwoverlay_to_plane [ ] ,
u32 caps , u32 fourcc )
{
struct omap_drm_private * priv = dev - > dev_private ;
int i ;
DBG ( " caps: %x fourcc: %x " , caps , fourcc ) ;
for ( i = 0 ; i < priv - > num_ovls ; i + + ) {
struct omap_hw_overlay * cur = priv - > overlays [ i ] ;
DBG ( " %d: id: %d cur->caps: %x " ,
cur - > idx , cur - > id , cur - > caps ) ;
/* skip if already in-use */
if ( hwoverlay_to_plane [ cur - > idx ] )
continue ;
/* skip if doesn't support some required caps: */
if ( caps & ~ cur - > caps )
continue ;
/* check supported format */
if ( ! dispc_ovl_color_mode_supported ( priv - > dispc ,
cur - > id , fourcc ) )
continue ;
return cur ;
}
DBG ( " no match " ) ;
return NULL ;
}
/*
* Assign a new overlay to a plane with the required caps and supported fourcc
* If a plane need a new overlay , the previous one should have been released
* with omap_overlay_release ( )
* This should be called from the plane atomic_check ( ) in order to prepare the
* next global overlay_map to be enabled when atomic transaction is valid .
*/
int omap_overlay_assign ( struct drm_atomic_state * s , struct drm_plane * plane ,
2021-11-17 15:19:28 +01:00
u32 caps , u32 fourcc , struct omap_hw_overlay * * overlay ,
struct omap_hw_overlay * * r_overlay )
2021-11-17 15:19:26 +01:00
{
/* Get the global state of the current atomic transaction */
struct omap_global_state * state = omap_get_global_state ( s ) ;
struct drm_plane * * overlay_map = state - > hwoverlay_to_plane ;
2021-11-17 15:19:28 +01:00
struct omap_hw_overlay * ovl , * r_ovl ;
2021-11-17 15:19:26 +01:00
ovl = omap_plane_find_free_overlay ( s - > dev , overlay_map , caps , fourcc ) ;
if ( ! ovl )
return - ENOMEM ;
overlay_map [ ovl - > idx ] = plane ;
* overlay = ovl ;
2021-11-17 15:19:28 +01:00
if ( r_overlay ) {
r_ovl = omap_plane_find_free_overlay ( s - > dev , overlay_map ,
caps , fourcc ) ;
if ( ! r_ovl ) {
2022-03-07 17:56:12 +08:00
overlay_map [ ovl - > idx ] = NULL ;
2021-11-17 15:19:28 +01:00
* overlay = NULL ;
return - ENOMEM ;
}
overlay_map [ r_ovl - > idx ] = plane ;
* r_overlay = r_ovl ;
}
2021-11-17 15:19:26 +01:00
DBG ( " %s: assign to plane %s caps %x " , ovl - > name , plane - > name , caps ) ;
2021-11-17 15:19:28 +01:00
if ( r_overlay ) {
DBG ( " %s: assign to right of plane %s caps %x " ,
r_ovl - > name , plane - > name , caps ) ;
}
2021-11-17 15:19:26 +01:00
return 0 ;
}
/*
* Release an overlay from a plane if the plane gets not visible or the plane
* need a new overlay if overlay caps changes .
* This should be called from the plane atomic_check ( ) in order to prepare the
* next global overlay_map to be enabled when atomic transaction is valid .
*/
void omap_overlay_release ( struct drm_atomic_state * s , struct omap_hw_overlay * overlay )
{
/* Get the global state of the current atomic transaction */
struct omap_global_state * state = omap_get_global_state ( s ) ;
struct drm_plane * * overlay_map = state - > hwoverlay_to_plane ;
if ( ! overlay )
return ;
if ( WARN_ON ( ! overlay_map [ overlay - > idx ] ) )
return ;
DBG ( " %s: release from plane %s " , overlay - > name , overlay_map [ overlay - > idx ] - > name ) ;
overlay_map [ overlay - > idx ] = NULL ;
}
/*
* Update an overlay state that was attached to a plane before the current atomic state .
* This should be called from the plane atomic_update ( ) or atomic_disable ( ) ,
* where an overlay association to a plane could have changed between the old and current
* atomic state .
*/
void omap_overlay_update_state ( struct omap_drm_private * priv ,
struct omap_hw_overlay * overlay )
{
struct omap_global_state * state = omap_get_existing_global_state ( priv ) ;
struct drm_plane * * overlay_map = state - > hwoverlay_to_plane ;
/* Check if this overlay is not used anymore, then disable it */
if ( ! overlay_map [ overlay - > idx ] ) {
DBG ( " %s: disabled " , overlay - > name ) ;
/* disable the overlay */
dispc_ovl_enable ( priv - > dispc , overlay - > id , false ) ;
}
}
2021-11-17 15:19:23 +01:00
static void omap_overlay_destroy ( struct omap_hw_overlay * overlay )
{
kfree ( overlay ) ;
}
static struct omap_hw_overlay * omap_overlay_init ( enum omap_plane_id overlay_id ,
enum omap_overlay_caps caps )
{
struct omap_hw_overlay * overlay ;
overlay = kzalloc ( sizeof ( * overlay ) , GFP_KERNEL ) ;
if ( ! overlay )
return ERR_PTR ( - ENOMEM ) ;
overlay - > name = overlay_id_to_name [ overlay_id ] ;
overlay - > id = overlay_id ;
overlay - > caps = caps ;
return overlay ;
}
int omap_hwoverlays_init ( struct omap_drm_private * priv )
{
static const enum omap_plane_id hw_plane_ids [ ] = {
OMAP_DSS_GFX , OMAP_DSS_VIDEO1 ,
OMAP_DSS_VIDEO2 , OMAP_DSS_VIDEO3 ,
} ;
u32 num_overlays = dispc_get_num_ovls ( priv - > dispc ) ;
enum omap_overlay_caps caps ;
int i , ret ;
for ( i = 0 ; i < num_overlays ; i + + ) {
struct omap_hw_overlay * overlay ;
caps = dispc_ovl_get_caps ( priv - > dispc , hw_plane_ids [ i ] ) ;
overlay = omap_overlay_init ( hw_plane_ids [ i ] , caps ) ;
if ( IS_ERR ( overlay ) ) {
ret = PTR_ERR ( overlay ) ;
dev_err ( priv - > dev , " failed to construct overlay for %s (%d) \n " ,
overlay_id_to_name [ i ] , ret ) ;
omap_hwoverlays_destroy ( priv ) ;
return ret ;
}
overlay - > idx = priv - > num_ovls ;
priv - > overlays [ priv - > num_ovls + + ] = overlay ;
}
return 0 ;
}
void omap_hwoverlays_destroy ( struct omap_drm_private * priv )
{
int i ;
for ( i = 0 ; i < priv - > num_ovls ; i + + ) {
omap_overlay_destroy ( priv - > overlays [ i ] ) ;
priv - > overlays [ i ] = NULL ;
}
priv - > num_ovls = 0 ;
}