2013-06-19 13:54:11 +02:00
/*
* rcar_du_kms . c - - R - Car Display Unit Mode Setting
*
2015-09-07 17:34:26 +03:00
* Copyright ( C ) 2013 - 2015 Renesas Electronics Corporation
2013-06-19 13:54:11 +02:00
*
* Contact : Laurent Pinchart ( laurent . pinchart @ ideasonboard . 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/drmP.h>
2015-02-23 01:02:15 +02:00
# include <drm/drm_atomic.h>
2015-02-20 13:18:56 +02:00
# include <drm/drm_atomic_helper.h>
2013-06-19 13:54:11 +02:00
# include <drm/drm_crtc.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_fb_cma_helper.h>
# include <drm/drm_gem_cma_helper.h>
2014-01-21 15:57:26 +01:00
# include <linux/of_graph.h>
2015-02-23 01:02:15 +02:00
# include <linux/wait.h>
2014-01-21 15:57:26 +01:00
2013-06-19 13:54:11 +02:00
# include "rcar_du_crtc.h"
# include "rcar_du_drv.h"
2013-06-15 15:02:12 +02:00
# include "rcar_du_encoder.h"
2013-06-19 13:54:11 +02:00
# include "rcar_du_kms.h"
2013-06-17 13:48:27 +02:00
# include "rcar_du_lvdsenc.h"
2013-06-19 13:54:11 +02:00
# include "rcar_du_regs.h"
2015-09-07 17:14:58 +03:00
# include "rcar_du_vsp.h"
2013-06-19 13:54:11 +02:00
/* -----------------------------------------------------------------------------
* Format helpers
*/
static const struct rcar_du_format_info rcar_du_format_infos [ ] = {
{
. fourcc = DRM_FORMAT_RGB565 ,
. bpp = 16 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_ARGB1555 ,
. bpp = 16 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_XRGB1555 ,
. bpp = 16 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_XRGB8888 ,
. bpp = 32 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP ,
. edf = PnDDCR4_EDF_RGB888 ,
} , {
. fourcc = DRM_FORMAT_ARGB8888 ,
. bpp = 32 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP ,
. edf = PnDDCR4_EDF_ARGB8888 ,
} , {
. fourcc = DRM_FORMAT_UYVY ,
. bpp = 16 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_YUYV ,
. bpp = 16 ,
. planes = 1 ,
. pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_NV12 ,
. bpp = 12 ,
. planes = 2 ,
. pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_NV21 ,
. bpp = 12 ,
. planes = 2 ,
. pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC ,
. edf = PnDDCR4_EDF_NONE ,
} , {
. fourcc = DRM_FORMAT_NV16 ,
. bpp = 16 ,
. planes = 2 ,
. pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC ,
. edf = PnDDCR4_EDF_NONE ,
} ,
2017-07-11 01:13:20 +03:00
/*
* The following formats are not supported on Gen2 and thus have no
2015-11-12 02:03:47 +02:00
* associated . pnmr or . edf settings .
*/
{
. fourcc = DRM_FORMAT_NV61 ,
. bpp = 16 ,
. planes = 2 ,
} , {
. fourcc = DRM_FORMAT_YUV420 ,
. bpp = 12 ,
. planes = 3 ,
} , {
. fourcc = DRM_FORMAT_YVU420 ,
. bpp = 12 ,
. planes = 3 ,
} , {
. fourcc = DRM_FORMAT_YUV422 ,
. bpp = 16 ,
. planes = 3 ,
} , {
. fourcc = DRM_FORMAT_YVU422 ,
. bpp = 16 ,
. planes = 3 ,
} , {
. fourcc = DRM_FORMAT_YUV444 ,
. bpp = 24 ,
. planes = 3 ,
} , {
. fourcc = DRM_FORMAT_YVU444 ,
. bpp = 24 ,
. planes = 3 ,
} ,
2013-06-19 13:54:11 +02:00
} ;
const struct rcar_du_format_info * rcar_du_format_info ( u32 fourcc )
{
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( rcar_du_format_infos ) ; + + i ) {
if ( rcar_du_format_infos [ i ] . fourcc = = fourcc )
return & rcar_du_format_infos [ i ] ;
}
return NULL ;
}
/* -----------------------------------------------------------------------------
* Frame buffer
*/
2013-07-04 20:05:51 +02:00
int rcar_du_dumb_create ( struct drm_file * file , struct drm_device * dev ,
struct drm_mode_create_dumb * args )
{
2013-06-14 20:52:52 +02:00
struct rcar_du_device * rcdu = dev - > dev_private ;
2013-07-04 20:05:51 +02:00
unsigned int min_pitch = DIV_ROUND_UP ( args - > width * args - > bpp , 8 ) ;
unsigned int align ;
2017-07-11 01:13:20 +03:00
/*
* The R8A7779 DU requires a 16 pixels pitch alignment as documented ,
2013-06-14 20:52:52 +02:00
* but the R8A7790 DU seems to require a 128 bytes pitch alignment .
*/
2013-11-13 13:33:45 +01:00
if ( rcar_du_needs ( rcdu , RCAR_DU_QUIRK_ALIGN_128B ) )
2013-06-14 20:52:52 +02:00
align = 128 ;
else
align = 16 * args - > bpp / 8 ;
2014-11-03 12:08:24 +01:00
args - > pitch = roundup ( min_pitch , align ) ;
2013-07-04 20:05:51 +02:00
2014-11-03 11:48:49 +01:00
return drm_gem_cma_dumb_create_internal ( file , dev , args ) ;
2013-07-04 20:05:51 +02:00
}
2013-06-19 13:54:11 +02:00
static struct drm_framebuffer *
rcar_du_fb_create ( struct drm_device * dev , struct drm_file * file_priv ,
2015-11-11 19:11:29 +02:00
const struct drm_mode_fb_cmd2 * mode_cmd )
2013-06-19 13:54:11 +02:00
{
2013-06-14 20:52:52 +02:00
struct rcar_du_device * rcdu = dev - > dev_private ;
2013-06-19 13:54:11 +02:00
const struct rcar_du_format_info * format ;
2014-07-28 20:18:36 +02:00
unsigned int max_pitch ;
2013-07-04 20:05:51 +02:00
unsigned int align ;
2014-07-28 20:18:36 +02:00
unsigned int bpp ;
2015-11-12 02:03:47 +02:00
unsigned int i ;
2013-06-19 13:54:11 +02:00
format = rcar_du_format_info ( mode_cmd - > pixel_format ) ;
if ( format = = NULL ) {
dev_dbg ( dev - > dev , " unsupported pixel format %08x \n " ,
mode_cmd - > pixel_format ) ;
return ERR_PTR ( - EINVAL ) ;
}
2014-07-28 20:18:36 +02:00
/*
* The pitch and alignment constraints are expressed in pixels on the
* hardware side and in bytes in the DRM API .
*/
2015-11-12 02:03:47 +02:00
bpp = format - > planes = = 1 ? format - > bpp / 8 : 1 ;
2014-07-28 20:18:36 +02:00
max_pitch = 4096 * bpp ;
2013-11-13 13:33:45 +01:00
if ( rcar_du_needs ( rcdu , RCAR_DU_QUIRK_ALIGN_128B ) )
2013-06-14 20:52:52 +02:00
align = 128 ;
else
2014-07-28 20:18:36 +02:00
align = 16 * bpp ;
2013-07-04 20:05:51 +02:00
if ( mode_cmd - > pitches [ 0 ] & ( align - 1 ) | |
2014-07-28 20:18:36 +02:00
mode_cmd - > pitches [ 0 ] > = max_pitch ) {
2013-06-19 13:54:11 +02:00
dev_dbg ( dev - > dev , " invalid pitch value %u \n " ,
mode_cmd - > pitches [ 0 ] ) ;
return ERR_PTR ( - EINVAL ) ;
}
2015-11-12 02:03:47 +02:00
for ( i = 1 ; i < format - > planes ; + + i ) {
if ( mode_cmd - > pitches [ i ] ! = mode_cmd - > pitches [ 0 ] ) {
2013-06-19 13:54:11 +02:00
dev_dbg ( dev - > dev ,
" luma and chroma pitches do not match \n " ) ;
return ERR_PTR ( - EINVAL ) ;
}
}
return drm_fb_cma_create ( dev , file_priv , mode_cmd ) ;
}
2013-03-14 22:45:22 +01:00
static void rcar_du_output_poll_changed ( struct drm_device * dev )
{
struct rcar_du_device * rcdu = dev - > dev_private ;
drm_fbdev_cma_hotplug_event ( rcdu - > fbdev ) ;
}
2015-02-23 01:02:15 +02:00
/* -----------------------------------------------------------------------------
2015-02-25 18:27:19 +02:00
* Atomic Check and Update
2015-02-23 01:02:15 +02:00
*/
2015-02-25 18:27:19 +02:00
static int rcar_du_atomic_check ( struct drm_device * dev ,
struct drm_atomic_state * state )
{
2015-09-07 17:14:58 +03:00
struct rcar_du_device * rcdu = dev - > dev_private ;
2015-02-25 18:27:19 +02:00
int ret ;
2016-10-10 17:50:56 +03:00
ret = drm_atomic_helper_check_modeset ( dev , state ) ;
if ( ret )
return ret ;
ret = drm_atomic_normalize_zpos ( dev , state ) ;
if ( ret )
return ret ;
ret = drm_atomic_helper_check_planes ( dev , state ) ;
if ( ret )
2015-02-25 18:27:19 +02:00
return ret ;
2015-09-07 17:14:58 +03:00
if ( rcar_du_has ( rcdu , RCAR_DU_FEATURE_VSP1_SOURCE ) )
return 0 ;
2015-07-27 15:34:18 +03:00
return rcar_du_atomic_check_planes ( dev , state ) ;
2015-02-25 18:27:19 +02:00
}
2017-02-10 13:30:35 +02:00
static void rcar_du_atomic_commit_tail ( struct drm_atomic_state * old_state )
2015-02-23 01:02:15 +02:00
{
2017-02-10 13:30:35 +02:00
struct drm_device * dev = old_state - > dev ;
2015-02-23 01:02:15 +02:00
/* Apply the atomic update. */
drm_atomic_helper_commit_modeset_disables ( dev , old_state ) ;
2016-08-29 17:12:03 +08:00
drm_atomic_helper_commit_planes ( dev , old_state ,
DRM_PLANE_COMMIT_ACTIVE_ONLY ) ;
2017-06-27 13:18:38 +03:00
drm_atomic_helper_commit_modeset_enables ( dev , old_state ) ;
2015-02-23 01:02:15 +02:00
2017-02-10 13:30:35 +02:00
drm_atomic_helper_commit_hw_done ( old_state ) ;
2015-02-23 01:02:15 +02:00
drm_atomic_helper_wait_for_vblanks ( dev , old_state ) ;
drm_atomic_helper_cleanup_planes ( dev , old_state ) ;
}
/* -----------------------------------------------------------------------------
* Initialization
*/
2017-02-10 13:30:35 +02:00
static const struct drm_mode_config_helper_funcs rcar_du_mode_config_helper = {
. atomic_commit_tail = rcar_du_atomic_commit_tail ,
} ;
2013-06-19 13:54:11 +02:00
static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
. fb_create = rcar_du_fb_create ,
2013-03-14 22:45:22 +01:00
. output_poll_changed = rcar_du_output_poll_changed ,
2015-02-25 18:27:19 +02:00
. atomic_check = rcar_du_atomic_check ,
2017-02-10 13:30:35 +02:00
. atomic_commit = drm_atomic_helper_commit ,
2013-06-19 13:54:11 +02:00
} ;
2014-09-17 02:07:52 +03:00
static int rcar_du_encoders_init_one ( struct rcar_du_device * rcdu ,
enum rcar_du_output output ,
struct of_endpoint * ep )
2014-01-21 15:57:26 +01:00
{
struct device_node * connector = NULL ;
struct device_node * encoder = NULL ;
2014-12-01 13:32:32 +01:00
struct device_node * ep_node = NULL ;
2014-01-21 15:57:26 +01:00
struct device_node * entity_ep_node ;
struct device_node * entity ;
int ret ;
/*
* Locate the connected entity and infer its type from the number of
* endpoints .
*/
entity = of_graph_get_remote_port_parent ( ep - > local_node ) ;
if ( ! entity ) {
2017-07-18 16:43:04 -05:00
dev_dbg ( rcdu - > dev , " unconnected endpoint %pOF, skipping \n " ,
ep - > local_node ) ;
2015-05-26 15:07:56 +03:00
return - ENODEV ;
2014-01-21 15:57:26 +01:00
}
2016-12-01 13:07:49 +02:00
if ( ! of_device_is_available ( entity ) ) {
dev_dbg ( rcdu - > dev ,
2017-07-18 16:43:04 -05:00
" connected entity %pOF is disabled, skipping \n " ,
entity ) ;
2016-12-01 13:07:49 +02:00
return - ENODEV ;
}
2017-06-28 00:32:17 +00:00
entity_ep_node = of_graph_get_remote_endpoint ( ep - > local_node ) ;
2014-01-21 15:57:26 +01:00
2014-12-22 11:46:40 +01:00
for_each_endpoint_of_node ( entity , ep_node ) {
2014-01-21 15:57:26 +01:00
if ( ep_node = = entity_ep_node )
continue ;
/*
* We ' ve found one endpoint other than the input , this must
* be an encoder . Locate the connector .
*/
encoder = entity ;
connector = of_graph_get_remote_port_parent ( ep_node ) ;
of_node_put ( ep_node ) ;
if ( ! connector ) {
dev_warn ( rcdu - > dev ,
2017-07-18 16:43:04 -05:00
" no connector for encoder %pOF, skipping \n " ,
encoder ) ;
2014-01-21 15:57:26 +01:00
of_node_put ( entity_ep_node ) ;
of_node_put ( encoder ) ;
2015-05-26 15:07:56 +03:00
return - ENODEV ;
2014-01-21 15:57:26 +01:00
}
break ;
}
of_node_put ( entity_ep_node ) ;
2016-10-07 17:39:21 +03:00
if ( ! encoder ) {
2014-01-21 15:57:26 +01:00
/*
* If no encoder has been found the entity must be the
* connector .
*/
connector = entity ;
}
2016-10-07 17:39:21 +03:00
ret = rcar_du_encoder_init ( rcdu , output , encoder , connector ) ;
2015-05-26 14:59:42 +03:00
if ( ret & & ret ! = - EPROBE_DEFER )
dev_warn ( rcdu - > dev ,
2017-07-18 16:43:04 -05:00
" failed to initialize encoder %pOF on output %u (%d), skipping \n " ,
encoder , output , ret ) ;
2016-10-03 20:03:22 +03:00
of_node_put ( encoder ) ;
of_node_put ( connector ) ;
2015-05-26 14:59:42 +03:00
2015-05-26 15:07:56 +03:00
return ret ;
2014-01-21 15:57:26 +01:00
}
2014-09-17 02:07:52 +03:00
static int rcar_du_encoders_init ( struct rcar_du_device * rcdu )
2014-01-21 15:57:26 +01:00
{
struct device_node * np = rcdu - > dev - > of_node ;
2014-12-22 11:46:40 +01:00
struct device_node * ep_node ;
2014-01-21 15:57:26 +01:00
unsigned int num_encoders = 0 ;
/*
* Iterate over the endpoints and create one encoder for each output
* pipeline .
*/
2014-12-22 11:46:40 +01:00
for_each_endpoint_of_node ( np , ep_node ) {
2014-01-21 15:57:26 +01:00
enum rcar_du_output output ;
struct of_endpoint ep ;
unsigned int i ;
int ret ;
ret = of_graph_parse_endpoint ( ep_node , & ep ) ;
if ( ret < 0 ) {
of_node_put ( ep_node ) ;
return ret ;
}
/* Find the output route corresponding to the port number. */
for ( i = 0 ; i < RCAR_DU_OUTPUT_MAX ; + + i ) {
if ( rcdu - > info - > routes [ i ] . possible_crtcs & &
rcdu - > info - > routes [ i ] . port = = ep . port ) {
output = i ;
break ;
}
}
if ( i = = RCAR_DU_OUTPUT_MAX ) {
dev_warn ( rcdu - > dev ,
" port %u references unexisting output, skipping \n " ,
ep . port ) ;
continue ;
}
/* Process the output pipeline. */
2014-09-17 02:07:52 +03:00
ret = rcar_du_encoders_init_one ( rcdu , output , & ep ) ;
2014-01-21 15:57:26 +01:00
if ( ret < 0 ) {
2014-12-11 01:26:04 +02:00
if ( ret = = - EPROBE_DEFER ) {
of_node_put ( ep_node ) ;
return ret ;
}
continue ;
2014-01-21 15:57:26 +01:00
}
2015-05-26 15:07:56 +03:00
num_encoders + + ;
2014-01-21 15:57:26 +01:00
}
return num_encoders ;
}
2015-04-28 23:59:29 +03:00
static int rcar_du_properties_init ( struct rcar_du_device * rcdu )
{
rcdu - > props . alpha =
drm_property_create_range ( rcdu - > ddev , 0 , " alpha " , 0 , 255 ) ;
if ( rcdu - > props . alpha = = NULL )
return - ENOMEM ;
2017-07-11 01:13:20 +03:00
/*
* The color key is expressed as an RGB888 triplet stored in a 32 - bit
2015-04-28 23:59:29 +03:00
* integer in XRGB8888 format . Bit 24 is used as a flag to disable ( 0 )
* or enable source color keying ( 1 ) .
*/
rcdu - > props . colorkey =
drm_property_create_range ( rcdu - > ddev , 0 , " colorkey " ,
0 , 0x01ffffff ) ;
if ( rcdu - > props . colorkey = = NULL )
return - ENOMEM ;
return 0 ;
}
2017-06-26 13:12:01 +03:00
static int rcar_du_vsps_init ( struct rcar_du_device * rcdu )
{
const struct device_node * np = rcdu - > dev - > of_node ;
struct of_phandle_args args ;
struct {
struct device_node * np ;
unsigned int crtcs_mask ;
} vsps [ RCAR_DU_MAX_VSPS ] = { { 0 , } , } ;
unsigned int vsps_count = 0 ;
unsigned int cells ;
unsigned int i ;
int ret ;
/*
* First parse the DT vsps property to populate the list of VSPs . Each
* entry contains a pointer to the VSP DT node and a bitmask of the
* connected DU CRTCs .
*/
cells = of_property_count_u32_elems ( np , " vsps " ) / rcdu - > num_crtcs - 1 ;
if ( cells > 1 )
return - EINVAL ;
for ( i = 0 ; i < rcdu - > num_crtcs ; + + i ) {
unsigned int j ;
ret = of_parse_phandle_with_fixed_args ( np , " vsps " , cells , i ,
& args ) ;
if ( ret < 0 )
goto error ;
/*
* Add the VSP to the list or update the corresponding existing
* entry if the VSP has already been added .
*/
for ( j = 0 ; j < vsps_count ; + + j ) {
if ( vsps [ j ] . np = = args . np )
break ;
}
if ( j < vsps_count )
of_node_put ( args . np ) ;
else
vsps [ vsps_count + + ] . np = args . np ;
vsps [ j ] . crtcs_mask | = BIT ( i ) ;
/* Store the VSP pointer and pipe index in the CRTC. */
rcdu - > crtcs [ i ] . vsp = & rcdu - > vsps [ j ] ;
rcdu - > crtcs [ i ] . vsp_pipe = cells > = 1 ? args . args [ 0 ] : 0 ;
}
/*
* Then initialize all the VSPs from the node pointers and CRTCs bitmask
* computed previously .
*/
for ( i = 0 ; i < vsps_count ; + + i ) {
struct rcar_du_vsp * vsp = & rcdu - > vsps [ i ] ;
vsp - > index = i ;
vsp - > dev = rcdu ;
ret = rcar_du_vsp_init ( vsp , vsps [ i ] . np , vsps [ i ] . crtcs_mask ) ;
if ( ret < 0 )
goto error ;
}
return 0 ;
error :
for ( i = 0 ; i < ARRAY_SIZE ( vsps ) ; + + i )
of_node_put ( vsps [ i ] . np ) ;
return ret ;
}
2013-06-19 13:54:11 +02:00
int rcar_du_modeset_init ( struct rcar_du_device * rcdu )
{
2013-06-17 00:29:25 +02:00
static const unsigned int mmio_offsets [ ] = {
DU0_REG_OFFSET , DU2_REG_OFFSET
} ;
2013-06-19 13:54:11 +02:00
struct drm_device * dev = rcdu - > ddev ;
struct drm_encoder * encoder ;
2013-03-14 22:45:22 +01:00
struct drm_fbdev_cma * fbdev ;
2014-01-21 15:57:26 +01:00
unsigned int num_encoders ;
2013-06-17 00:29:25 +02:00
unsigned int num_groups ;
2013-06-19 13:54:11 +02:00
unsigned int i ;
int ret ;
2013-03-14 22:45:22 +01:00
drm_mode_config_init ( dev ) ;
2013-06-19 13:54:11 +02:00
2013-03-14 22:45:22 +01:00
dev - > mode_config . min_width = 0 ;
dev - > mode_config . min_height = 0 ;
dev - > mode_config . max_width = 4095 ;
dev - > mode_config . max_height = 2047 ;
dev - > mode_config . funcs = & rcar_du_mode_config_funcs ;
2017-02-10 13:30:35 +02:00
dev - > mode_config . helper_private = & rcar_du_mode_config_helper ;
2013-06-19 13:54:11 +02:00
2013-06-17 00:29:25 +02:00
rcdu - > num_crtcs = rcdu - > info - > num_crtcs ;
2015-04-28 23:59:29 +03:00
ret = rcar_du_properties_init ( rcdu ) ;
if ( ret < 0 )
return ret ;
2017-07-11 01:13:20 +03:00
/*
* Initialize vertical blanking interrupts handling . Start with vblank
2016-10-19 00:51:35 +03:00
* disabled for all CRTCs .
*/
ret = drm_vblank_init ( dev , ( 1 < < rcdu - > info - > num_crtcs ) - 1 ) ;
if ( ret < 0 )
return ret ;
2013-06-17 00:29:25 +02:00
/* Initialize the groups. */
num_groups = DIV_ROUND_UP ( rcdu - > num_crtcs , 2 ) ;
for ( i = 0 ; i < num_groups ; + + i ) {
struct rcar_du_group * rgrp = & rcdu - > groups [ i ] ;
2013-06-16 21:01:02 +02:00
2015-02-25 18:27:19 +02:00
mutex_init ( & rgrp - > lock ) ;
2013-06-17 00:29:25 +02:00
rgrp - > dev = rcdu ;
rgrp - > mmio_offset = mmio_offsets [ i ] ;
rgrp - > index = i ;
2015-04-28 17:36:33 +03:00
rgrp - > num_crtcs = min ( rcdu - > num_crtcs - 2 * i , 2U ) ;
2013-06-19 13:54:11 +02:00
2017-07-11 01:13:20 +03:00
/*
* If we have more than one CRTCs in this group pre - associate
2015-09-07 17:34:26 +03:00
* the low - order planes with CRTC 0 and the high - order planes
* with CRTC 1 to minimize flicker occurring when the
* association is changed .
2015-04-29 00:51:01 +03:00
*/
2015-09-07 17:34:26 +03:00
rgrp - > dptsr_planes = rgrp - > num_crtcs > 1
? ( rcdu - > info - > gen > = 3 ? 0x04 : 0xf0 )
: 0 ;
2015-04-29 00:51:01 +03:00
2015-09-07 17:14:58 +03:00
if ( ! rcar_du_has ( rcdu , RCAR_DU_FEATURE_VSP1_SOURCE ) ) {
ret = rcar_du_planes_init ( rgrp ) ;
if ( ret < 0 )
return ret ;
}
}
/* Initialize the compositors. */
if ( rcar_du_has ( rcdu , RCAR_DU_FEATURE_VSP1_SOURCE ) ) {
2017-06-26 13:12:01 +03:00
ret = rcar_du_vsps_init ( rcdu ) ;
if ( ret < 0 )
return ret ;
2013-07-04 20:05:50 +02:00
}
2013-06-19 13:54:11 +02:00
2013-06-17 00:29:25 +02:00
/* Create the CRTCs. */
for ( i = 0 ; i < rcdu - > num_crtcs ; + + i ) {
struct rcar_du_group * rgrp = & rcdu - > groups [ i / 2 ] ;
ret = rcar_du_crtc_create ( rgrp , i ) ;
if ( ret < 0 )
return ret ;
}
2013-06-19 13:54:11 +02:00
2013-06-17 00:29:25 +02:00
/* Initialize the encoders. */
2013-06-17 13:48:27 +02:00
ret = rcar_du_lvdsenc_init ( rcdu ) ;
if ( ret < 0 )
return ret ;
2014-09-17 02:07:52 +03:00
ret = rcar_du_encoders_init ( rcdu ) ;
2014-01-21 15:57:26 +01:00
if ( ret < 0 )
return ret ;
2013-06-19 13:54:11 +02:00
2014-12-11 01:26:04 +02:00
if ( ret = = 0 ) {
dev_err ( rcdu - > dev , " error: no encoder could be initialized \n " ) ;
return - EINVAL ;
}
2014-01-21 15:57:26 +01:00
num_encoders = ret ;
2013-06-19 13:54:11 +02:00
2017-07-11 01:13:20 +03:00
/*
* Set the possible CRTCs and possible clones . There ' s always at least
2013-06-17 03:13:11 +02:00
* one way for all encoders to clone each other , set all bits in the
* possible clones field .
2013-06-19 13:54:11 +02:00
*/
list_for_each_entry ( encoder , & dev - > mode_config . encoder_list , head ) {
struct rcar_du_encoder * renc = to_rcar_encoder ( encoder ) ;
2013-06-17 03:13:11 +02:00
const struct rcar_du_output_routing * route =
& rcdu - > info - > routes [ renc - > output ] ;
2013-06-19 13:54:11 +02:00
2013-06-17 03:13:11 +02:00
encoder - > possible_crtcs = route - > possible_crtcs ;
2014-01-21 15:57:26 +01:00
encoder - > possible_clones = ( 1 < < num_encoders ) - 1 ;
2013-06-19 13:54:11 +02:00
}
2015-02-20 11:30:59 +02:00
drm_mode_config_reset ( dev ) ;
2013-03-14 22:45:22 +01:00
drm_kms_helper_poll_init ( dev ) ;
2015-02-24 03:51:26 +02:00
if ( dev - > mode_config . num_connector ) {
drm: Rely on mode_config data for fb_helper initialization
Instead of receiving the num_crts as a parameter, we can read it
directly from the mode_config structure. I audited the drivers that
invoke this helper and I believe all of them initialize the mode_config
struct accordingly, prior to calling the fb_helper.
I used the following coccinelle hack to make this transformation, except
for the function headers and comment updates. The first and second
rules are split because I couldn't find a way to remove the unused
temporary variables at the same time I removed the parameter.
// <smpl>
@r@
expression A,B,D,E;
identifier C;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
expression A,B,C,D,E;
@@
(
- drm_fb_helper_init(A,B,C,D)
+ drm_fb_helper_init(A,B,D)
|
- drm_fbdev_cma_init_with_funcs(A,B,C,D,E)
+ drm_fbdev_cma_init_with_funcs(A,B,D,E)
|
- drm_fbdev_cma_init(A,B,C,D)
+ drm_fbdev_cma_init(A,B,D)
)
@@
identifier r.C;
type T;
expression V;
@@
- T C;
<...
when != C
- C = V;
...>
// </smpl>
Changes since v1:
- Rebased on top of the tip of drm-misc-next.
- Remove mention to sti since a proper fix got merged.
Suggested-by: Daniel Vetter <daniel.vetter@intel.com>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
Reviewed-by: Eric Anholt <eric@anholt.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/20170202162640.27261-1-krisman@collabora.co.uk
2017-02-02 14:26:40 -02:00
fbdev = drm_fbdev_cma_init ( dev , 32 ,
2015-02-24 03:51:26 +02:00
dev - > mode_config . num_connector ) ;
if ( IS_ERR ( fbdev ) )
return PTR_ERR ( fbdev ) ;
2013-03-14 22:45:22 +01:00
2015-02-24 03:51:26 +02:00
rcdu - > fbdev = fbdev ;
} else {
dev_info ( rcdu - > dev ,
" no connector found, disabling fbdev emulation \n " ) ;
}
2013-06-19 13:54:11 +02:00
return 0 ;
}