2015-08-19 22:19:49 -04:00
/*
* Copyright 2015 Freescale Semiconductor , Inc .
*
* Freescale DCU drm device driver
*
* 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 <linux/backlight.h>
2016-07-15 14:53:37 +08:00
# include <linux/of_graph.h>
2015-08-19 22:19:49 -04:00
# include <drm/drmP.h>
# include <drm/drm_atomic_helper.h>
# include <drm/drm_crtc_helper.h>
# include <drm/drm_panel.h>
# include "fsl_dcu_drm_drv.h"
2015-12-02 14:39:40 -08:00
# include "fsl_tcon.h"
2015-08-19 22:19:49 -04:00
static int
fsl_dcu_drm_encoder_atomic_check ( struct drm_encoder * encoder ,
struct drm_crtc_state * crtc_state ,
struct drm_connector_state * conn_state )
{
return 0 ;
}
static void fsl_dcu_drm_encoder_disable ( struct drm_encoder * encoder )
{
2015-12-02 14:39:40 -08:00
struct drm_device * dev = encoder - > dev ;
struct fsl_dcu_drm_device * fsl_dev = dev - > dev_private ;
if ( fsl_dev - > tcon )
fsl_tcon_bypass_disable ( fsl_dev - > tcon ) ;
2015-08-19 22:19:49 -04:00
}
static void fsl_dcu_drm_encoder_enable ( struct drm_encoder * encoder )
{
2015-12-02 14:39:40 -08:00
struct drm_device * dev = encoder - > dev ;
struct fsl_dcu_drm_device * fsl_dev = dev - > dev_private ;
if ( fsl_dev - > tcon )
fsl_tcon_bypass_enable ( fsl_dev - > tcon ) ;
2015-08-19 22:19:49 -04:00
}
static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
. atomic_check = fsl_dcu_drm_encoder_atomic_check ,
. disable = fsl_dcu_drm_encoder_disable ,
. enable = fsl_dcu_drm_encoder_enable ,
} ;
static void fsl_dcu_drm_encoder_destroy ( struct drm_encoder * encoder )
{
drm_encoder_cleanup ( encoder ) ;
}
static const struct drm_encoder_funcs encoder_funcs = {
. destroy = fsl_dcu_drm_encoder_destroy ,
} ;
int fsl_dcu_drm_encoder_create ( struct fsl_dcu_drm_device * fsl_dev ,
struct drm_crtc * crtc )
{
struct drm_encoder * encoder = & fsl_dev - > encoder ;
int ret ;
encoder - > possible_crtcs = 1 ;
ret = drm_encoder_init ( fsl_dev - > drm , encoder , & encoder_funcs ,
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
DRM_MODE_ENCODER_LVDS , NULL ) ;
2015-08-19 22:19:49 -04:00
if ( ret < 0 )
return ret ;
drm_encoder_helper_add ( encoder , & encoder_helper_funcs ) ;
return 0 ;
}
static void fsl_dcu_drm_connector_destroy ( struct drm_connector * connector )
{
2016-03-23 23:27:11 -07:00
struct fsl_dcu_drm_connector * fsl_con = to_fsl_dcu_connector ( connector ) ;
2015-08-19 22:19:49 -04:00
drm_connector_unregister ( connector ) ;
2016-03-23 23:27:11 -07:00
drm_panel_detach ( fsl_con - > panel ) ;
2015-08-19 22:19:49 -04:00
drm_connector_cleanup ( connector ) ;
}
static enum drm_connector_status
fsl_dcu_drm_connector_detect ( struct drm_connector * connector , bool force )
{
return connector_status_connected ;
}
static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs = {
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
. destroy = fsl_dcu_drm_connector_destroy ,
. detect = fsl_dcu_drm_connector_detect ,
. dpms = drm_atomic_helper_connector_dpms ,
. fill_modes = drm_helper_probe_single_connector_modes ,
. reset = drm_atomic_helper_connector_reset ,
} ;
static int fsl_dcu_drm_connector_get_modes ( struct drm_connector * connector )
{
struct fsl_dcu_drm_connector * fsl_connector ;
int ( * get_modes ) ( struct drm_panel * panel ) ;
int num_modes = 0 ;
fsl_connector = to_fsl_dcu_connector ( connector ) ;
if ( fsl_connector - > panel & & fsl_connector - > panel - > funcs & &
fsl_connector - > panel - > funcs - > get_modes ) {
get_modes = fsl_connector - > panel - > funcs - > get_modes ;
num_modes = get_modes ( fsl_connector - > panel ) ;
}
return num_modes ;
}
static int fsl_dcu_drm_connector_mode_valid ( struct drm_connector * connector ,
struct drm_display_mode * mode )
{
if ( mode - > hdisplay & 0xf )
return MODE_ERROR ;
return MODE_OK ;
}
static const struct drm_connector_helper_funcs connector_helper_funcs = {
. get_modes = fsl_dcu_drm_connector_get_modes ,
. mode_valid = fsl_dcu_drm_connector_mode_valid ,
} ;
2016-07-15 14:53:37 +08:00
static int fsl_dcu_attach_panel ( struct fsl_dcu_drm_device * fsl_dev ,
struct drm_panel * panel )
2015-08-19 22:19:49 -04:00
{
2016-07-15 14:53:37 +08:00
struct drm_encoder * encoder = & fsl_dev - > encoder ;
2015-08-19 22:19:49 -04:00
struct drm_connector * connector = & fsl_dev - > connector . base ;
2016-02-22 22:33:31 +01:00
struct drm_mode_config * mode_config = & fsl_dev - > drm - > mode_config ;
2015-08-19 22:19:49 -04:00
int ret ;
fsl_dev - > connector . encoder = encoder ;
ret = drm_connector_init ( fsl_dev - > drm , connector ,
& fsl_dcu_drm_connector_funcs ,
DRM_MODE_CONNECTOR_LVDS ) ;
if ( ret < 0 )
return ret ;
drm_connector_helper_add ( connector , & connector_helper_funcs ) ;
ret = drm_connector_register ( connector ) ;
if ( ret < 0 )
goto err_cleanup ;
ret = drm_mode_connector_attach_encoder ( connector , encoder ) ;
if ( ret < 0 )
goto err_sysfs ;
drm_object_property_set_value ( & connector - > base ,
2016-02-22 22:33:31 +01:00
mode_config - > dpms_property ,
2015-08-19 22:19:49 -04:00
DRM_MODE_DPMS_OFF ) ;
2016-07-15 14:53:37 +08:00
ret = drm_panel_attach ( panel , connector ) ;
2015-08-19 22:19:49 -04:00
if ( ret ) {
dev_err ( fsl_dev - > dev , " failed to attach panel \n " ) ;
goto err_sysfs ;
}
return 0 ;
err_sysfs :
drm_connector_unregister ( connector ) ;
err_cleanup :
drm_connector_cleanup ( connector ) ;
return ret ;
}
2016-07-15 14:53:37 +08:00
static int fsl_dcu_attach_endpoint ( struct fsl_dcu_drm_device * fsl_dev ,
const struct of_endpoint * ep )
{
2016-07-15 14:53:38 +08:00
struct drm_bridge * bridge ;
2016-07-15 14:53:37 +08:00
struct device_node * np ;
np = of_graph_get_remote_port_parent ( ep - > local_node ) ;
fsl_dev - > connector . panel = of_drm_find_panel ( np ) ;
2016-07-15 14:53:38 +08:00
if ( fsl_dev - > connector . panel ) {
of_node_put ( np ) ;
2016-07-15 14:53:37 +08:00
return fsl_dcu_attach_panel ( fsl_dev , fsl_dev - > connector . panel ) ;
2016-07-15 14:53:38 +08:00
}
bridge = of_drm_find_bridge ( np ) ;
of_node_put ( np ) ;
if ( ! bridge )
return - ENODEV ;
fsl_dev - > encoder . bridge = bridge ;
bridge - > encoder = & fsl_dev - > encoder ;
2016-07-15 14:53:37 +08:00
2016-07-15 14:53:38 +08:00
return drm_bridge_attach ( fsl_dev - > drm , bridge ) ;
2016-07-15 14:53:37 +08:00
}
int fsl_dcu_create_outputs ( struct fsl_dcu_drm_device * fsl_dev )
{
struct of_endpoint ep ;
struct device_node * ep_node , * panel_node ;
int ret ;
/* This is for backward compatibility */
panel_node = of_parse_phandle ( fsl_dev - > np , " fsl,panel " , 0 ) ;
if ( panel_node ) {
fsl_dev - > connector . panel = of_drm_find_panel ( panel_node ) ;
of_node_put ( panel_node ) ;
if ( ! fsl_dev - > connector . panel )
return - EPROBE_DEFER ;
return fsl_dcu_attach_panel ( fsl_dev , fsl_dev - > connector . panel ) ;
}
ep_node = of_graph_get_next_endpoint ( fsl_dev - > np , NULL ) ;
if ( ! ep_node )
return - ENODEV ;
ret = of_graph_parse_endpoint ( ep_node , & ep ) ;
of_node_put ( ep_node ) ;
if ( ret )
return - ENODEV ;
return fsl_dcu_attach_endpoint ( fsl_dev , & ep ) ;
}