2015-01-06 11:13:28 +01:00
/*
* Copyright ( C ) 2014 Free Electrons
* Copyright ( C ) 2014 Atmel
*
* Author : Boris BREZILLON < boris . brezillon @ 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 version 2 as published by
* the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program . If not , see < http : //www.gnu.org/licenses/>.
*/
2019-06-30 08:19:03 +02:00
# include <linux/dmapool.h>
# include <linux/mfd/atmel-hlcdc.h>
# include <drm/drm_atomic.h>
# include <drm/drm_atomic_helper.h>
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_fourcc.h>
# include <drm/drm_gem_cma_helper.h>
# include <drm/drm_plane_helper.h>
2015-01-06 11:13:28 +01:00
# include "atmel_hlcdc_dc.h"
2015-02-05 16:32:33 +01:00
/**
* Atmel HLCDC Plane state structure .
*
* @ base : DRM plane state
* @ crtc_x : x position of the plane relative to the CRTC
* @ crtc_y : y position of the plane relative to the CRTC
* @ crtc_w : visible width of the plane
* @ crtc_h : visible height of the plane
* @ src_x : x buffer position
* @ src_y : y buffer position
* @ src_w : buffer width
* @ src_h : buffer height
2017-02-06 18:57:19 +01:00
* @ disc_x : x discard position
* @ disc_y : y discard position
* @ disc_w : discard width
* @ disc_h : discard height
2015-02-05 16:32:33 +01:00
* @ bpp : bytes per pixel deduced from pixel_format
* @ offsets : offsets to apply to the GEM buffers
* @ xstride : value to add to the pixel pointer between each line
* @ pstride : value to add to the pixel pointer between each pixel
* @ nplanes : number of planes ( deduced from pixel_format )
2017-02-06 18:57:19 +01:00
* @ dscrs : DMA descriptors
2015-02-05 16:32:33 +01:00
*/
struct atmel_hlcdc_plane_state {
struct drm_plane_state base ;
int crtc_x ;
int crtc_y ;
unsigned int crtc_w ;
unsigned int crtc_h ;
uint32_t src_x ;
uint32_t src_y ;
uint32_t src_w ;
uint32_t src_h ;
2015-02-06 16:25:06 +01:00
int disc_x ;
int disc_y ;
int disc_w ;
int disc_h ;
2016-03-15 18:01:08 +01:00
int ahb_id ;
2015-02-05 16:32:33 +01:00
/* These fields are private and should not be touched */
2017-02-06 18:57:19 +01:00
int bpp [ ATMEL_HLCDC_LAYER_MAX_PLANES ] ;
unsigned int offsets [ ATMEL_HLCDC_LAYER_MAX_PLANES ] ;
int xstride [ ATMEL_HLCDC_LAYER_MAX_PLANES ] ;
int pstride [ ATMEL_HLCDC_LAYER_MAX_PLANES ] ;
2015-02-05 16:32:33 +01:00
int nplanes ;
2017-02-06 18:57:19 +01:00
/* DMA descriptors. */
struct atmel_hlcdc_dma_channel_dscr * dscrs [ ATMEL_HLCDC_LAYER_MAX_PLANES ] ;
2015-02-05 16:32:33 +01:00
} ;
static inline struct atmel_hlcdc_plane_state *
drm_plane_state_to_atmel_hlcdc_plane_state ( struct drm_plane_state * s )
{
return container_of ( s , struct atmel_hlcdc_plane_state , base ) ;
}
2015-01-06 11:13:28 +01:00
# define SUBPIXEL_MASK 0xffff
static uint32_t rgb_formats [ ] = {
2017-06-22 07:03:11 +02:00
DRM_FORMAT_C8 ,
2015-01-06 11:13:28 +01:00
DRM_FORMAT_XRGB4444 ,
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_RGBA4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_RGBA8888 ,
} ;
struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
. formats = rgb_formats ,
. nformats = ARRAY_SIZE ( rgb_formats ) ,
} ;
static uint32_t rgb_and_yuv_formats [ ] = {
2017-06-22 07:03:11 +02:00
DRM_FORMAT_C8 ,
2015-01-06 11:13:28 +01:00
DRM_FORMAT_XRGB4444 ,
DRM_FORMAT_ARGB4444 ,
DRM_FORMAT_RGBA4444 ,
DRM_FORMAT_ARGB1555 ,
DRM_FORMAT_RGB565 ,
DRM_FORMAT_RGB888 ,
DRM_FORMAT_XRGB8888 ,
DRM_FORMAT_ARGB8888 ,
DRM_FORMAT_RGBA8888 ,
DRM_FORMAT_AYUV ,
DRM_FORMAT_YUYV ,
DRM_FORMAT_UYVY ,
DRM_FORMAT_YVYU ,
DRM_FORMAT_VYUY ,
DRM_FORMAT_NV21 ,
DRM_FORMAT_NV61 ,
DRM_FORMAT_YUV422 ,
DRM_FORMAT_YUV420 ,
} ;
struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
. formats = rgb_and_yuv_formats ,
. nformats = ARRAY_SIZE ( rgb_and_yuv_formats ) ,
} ;
static int atmel_hlcdc_format_to_plane_mode ( u32 format , u32 * mode )
{
switch ( format ) {
2017-06-22 07:03:11 +02:00
case DRM_FORMAT_C8 :
* mode = ATMEL_HLCDC_C8_MODE ;
break ;
2015-01-06 11:13:28 +01:00
case DRM_FORMAT_XRGB4444 :
* mode = ATMEL_HLCDC_XRGB4444_MODE ;
break ;
case DRM_FORMAT_ARGB4444 :
* mode = ATMEL_HLCDC_ARGB4444_MODE ;
break ;
case DRM_FORMAT_RGBA4444 :
* mode = ATMEL_HLCDC_RGBA4444_MODE ;
break ;
case DRM_FORMAT_RGB565 :
* mode = ATMEL_HLCDC_RGB565_MODE ;
break ;
case DRM_FORMAT_RGB888 :
* mode = ATMEL_HLCDC_RGB888_MODE ;
break ;
case DRM_FORMAT_ARGB1555 :
* mode = ATMEL_HLCDC_ARGB1555_MODE ;
break ;
case DRM_FORMAT_XRGB8888 :
* mode = ATMEL_HLCDC_XRGB8888_MODE ;
break ;
case DRM_FORMAT_ARGB8888 :
* mode = ATMEL_HLCDC_ARGB8888_MODE ;
break ;
case DRM_FORMAT_RGBA8888 :
* mode = ATMEL_HLCDC_RGBA8888_MODE ;
break ;
case DRM_FORMAT_AYUV :
* mode = ATMEL_HLCDC_AYUV_MODE ;
break ;
case DRM_FORMAT_YUYV :
* mode = ATMEL_HLCDC_YUYV_MODE ;
break ;
case DRM_FORMAT_UYVY :
* mode = ATMEL_HLCDC_UYVY_MODE ;
break ;
case DRM_FORMAT_YVYU :
* mode = ATMEL_HLCDC_YVYU_MODE ;
break ;
case DRM_FORMAT_VYUY :
* mode = ATMEL_HLCDC_VYUY_MODE ;
break ;
case DRM_FORMAT_NV21 :
* mode = ATMEL_HLCDC_NV21_MODE ;
break ;
case DRM_FORMAT_NV61 :
* mode = ATMEL_HLCDC_NV61_MODE ;
break ;
case DRM_FORMAT_YUV420 :
* mode = ATMEL_HLCDC_YUV420_MODE ;
break ;
case DRM_FORMAT_YUV422 :
* mode = ATMEL_HLCDC_YUV422_MODE ;
break ;
default :
return - ENOTSUPP ;
}
return 0 ;
}
static u32 heo_downscaling_xcoef [ ] = {
0x11343311 ,
0x000000f7 ,
0x1635300c ,
0x000000f9 ,
0x1b362c08 ,
0x000000fb ,
0x1f372804 ,
0x000000fe ,
0x24382400 ,
0x00000000 ,
0x28371ffe ,
0x00000004 ,
0x2c361bfb ,
0x00000008 ,
0x303516f9 ,
0x0000000c ,
} ;
static u32 heo_downscaling_ycoef [ ] = {
0x00123737 ,
0x00173732 ,
0x001b382d ,
0x001f3928 ,
0x00243824 ,
0x0028391f ,
0x002d381b ,
0x00323717 ,
} ;
static u32 heo_upscaling_xcoef [ ] = {
0xf74949f7 ,
0x00000000 ,
0xf55f33fb ,
0x000000fe ,
0xf5701efe ,
0x000000ff ,
0xf87c0dff ,
0x00000000 ,
0x00800000 ,
0x00000000 ,
0x0d7cf800 ,
0x000000ff ,
0x1e70f5ff ,
0x000000fe ,
0x335ff5fe ,
0x000000fb ,
} ;
static u32 heo_upscaling_ycoef [ ] = {
0x00004040 ,
0x00075920 ,
0x00056f0c ,
0x00027b03 ,
0x00008000 ,
0x00037b02 ,
0x000c6f05 ,
0x00205907 ,
} ;
2017-02-06 18:57:19 +01:00
# define ATMEL_HLCDC_XPHIDEF 4
# define ATMEL_HLCDC_YPHIDEF 4
static u32 atmel_hlcdc_plane_phiscaler_get_factor ( u32 srcsize ,
u32 dstsize ,
u32 phidef )
{
u32 factor , max_memsize ;
factor = ( 256 * ( ( 8 * ( srcsize - 1 ) ) - phidef ) ) / ( dstsize - 1 ) ;
max_memsize = ( ( factor * ( dstsize - 1 ) ) + ( 256 * phidef ) ) / 2048 ;
if ( max_memsize > srcsize - 1 )
factor - - ;
return factor ;
}
2015-01-06 11:13:28 +01:00
static void
2017-02-06 18:57:19 +01:00
atmel_hlcdc_plane_scaler_set_phicoeff ( struct atmel_hlcdc_plane * plane ,
const u32 * coeff_tab , int size ,
unsigned int cfg_offs )
2015-01-06 11:13:28 +01:00
{
2017-02-06 18:57:19 +01:00
int i ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
for ( i = 0 ; i < size ; i + + )
atmel_hlcdc_layer_write_cfg ( & plane - > layer , cfg_offs + i ,
coeff_tab [ i ] ) ;
}
void atmel_hlcdc_plane_setup_scaler ( struct atmel_hlcdc_plane * plane ,
struct atmel_hlcdc_plane_state * state )
{
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
u32 xfactor , yfactor ;
if ( ! desc - > layout . scaler_config )
return ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
if ( state - > crtc_w = = state - > src_w & & state - > crtc_h = = state - > src_h ) {
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . scaler_config , 0 ) ;
return ;
}
if ( desc - > layout . phicoeffs . x ) {
xfactor = atmel_hlcdc_plane_phiscaler_get_factor ( state - > src_w ,
state - > crtc_w ,
ATMEL_HLCDC_XPHIDEF ) ;
yfactor = atmel_hlcdc_plane_phiscaler_get_factor ( state - > src_h ,
state - > crtc_h ,
ATMEL_HLCDC_YPHIDEF ) ;
atmel_hlcdc_plane_scaler_set_phicoeff ( plane ,
state - > crtc_w < state - > src_w ?
heo_downscaling_xcoef :
heo_upscaling_xcoef ,
ARRAY_SIZE ( heo_upscaling_xcoef ) ,
desc - > layout . phicoeffs . x ) ;
atmel_hlcdc_plane_scaler_set_phicoeff ( plane ,
state - > crtc_h < state - > src_h ?
heo_downscaling_ycoef :
heo_upscaling_ycoef ,
ARRAY_SIZE ( heo_upscaling_ycoef ) ,
desc - > layout . phicoeffs . y ) ;
2016-05-27 16:09:25 +02:00
} else {
2017-02-06 18:57:19 +01:00
xfactor = ( 1024 * state - > src_w ) / state - > crtc_w ;
yfactor = ( 1024 * state - > src_h ) / state - > crtc_h ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_write_cfg ( & plane - > layer , desc - > layout . scaler_config ,
ATMEL_HLCDC_LAYER_SCALER_ENABLE |
ATMEL_HLCDC_LAYER_SCALER_FACTORS ( xfactor ,
yfactor ) ) ;
}
static void
atmel_hlcdc_plane_update_pos_and_size ( struct atmel_hlcdc_plane * plane ,
struct atmel_hlcdc_plane_state * state )
{
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
if ( desc - > layout . size )
atmel_hlcdc_layer_write_cfg ( & plane - > layer , desc - > layout . size ,
ATMEL_HLCDC_LAYER_SIZE ( state - > crtc_w ,
state - > crtc_h ) ) ;
if ( desc - > layout . memsize )
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . memsize ,
ATMEL_HLCDC_LAYER_SIZE ( state - > src_w ,
state - > src_h ) ) ;
if ( desc - > layout . pos )
atmel_hlcdc_layer_write_cfg ( & plane - > layer , desc - > layout . pos ,
ATMEL_HLCDC_LAYER_POS ( state - > crtc_x ,
state - > crtc_y ) ) ;
atmel_hlcdc_plane_setup_scaler ( plane , state ) ;
2015-01-06 11:13:28 +01:00
}
static void
atmel_hlcdc_plane_update_general_settings ( struct atmel_hlcdc_plane * plane ,
2015-02-05 16:32:33 +01:00
struct atmel_hlcdc_plane_state * state )
2015-01-06 11:13:28 +01:00
{
2017-02-06 18:57:19 +01:00
unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state - > ahb_id ;
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
2017-12-22 15:31:27 +01:00
const struct drm_format_info * format = state - > base . fb - > format ;
2017-02-06 18:57:19 +01:00
/*
* Rotation optimization is not working on RGB888 ( rotation is still
* working but without any optimization ) .
*/
2017-12-22 15:31:27 +01:00
if ( format - > format = = DRM_FORMAT_RGB888 )
2017-02-06 18:57:19 +01:00
cfg | = ATMEL_HLCDC_LAYER_DMA_ROTDIS ;
atmel_hlcdc_layer_write_cfg ( & plane - > layer , ATMEL_HLCDC_LAYER_DMA_CFG ,
cfg ) ;
2019-07-09 15:35:12 +00:00
cfg = ATMEL_HLCDC_LAYER_DMA | ATMEL_HLCDC_LAYER_REP ;
2015-01-06 11:13:28 +01:00
if ( plane - > base . type ! = DRM_PLANE_TYPE_PRIMARY ) {
cfg | = ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
ATMEL_HLCDC_LAYER_ITER ;
2017-12-22 15:31:27 +01:00
if ( format - > has_alpha )
2015-01-06 11:13:28 +01:00
cfg | = ATMEL_HLCDC_LAYER_LAEN ;
else
2015-02-05 16:32:33 +01:00
cfg | = ATMEL_HLCDC_LAYER_GAEN |
2019-04-25 12:36:39 +00:00
ATMEL_HLCDC_LAYER_GA ( state - > base . alpha ) ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
if ( state - > disc_h & & state - > disc_w )
cfg | = ATMEL_HLCDC_LAYER_DISCEN ;
atmel_hlcdc_layer_write_cfg ( & plane - > layer , desc - > layout . general_config ,
cfg ) ;
2015-01-06 11:13:28 +01:00
}
static void atmel_hlcdc_plane_update_format ( struct atmel_hlcdc_plane * plane ,
2015-02-05 16:32:33 +01:00
struct atmel_hlcdc_plane_state * state )
2015-01-06 11:13:28 +01:00
{
u32 cfg ;
int ret ;
2016-12-14 23:32:55 +02:00
ret = atmel_hlcdc_format_to_plane_mode ( state - > base . fb - > format - > format ,
2015-02-05 16:32:33 +01:00
& cfg ) ;
2015-01-06 11:13:28 +01:00
if ( ret )
return ;
2016-12-14 23:32:55 +02:00
if ( ( state - > base . fb - > format - > format = = DRM_FORMAT_YUV422 | |
state - > base . fb - > format - > format = = DRM_FORMAT_NV61 ) & &
2016-09-26 19:30:46 +03:00
drm_rotation_90_or_270 ( state - > base . rotation ) )
2015-01-06 11:13:28 +01:00
cfg | = ATMEL_HLCDC_YUV422ROT ;
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
ATMEL_HLCDC_LAYER_FORMAT_CFG , cfg ) ;
2015-01-06 11:13:28 +01:00
}
2018-04-05 18:13:50 +03:00
static void atmel_hlcdc_plane_update_clut ( struct atmel_hlcdc_plane * plane ,
struct atmel_hlcdc_plane_state * state )
2017-06-22 07:03:11 +02:00
{
2018-04-05 18:13:50 +03:00
struct drm_crtc * crtc = state - > base . crtc ;
2017-06-22 07:03:11 +02:00
struct drm_color_lut * lut ;
int idx ;
if ( ! crtc | | ! crtc - > state )
return ;
if ( ! crtc - > state - > color_mgmt_changed | | ! crtc - > state - > gamma_lut )
return ;
lut = ( struct drm_color_lut * ) crtc - > state - > gamma_lut - > data ;
for ( idx = 0 ; idx < ATMEL_HLCDC_CLUT_SIZE ; idx + + , lut + + ) {
u32 val = ( ( lut - > red < < 8 ) & 0xff0000 ) |
( lut - > green & 0xff00 ) |
( lut - > blue > > 8 ) ;
atmel_hlcdc_layer_write_clut ( & plane - > layer , idx , val ) ;
}
}
2015-01-06 11:13:28 +01:00
static void atmel_hlcdc_plane_update_buffers ( struct atmel_hlcdc_plane * plane ,
2015-02-05 16:32:33 +01:00
struct atmel_hlcdc_plane_state * state )
2015-01-06 11:13:28 +01:00
{
2017-02-06 18:57:19 +01:00
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
struct drm_framebuffer * fb = state - > base . fb ;
u32 sr ;
2015-01-06 11:13:28 +01:00
int i ;
2017-02-06 18:57:19 +01:00
sr = atmel_hlcdc_layer_read_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_CHSR ) ;
2015-01-06 11:13:28 +01:00
2015-02-05 16:32:33 +01:00
for ( i = 0 ; i < state - > nplanes ; i + + ) {
2017-02-06 18:57:19 +01:00
struct drm_gem_cma_object * gem = drm_fb_cma_get_gem_obj ( fb , i ) ;
state - > dscrs [ i ] - > addr = gem - > paddr + state - > offsets [ i ] ;
atmel_hlcdc_layer_write_reg ( & plane - > layer ,
ATMEL_HLCDC_LAYER_PLANE_HEAD ( i ) ,
state - > dscrs [ i ] - > self ) ;
if ( ! ( sr & ATMEL_HLCDC_LAYER_EN ) ) {
atmel_hlcdc_layer_write_reg ( & plane - > layer ,
ATMEL_HLCDC_LAYER_PLANE_ADDR ( i ) ,
state - > dscrs [ i ] - > addr ) ;
atmel_hlcdc_layer_write_reg ( & plane - > layer ,
ATMEL_HLCDC_LAYER_PLANE_CTRL ( i ) ,
state - > dscrs [ i ] - > ctrl ) ;
atmel_hlcdc_layer_write_reg ( & plane - > layer ,
ATMEL_HLCDC_LAYER_PLANE_NEXT ( i ) ,
state - > dscrs [ i ] - > self ) ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
if ( desc - > layout . xstride [ i ] )
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . xstride [ i ] ,
state - > xstride [ i ] ) ;
if ( desc - > layout . pstride [ i ] )
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . pstride [ i ] ,
state - > pstride [ i ] ) ;
2015-01-06 11:13:28 +01:00
}
}
2016-03-15 18:01:08 +01:00
int atmel_hlcdc_plane_prepare_ahb_routing ( struct drm_crtc_state * c_state )
{
unsigned int ahb_load [ 2 ] = { } ;
struct drm_plane * plane ;
drm_atomic_crtc_state_for_each_plane ( plane , c_state ) {
struct atmel_hlcdc_plane_state * plane_state ;
struct drm_plane_state * plane_s ;
unsigned int pixels , load = 0 ;
int i ;
plane_s = drm_atomic_get_plane_state ( c_state - > state , plane ) ;
if ( IS_ERR ( plane_s ) )
return PTR_ERR ( plane_s ) ;
plane_state =
drm_plane_state_to_atmel_hlcdc_plane_state ( plane_s ) ;
pixels = ( plane_state - > src_w * plane_state - > src_h ) -
( plane_state - > disc_w * plane_state - > disc_h ) ;
for ( i = 0 ; i < plane_state - > nplanes ; i + + )
load + = pixels * plane_state - > bpp [ i ] ;
if ( ahb_load [ 0 ] < = ahb_load [ 1 ] )
plane_state - > ahb_id = 0 ;
else
plane_state - > ahb_id = 1 ;
ahb_load [ plane_state - > ahb_id ] + = load ;
}
return 0 ;
}
2015-02-06 16:25:06 +01:00
int
atmel_hlcdc_plane_prepare_disc_area ( struct drm_crtc_state * c_state )
{
int disc_x = 0 , disc_y = 0 , disc_w = 0 , disc_h = 0 ;
const struct atmel_hlcdc_layer_cfg_layout * layout ;
struct atmel_hlcdc_plane_state * primary_state ;
struct drm_plane_state * primary_s ;
struct atmel_hlcdc_plane * primary ;
struct drm_plane * ovl ;
primary = drm_plane_to_atmel_hlcdc_plane ( c_state - > crtc - > primary ) ;
layout = & primary - > layer . desc - > layout ;
if ( ! layout - > disc_pos | | ! layout - > disc_size )
return 0 ;
primary_s = drm_atomic_get_plane_state ( c_state - > state ,
& primary - > base ) ;
if ( IS_ERR ( primary_s ) )
return PTR_ERR ( primary_s ) ;
primary_state = drm_plane_state_to_atmel_hlcdc_plane_state ( primary_s ) ;
drm_atomic_crtc_state_for_each_plane ( ovl , c_state ) {
struct atmel_hlcdc_plane_state * ovl_state ;
struct drm_plane_state * ovl_s ;
if ( ovl = = c_state - > crtc - > primary )
continue ;
ovl_s = drm_atomic_get_plane_state ( c_state - > state , ovl ) ;
if ( IS_ERR ( ovl_s ) )
return PTR_ERR ( ovl_s ) ;
ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state ( ovl_s ) ;
2019-01-10 15:10:44 +00:00
if ( ! ovl_s - > visible | |
! ovl_s - > fb | |
2017-12-22 15:31:27 +01:00
ovl_s - > fb - > format - > has_alpha | |
2018-04-11 09:39:26 +02:00
ovl_s - > alpha ! = DRM_BLEND_ALPHA_OPAQUE )
2015-02-06 16:25:06 +01:00
continue ;
/* TODO: implement a smarter hidden area detection */
if ( ovl_state - > crtc_h * ovl_state - > crtc_w < disc_h * disc_w )
continue ;
disc_x = ovl_state - > crtc_x ;
disc_y = ovl_state - > crtc_y ;
disc_h = ovl_state - > crtc_h ;
disc_w = ovl_state - > crtc_w ;
}
primary_state - > disc_x = disc_x ;
primary_state - > disc_y = disc_y ;
primary_state - > disc_w = disc_w ;
primary_state - > disc_h = disc_h ;
return 0 ;
}
static void
atmel_hlcdc_plane_update_disc_area ( struct atmel_hlcdc_plane * plane ,
struct atmel_hlcdc_plane_state * state )
{
2017-02-06 18:57:19 +01:00
const struct atmel_hlcdc_layer_cfg_layout * layout ;
2015-02-06 16:25:06 +01:00
2017-02-06 18:57:19 +01:00
layout = & plane - > layer . desc - > layout ;
if ( ! layout - > disc_pos | | ! layout - > disc_size )
2015-02-06 16:25:06 +01:00
return ;
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_write_cfg ( & plane - > layer , layout - > disc_pos ,
ATMEL_HLCDC_LAYER_DISC_POS ( state - > disc_x ,
state - > disc_y ) ) ;
2015-02-06 16:25:06 +01:00
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_write_cfg ( & plane - > layer , layout - > disc_size ,
ATMEL_HLCDC_LAYER_DISC_SIZE ( state - > disc_w ,
state - > disc_h ) ) ;
2015-02-06 16:25:06 +01:00
}
2015-02-05 16:32:33 +01:00
static int atmel_hlcdc_plane_atomic_check ( struct drm_plane * p ,
struct drm_plane_state * s )
2015-01-06 11:13:28 +01:00
{
struct atmel_hlcdc_plane * plane = drm_plane_to_atmel_hlcdc_plane ( p ) ;
2015-02-05 16:32:33 +01:00
struct atmel_hlcdc_plane_state * state =
drm_plane_state_to_atmel_hlcdc_plane_state ( s ) ;
2017-02-06 18:57:19 +01:00
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
2015-02-05 16:32:33 +01:00
struct drm_framebuffer * fb = state - > base . fb ;
const struct drm_display_mode * mode ;
struct drm_crtc_state * crtc_state ;
2015-01-06 11:13:28 +01:00
unsigned int tmp ;
2019-01-10 15:10:44 +00:00
int ret ;
2015-01-06 11:13:28 +01:00
int i ;
2015-02-05 16:32:33 +01:00
if ( ! state - > base . crtc | | ! fb )
return 0 ;
2016-03-15 13:46:28 +01:00
crtc_state = drm_atomic_get_existing_crtc_state ( s - > state , s - > crtc ) ;
2015-02-05 16:32:33 +01:00
mode = & crtc_state - > adjusted_mode ;
2019-01-10 15:10:44 +00:00
ret = drm_atomic_helper_check_plane_state ( s , crtc_state ,
( 1 < < 16 ) / 2048 ,
INT_MAX , true , true ) ;
if ( ret | | ! s - > visible )
return ret ;
state - > src_x = s - > src . x1 ;
state - > src_y = s - > src . y1 ;
state - > src_w = drm_rect_width ( & s - > src ) ;
state - > src_h = drm_rect_height ( & s - > src ) ;
state - > crtc_x = s - > dst . x1 ;
state - > crtc_y = s - > dst . y1 ;
state - > crtc_w = drm_rect_width ( & s - > dst ) ;
state - > crtc_h = drm_rect_height ( & s - > dst ) ;
2015-02-05 16:32:33 +01:00
if ( ( state - > src_x | state - > src_y | state - > src_w | state - > src_h ) &
2015-01-06 11:13:28 +01:00
SUBPIXEL_MASK )
return - EINVAL ;
2015-02-05 16:32:33 +01:00
state - > src_x > > = 16 ;
state - > src_y > > = 16 ;
state - > src_w > > = 16 ;
state - > src_h > > = 16 ;
2015-01-06 11:13:28 +01:00
2016-12-14 23:30:22 +02:00
state - > nplanes = fb - > format - > num_planes ;
2017-02-06 18:57:19 +01:00
if ( state - > nplanes > ATMEL_HLCDC_LAYER_MAX_PLANES )
2015-01-06 11:13:28 +01:00
return - EINVAL ;
2015-02-05 16:32:33 +01:00
for ( i = 0 ; i < state - > nplanes ; i + + ) {
2015-01-06 11:13:28 +01:00
unsigned int offset = 0 ;
2019-05-16 12:31:48 +02:00
int xdiv = i ? fb - > format - > hsub : 1 ;
int ydiv = i ? fb - > format - > vsub : 1 ;
2015-01-06 11:13:28 +01:00
2016-12-14 23:30:57 +02:00
state - > bpp [ i ] = fb - > format - > cpp [ i ] ;
2015-02-05 16:32:33 +01:00
if ( ! state - > bpp [ i ] )
2015-01-06 11:13:28 +01:00
return - EINVAL ;
2017-05-19 16:50:17 -04:00
switch ( state - > base . rotation & DRM_MODE_ROTATE_MASK ) {
case DRM_MODE_ROTATE_90 :
2019-01-10 15:10:44 +00:00
offset = ( state - > src_y / ydiv ) *
2019-01-10 15:10:34 +00:00
fb - > pitches [ i ] ;
2019-01-10 15:10:44 +00:00
offset + = ( ( state - > src_x + state - > src_w - 1 ) /
2019-01-10 15:10:34 +00:00
xdiv ) * state - > bpp [ i ] ;
2019-01-10 15:10:44 +00:00
state - > xstride [ i ] = - ( ( ( state - > src_h - 1 ) / ydiv ) *
2019-01-10 15:10:34 +00:00
fb - > pitches [ i ] ) -
( 2 * state - > bpp [ i ] ) ;
state - > pstride [ i ] = fb - > pitches [ i ] - state - > bpp [ i ] ;
2015-01-06 11:13:28 +01:00
break ;
2017-05-19 16:50:17 -04:00
case DRM_MODE_ROTATE_180 :
2019-01-10 15:10:44 +00:00
offset = ( ( state - > src_y + state - > src_h - 1 ) /
2015-02-05 16:32:33 +01:00
ydiv ) * fb - > pitches [ i ] ;
2019-01-10 15:10:44 +00:00
offset + = ( ( state - > src_x + state - > src_w - 1 ) /
2015-02-05 16:32:33 +01:00
xdiv ) * state - > bpp [ i ] ;
2019-01-10 15:10:44 +00:00
state - > xstride [ i ] = ( ( ( ( state - > src_w - 1 ) / xdiv ) - 1 ) *
2015-02-05 16:32:33 +01:00
state - > bpp [ i ] ) - fb - > pitches [ i ] ;
state - > pstride [ i ] = - 2 * state - > bpp [ i ] ;
2015-01-06 11:13:28 +01:00
break ;
2017-05-19 16:50:17 -04:00
case DRM_MODE_ROTATE_270 :
2019-01-10 15:10:44 +00:00
offset = ( ( state - > src_y + state - > src_h - 1 ) /
2019-01-10 15:10:34 +00:00
ydiv ) * fb - > pitches [ i ] ;
2019-01-10 15:10:44 +00:00
offset + = ( state - > src_x / xdiv ) * state - > bpp [ i ] ;
state - > xstride [ i ] = ( ( state - > src_h - 1 ) / ydiv ) *
2019-01-10 15:10:34 +00:00
fb - > pitches [ i ] ;
state - > pstride [ i ] = - fb - > pitches [ i ] - state - > bpp [ i ] ;
2015-01-06 11:13:28 +01:00
break ;
2017-05-19 16:50:17 -04:00
case DRM_MODE_ROTATE_0 :
2015-01-06 11:13:28 +01:00
default :
2019-01-10 15:10:44 +00:00
offset = ( state - > src_y / ydiv ) * fb - > pitches [ i ] ;
offset + = ( state - > src_x / xdiv ) * state - > bpp [ i ] ;
2015-02-05 16:32:33 +01:00
state - > xstride [ i ] = fb - > pitches [ i ] -
2019-01-10 15:10:44 +00:00
( ( state - > src_w / xdiv ) *
2015-02-05 16:32:33 +01:00
state - > bpp [ i ] ) ;
state - > pstride [ i ] = 0 ;
2015-01-06 11:13:28 +01:00
break ;
}
2015-02-05 16:32:33 +01:00
state - > offsets [ i ] = offset + fb - > offsets [ i ] ;
2015-01-06 11:13:28 +01:00
}
2019-01-10 15:10:44 +00:00
/*
* Swap width and size in case of 90 or 270 degrees rotation
*/
if ( drm_rotation_90_or_270 ( state - > base . rotation ) ) {
tmp = state - > src_w ;
state - > src_w = state - > src_h ;
state - > src_h = tmp ;
}
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
if ( ! desc - > layout . size & &
2015-02-05 16:32:33 +01:00
( mode - > hdisplay ! = state - > crtc_w | |
mode - > vdisplay ! = state - > crtc_h ) )
return - EINVAL ;
2015-01-06 11:13:28 +01:00
2015-02-05 16:32:33 +01:00
if ( ( state - > crtc_h ! = state - > src_h | | state - > crtc_w ! = state - > src_w ) & &
2017-02-06 18:57:19 +01:00
( ! desc - > layout . memsize | |
2017-12-22 15:31:27 +01:00
state - > base . fb - > format - > has_alpha ) )
2015-02-05 16:32:33 +01:00
return - EINVAL ;
2015-01-06 11:13:28 +01:00
2019-01-10 15:10:44 +00:00
return 0 ;
}
2015-02-05 16:32:33 +01:00
2019-01-10 15:10:44 +00:00
static void atmel_hlcdc_plane_atomic_disable ( struct drm_plane * p ,
struct drm_plane_state * old_state )
{
struct atmel_hlcdc_plane * plane = drm_plane_to_atmel_hlcdc_plane ( p ) ;
2015-01-06 11:13:28 +01:00
2019-01-10 15:10:44 +00:00
/* Disable interrupts */
atmel_hlcdc_layer_write_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_IDR ,
0xffffffff ) ;
/* Disable the layer */
atmel_hlcdc_layer_write_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_CHDR ,
ATMEL_HLCDC_LAYER_RST |
ATMEL_HLCDC_LAYER_A2Q |
ATMEL_HLCDC_LAYER_UPDATE ) ;
/* Clear all pending interrupts */
atmel_hlcdc_layer_read_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_ISR ) ;
2015-01-06 11:13:28 +01:00
}
2015-02-05 16:32:33 +01:00
static void atmel_hlcdc_plane_atomic_update ( struct drm_plane * p ,
struct drm_plane_state * old_s )
2015-01-06 11:13:28 +01:00
{
2015-02-05 16:32:33 +01:00
struct atmel_hlcdc_plane * plane = drm_plane_to_atmel_hlcdc_plane ( p ) ;
struct atmel_hlcdc_plane_state * state =
drm_plane_state_to_atmel_hlcdc_plane_state ( p - > state ) ;
2017-02-06 18:57:19 +01:00
u32 sr ;
2015-02-05 16:32:33 +01:00
if ( ! p - > state - > crtc | | ! p - > state - > fb )
return ;
2019-01-10 15:10:44 +00:00
if ( ! state - > base . visible ) {
atmel_hlcdc_plane_atomic_disable ( p , old_s ) ;
return ;
}
2015-02-05 16:32:33 +01:00
atmel_hlcdc_plane_update_pos_and_size ( plane , state ) ;
atmel_hlcdc_plane_update_general_settings ( plane , state ) ;
atmel_hlcdc_plane_update_format ( plane , state ) ;
2018-04-05 18:13:50 +03:00
atmel_hlcdc_plane_update_clut ( plane , state ) ;
2015-02-05 16:32:33 +01:00
atmel_hlcdc_plane_update_buffers ( plane , state ) ;
2015-02-06 16:25:06 +01:00
atmel_hlcdc_plane_update_disc_area ( plane , state ) ;
2015-02-05 16:32:33 +01:00
2017-02-06 18:57:19 +01:00
/* Enable the overrun interrupts. */
atmel_hlcdc_layer_write_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_IER ,
ATMEL_HLCDC_LAYER_OVR_IRQ ( 0 ) |
ATMEL_HLCDC_LAYER_OVR_IRQ ( 1 ) |
ATMEL_HLCDC_LAYER_OVR_IRQ ( 2 ) ) ;
/* Apply the new config at the next SOF event. */
sr = atmel_hlcdc_layer_read_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_CHSR ) ;
atmel_hlcdc_layer_write_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_CHER ,
ATMEL_HLCDC_LAYER_UPDATE |
( sr & ATMEL_HLCDC_LAYER_EN ?
ATMEL_HLCDC_LAYER_A2Q : ATMEL_HLCDC_LAYER_EN ) ) ;
2015-01-06 11:13:28 +01:00
}
2018-04-11 09:39:26 +02:00
static int atmel_hlcdc_plane_init_properties ( struct atmel_hlcdc_plane * plane )
2015-01-06 11:13:28 +01:00
{
2017-02-06 18:57:19 +01:00
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
2015-01-06 11:13:28 +01:00
if ( desc - > type = = ATMEL_HLCDC_OVERLAY_LAYER | |
2018-04-11 09:39:26 +02:00
desc - > type = = ATMEL_HLCDC_CURSOR_LAYER ) {
int ret ;
ret = drm_plane_create_alpha_property ( & plane - > base ) ;
if ( ret )
return ret ;
}
2015-01-06 11:13:28 +01:00
2018-06-17 10:48:22 +02:00
if ( desc - > layout . xstride [ 0 ] & & desc - > layout . pstride [ 0 ] ) {
2016-09-26 19:30:50 +03:00
int ret ;
ret = drm_plane_create_rotation_property ( & plane - > base ,
2017-05-19 16:50:17 -04:00
DRM_MODE_ROTATE_0 ,
DRM_MODE_ROTATE_0 |
DRM_MODE_ROTATE_90 |
DRM_MODE_ROTATE_180 |
DRM_MODE_ROTATE_270 ) ;
2016-09-26 19:30:50 +03:00
if ( ret )
return ret ;
}
2015-01-06 11:13:28 +01:00
if ( desc - > layout . csc ) {
/*
* TODO : decare a " yuv-to-rgb-conv-factors " property to let
* userspace modify these factors ( using a BLOB property ? ) .
*/
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . csc ,
0x4c900091 ) ;
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . csc + 1 ,
0x7a5f5090 ) ;
atmel_hlcdc_layer_write_cfg ( & plane - > layer ,
desc - > layout . csc + 2 ,
0x40040890 ) ;
2015-01-06 11:13:28 +01:00
}
2016-09-26 19:30:50 +03:00
return 0 ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
void atmel_hlcdc_plane_irq ( struct atmel_hlcdc_plane * plane )
{
const struct atmel_hlcdc_layer_desc * desc = plane - > layer . desc ;
u32 isr ;
isr = atmel_hlcdc_layer_read_reg ( & plane - > layer , ATMEL_HLCDC_LAYER_ISR ) ;
/*
* There ' s not much we can do in case of overrun except informing
* the user . However , we are in interrupt context here , hence the
* use of dev_dbg ( ) .
*/
if ( isr &
( ATMEL_HLCDC_LAYER_OVR_IRQ ( 0 ) | ATMEL_HLCDC_LAYER_OVR_IRQ ( 1 ) |
ATMEL_HLCDC_LAYER_OVR_IRQ ( 2 ) ) )
dev_dbg ( plane - > base . dev - > dev , " overrun on plane %s \n " ,
desc - > name ) ;
}
2017-07-03 21:53:54 +05:30
static const struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
2015-02-05 16:32:33 +01:00
. atomic_check = atmel_hlcdc_plane_atomic_check ,
. atomic_update = atmel_hlcdc_plane_atomic_update ,
. atomic_disable = atmel_hlcdc_plane_atomic_disable ,
} ;
2017-02-06 18:57:19 +01:00
static int atmel_hlcdc_plane_alloc_dscrs ( struct drm_plane * p ,
struct atmel_hlcdc_plane_state * state )
{
struct atmel_hlcdc_dc * dc = p - > dev - > dev_private ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( state - > dscrs ) ; i + + ) {
struct atmel_hlcdc_dma_channel_dscr * dscr ;
dma_addr_t dscr_dma ;
dscr = dma_pool_alloc ( dc - > dscrpool , GFP_KERNEL , & dscr_dma ) ;
if ( ! dscr )
goto err ;
dscr - > addr = 0 ;
dscr - > next = dscr_dma ;
dscr - > self = dscr_dma ;
dscr - > ctrl = ATMEL_HLCDC_LAYER_DFETCH ;
state - > dscrs [ i ] = dscr ;
}
return 0 ;
err :
for ( i - - ; i > = 0 ; i - - ) {
dma_pool_free ( dc - > dscrpool , state - > dscrs [ i ] ,
state - > dscrs [ i ] - > self ) ;
}
return - ENOMEM ;
}
2015-02-05 16:32:33 +01:00
static void atmel_hlcdc_plane_reset ( struct drm_plane * p )
{
struct atmel_hlcdc_plane_state * state ;
if ( p - > state ) {
state = drm_plane_state_to_atmel_hlcdc_plane_state ( p - > state ) ;
if ( state - > base . fb )
2017-08-03 14:58:20 +03:00
drm_framebuffer_put ( state - > base . fb ) ;
2015-02-05 16:32:33 +01:00
kfree ( state ) ;
p - > state = NULL ;
}
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( state ) {
2017-02-06 18:57:19 +01:00
if ( atmel_hlcdc_plane_alloc_dscrs ( p , state ) ) {
kfree ( state ) ;
dev_err ( p - > dev - > dev ,
" Failed to allocate initial plane state \n " ) ;
return ;
}
2018-08-04 17:15:24 +01:00
__drm_atomic_helper_plane_reset ( p , & state - > base ) ;
2015-02-05 16:32:33 +01:00
}
}
static struct drm_plane_state *
atmel_hlcdc_plane_atomic_duplicate_state ( struct drm_plane * p )
{
struct atmel_hlcdc_plane_state * state =
drm_plane_state_to_atmel_hlcdc_plane_state ( p - > state ) ;
struct atmel_hlcdc_plane_state * copy ;
copy = kmemdup ( state , sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! copy )
return NULL ;
2017-02-06 18:57:19 +01:00
if ( atmel_hlcdc_plane_alloc_dscrs ( p , copy ) ) {
kfree ( copy ) ;
return NULL ;
}
2015-02-06 16:25:06 +01:00
2015-02-05 16:32:33 +01:00
if ( copy - > base . fb )
2017-08-03 14:58:20 +03:00
drm_framebuffer_get ( copy - > base . fb ) ;
2015-02-05 16:32:33 +01:00
return & copy - > base ;
}
2017-02-06 18:57:19 +01:00
static void atmel_hlcdc_plane_atomic_destroy_state ( struct drm_plane * p ,
2015-02-05 16:32:33 +01:00
struct drm_plane_state * s )
{
struct atmel_hlcdc_plane_state * state =
drm_plane_state_to_atmel_hlcdc_plane_state ( s ) ;
2017-02-06 18:57:19 +01:00
struct atmel_hlcdc_dc * dc = p - > dev - > dev_private ;
int i ;
for ( i = 0 ; i < ARRAY_SIZE ( state - > dscrs ) ; i + + ) {
dma_pool_free ( dc - > dscrpool , state - > dscrs [ i ] ,
state - > dscrs [ i ] - > self ) ;
}
2015-02-05 16:32:33 +01:00
if ( s - > fb )
2017-08-03 14:58:20 +03:00
drm_framebuffer_put ( s - > fb ) ;
2015-02-05 16:32:33 +01:00
kfree ( state ) ;
}
2017-07-03 21:53:54 +05:30
static const struct drm_plane_funcs layer_plane_funcs = {
2015-02-05 16:32:33 +01:00
. update_plane = drm_atomic_helper_update_plane ,
. disable_plane = drm_atomic_helper_disable_plane ,
2018-04-05 18:13:57 +03:00
. destroy = drm_plane_cleanup ,
2015-02-05 16:32:33 +01:00
. reset = atmel_hlcdc_plane_reset ,
. atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state ,
. atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state ,
2015-01-06 11:13:28 +01:00
} ;
2017-02-06 18:57:19 +01:00
static int atmel_hlcdc_plane_create ( struct drm_device * dev ,
2018-04-11 09:39:26 +02:00
const struct atmel_hlcdc_layer_desc * desc )
2015-01-06 11:13:28 +01:00
{
2017-02-06 18:57:19 +01:00
struct atmel_hlcdc_dc * dc = dev - > dev_private ;
2015-01-06 11:13:28 +01:00
struct atmel_hlcdc_plane * plane ;
enum drm_plane_type type ;
int ret ;
plane = devm_kzalloc ( dev - > dev , sizeof ( * plane ) , GFP_KERNEL ) ;
if ( ! plane )
2017-02-06 18:57:19 +01:00
return - ENOMEM ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
atmel_hlcdc_layer_init ( & plane - > layer , desc , dc - > hlcdc - > regmap ) ;
2015-01-06 11:13:28 +01:00
if ( desc - > type = = ATMEL_HLCDC_BASE_LAYER )
type = DRM_PLANE_TYPE_PRIMARY ;
else if ( desc - > type = = ATMEL_HLCDC_CURSOR_LAYER )
type = DRM_PLANE_TYPE_CURSOR ;
else
type = DRM_PLANE_TYPE_OVERLAY ;
ret = drm_universal_plane_init ( dev , & plane - > base , 0 ,
& layer_plane_funcs ,
desc - > formats - > formats ,
2017-07-23 20:46:38 -07:00
desc - > formats - > nformats ,
NULL , type , NULL ) ;
2015-01-06 11:13:28 +01:00
if ( ret )
2017-02-06 18:57:19 +01:00
return ret ;
2015-01-06 11:13:28 +01:00
2015-02-05 16:32:33 +01:00
drm_plane_helper_add ( & plane - > base ,
& atmel_hlcdc_layer_plane_helper_funcs ) ;
2015-01-06 11:13:28 +01:00
/* Set default property values*/
2018-04-11 09:39:26 +02:00
ret = atmel_hlcdc_plane_init_properties ( plane ) ;
2016-09-26 19:30:50 +03:00
if ( ret )
2017-02-06 18:57:19 +01:00
return ret ;
dc - > layers [ desc - > id ] = & plane - > layer ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
return 0 ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
int atmel_hlcdc_create_planes ( struct drm_device * dev )
2015-01-06 11:13:28 +01:00
{
struct atmel_hlcdc_dc * dc = dev - > dev_private ;
const struct atmel_hlcdc_layer_desc * descs = dc - > desc - > layers ;
int nlayers = dc - > desc - > nlayers ;
2017-02-06 18:57:19 +01:00
int i , ret ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
dc - > dscrpool = dmam_pool_create ( " atmel-hlcdc-dscr " , dev - > dev ,
sizeof ( struct atmel_hlcdc_dma_channel_dscr ) ,
sizeof ( u64 ) , 0 ) ;
if ( ! dc - > dscrpool )
return - ENOMEM ;
2015-01-06 11:13:28 +01:00
2017-02-06 18:57:19 +01:00
for ( i = 0 ; i < nlayers ; i + + ) {
if ( descs [ i ] . type ! = ATMEL_HLCDC_BASE_LAYER & &
descs [ i ] . type ! = ATMEL_HLCDC_OVERLAY_LAYER & &
descs [ i ] . type ! = ATMEL_HLCDC_CURSOR_LAYER )
2015-01-06 11:13:28 +01:00
continue ;
2018-04-11 09:39:26 +02:00
ret = atmel_hlcdc_plane_create ( dev , & descs [ i ] ) ;
2017-02-06 18:57:19 +01:00
if ( ret )
return ret ;
2015-01-06 11:13:28 +01:00
}
2017-02-06 18:57:19 +01:00
return 0 ;
2015-01-06 11:13:28 +01:00
}