2019-01-23 18:14:39 +08:00
// SPDX-License-Identifier: GPL-2.0
2018-08-30 23:12:06 +02:00
/*
* Copyright ( C ) Fuzhou Rockchip Electronics Co . Ltd
* Author :
* Sandy Huang < hjc @ rock - chips . com >
*/
2019-07-16 08:42:19 +02:00
# include <linux/component.h>
2022-06-30 22:51:13 +03:00
# include <linux/media-bus-format.h>
2019-07-16 08:42:19 +02:00
# include <linux/of_graph.h>
2022-04-21 09:31:02 +02:00
# include <drm/display/drm_dp_helper.h>
2018-08-30 23:12:06 +02:00
# include <drm/drm_atomic_helper.h>
2019-08-26 17:26:29 +02:00
# include <drm/drm_bridge.h>
2021-09-13 14:51:08 +02:00
# include <drm/drm_bridge_connector.h>
2018-08-30 23:12:06 +02:00
# include <drm/drm_of.h>
2019-07-16 08:42:19 +02:00
# include <drm/drm_panel.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2020-03-05 16:59:40 +01:00
# include <drm/drm_simple_kms_helper.h>
2018-08-30 23:12:06 +02:00
# include "rockchip_drm_drv.h"
2020-11-16 17:40:55 +00:00
# include "rockchip_rgb.h"
2018-08-30 23:12:06 +02:00
struct rockchip_rgb {
struct device * dev ;
struct drm_device * drm_dev ;
struct drm_bridge * bridge ;
2023-01-24 06:47:02 +01:00
struct rockchip_encoder encoder ;
2021-09-13 14:51:08 +02:00
struct drm_connector connector ;
2018-08-30 23:12:06 +02:00
int output_mode ;
} ;
static int
rockchip_rgb_encoder_atomic_check ( struct drm_encoder * encoder ,
struct drm_crtc_state * crtc_state ,
struct drm_connector_state * conn_state )
{
struct rockchip_crtc_state * s = to_rockchip_crtc_state ( crtc_state ) ;
struct drm_connector * connector = conn_state - > connector ;
struct drm_display_info * info = & connector - > display_info ;
u32 bus_format ;
if ( info - > num_bus_formats )
bus_format = info - > bus_formats [ 0 ] ;
else
bus_format = MEDIA_BUS_FMT_RGB888_1X24 ;
switch ( bus_format ) {
case MEDIA_BUS_FMT_RGB666_1X18 :
s - > output_mode = ROCKCHIP_OUT_MODE_P666 ;
break ;
case MEDIA_BUS_FMT_RGB565_1X16 :
s - > output_mode = ROCKCHIP_OUT_MODE_P565 ;
break ;
case MEDIA_BUS_FMT_RGB888_1X24 :
case MEDIA_BUS_FMT_RGB666_1X24_CPADHI :
default :
s - > output_mode = ROCKCHIP_OUT_MODE_P888 ;
break ;
}
s - > output_type = DRM_MODE_CONNECTOR_LVDS ;
return 0 ;
}
static const
struct drm_encoder_helper_funcs rockchip_rgb_encoder_helper_funcs = {
. atomic_check = rockchip_rgb_encoder_atomic_check ,
} ;
struct rockchip_rgb * rockchip_rgb_init ( struct device * dev ,
struct drm_crtc * crtc ,
2023-01-24 06:47:03 +01:00
struct drm_device * drm_dev ,
int video_port )
2018-08-30 23:12:06 +02:00
{
struct rockchip_rgb * rgb ;
struct drm_encoder * encoder ;
struct device_node * port , * endpoint ;
u32 endpoint_id ;
int ret = 0 , child_count = 0 ;
struct drm_panel * panel ;
struct drm_bridge * bridge ;
2021-09-13 14:51:08 +02:00
struct drm_connector * connector ;
2018-08-30 23:12:06 +02:00
rgb = devm_kzalloc ( dev , sizeof ( * rgb ) , GFP_KERNEL ) ;
if ( ! rgb )
return ERR_PTR ( - ENOMEM ) ;
rgb - > dev = dev ;
rgb - > drm_dev = drm_dev ;
2023-01-24 06:47:03 +01:00
port = of_graph_get_port_by_id ( dev - > of_node , video_port ) ;
2018-08-30 23:12:06 +02:00
if ( ! port )
return ERR_PTR ( - EINVAL ) ;
for_each_child_of_node ( port , endpoint ) {
if ( of_property_read_u32 ( endpoint , " reg " , & endpoint_id ) )
endpoint_id = 0 ;
2020-01-21 23:48:28 +01:00
/* if subdriver (> 0) or error case (< 0), ignore entry */
if ( rockchip_drm_endpoint_is_subdriver ( endpoint ) ! = 0 )
2018-08-30 23:12:06 +02:00
continue ;
child_count + + ;
2023-01-24 06:47:03 +01:00
ret = drm_of_find_panel_or_bridge ( dev - > of_node , video_port ,
endpoint_id , & panel , & bridge ) ;
2019-01-13 09:47:43 +01:00
if ( ! ret ) {
of_node_put ( endpoint ) ;
2018-08-30 23:12:06 +02:00
break ;
2019-01-13 09:47:43 +01:00
}
2018-08-30 23:12:06 +02:00
}
of_node_put ( port ) ;
/* if the rgb output is not connected to anything, just return */
if ( ! child_count )
return NULL ;
if ( ret < 0 ) {
if ( ret ! = - EPROBE_DEFER )
DRM_DEV_ERROR ( dev , " failed to find panel or bridge %d \n " , ret ) ;
return ERR_PTR ( ret ) ;
}
2023-01-24 06:47:02 +01:00
encoder = & rgb - > encoder . encoder ;
2018-08-30 23:12:06 +02:00
encoder - > possible_crtcs = drm_crtc_mask ( crtc ) ;
2020-03-05 16:59:40 +01:00
ret = drm_simple_encoder_init ( drm_dev , encoder , DRM_MODE_ENCODER_NONE ) ;
2018-08-30 23:12:06 +02:00
if ( ret < 0 ) {
DRM_DEV_ERROR ( drm_dev - > dev ,
" failed to initialize encoder: %d \n " , ret ) ;
return ERR_PTR ( ret ) ;
}
drm_encoder_helper_add ( encoder , & rockchip_rgb_encoder_helper_funcs ) ;
if ( panel ) {
drm/bridge: panel: Infer connector type from panel by default
The drm panel bridge creates a connector using a connector type
explicitly passed by the display controller or bridge driver that
instantiates the panel bridge. Now that drm_panel reports its connector
type, we can use it to avoid passing an explicit (and often incorrect)
connector type to drm_panel_bridge_add() and
devm_drm_panel_bridge_add().
Several drivers report incorrect or unknown connector types to
userspace. Reporting a different type may result in a breakage. For that
reason, rename (devm_)drm_panel_bridge_add() to
(devm_)drm_panel_bridge_add_typed(), and add new
(devm_)drm_panel_bridge_add() functions that use the panel connector
type. Update all callers of (devm_)drm_panel_bridge_add() to the _typed
function, they will be converted one by one after testing.
The panel drivers have been updated with the following Coccinelle
semantic patch, with manual inspection and fixes to indentation.
@@
expression bridge;
expression dev;
expression panel;
identifier type;
@@
(
-bridge = drm_panel_bridge_add(panel, type);
+bridge = drm_panel_bridge_add_typed(panel, type);
|
-bridge = devm_drm_panel_bridge_add(dev, panel, type);
+bridge = devm_drm_panel_bridge_add_typed(dev, panel, type);
)
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190904132804.29680-3-laurent.pinchart@ideasonboard.com
2019-09-04 16:28:04 +03:00
bridge = drm_panel_bridge_add_typed ( panel ,
DRM_MODE_CONNECTOR_LVDS ) ;
2018-08-30 23:12:06 +02:00
if ( IS_ERR ( bridge ) )
return ERR_CAST ( bridge ) ;
}
rgb - > bridge = bridge ;
2021-09-13 14:51:08 +02:00
ret = drm_bridge_attach ( encoder , rgb - > bridge , NULL ,
DRM_BRIDGE_ATTACH_NO_CONNECTOR ) ;
2021-03-23 23:50:08 +02:00
if ( ret )
2018-08-30 23:12:06 +02:00
goto err_free_encoder ;
2021-09-13 14:51:08 +02:00
connector = & rgb - > connector ;
connector = drm_bridge_connector_init ( rgb - > drm_dev , encoder ) ;
if ( IS_ERR ( connector ) ) {
DRM_DEV_ERROR ( drm_dev - > dev ,
" failed to initialize bridge connector: %pe \n " ,
connector ) ;
ret = PTR_ERR ( connector ) ;
goto err_free_encoder ;
}
2023-01-24 06:47:02 +01:00
rgb - > encoder . crtc_endpoint_id = endpoint_id ;
2021-09-13 14:51:08 +02:00
ret = drm_connector_attach_encoder ( connector , encoder ) ;
if ( ret < 0 ) {
DRM_DEV_ERROR ( drm_dev - > dev ,
" failed to attach encoder: %d \n " , ret ) ;
goto err_free_connector ;
}
2018-08-30 23:12:06 +02:00
return rgb ;
2021-09-13 14:51:08 +02:00
err_free_connector :
drm_connector_cleanup ( connector ) ;
2018-08-30 23:12:06 +02:00
err_free_encoder :
drm_encoder_cleanup ( encoder ) ;
return ERR_PTR ( ret ) ;
}
EXPORT_SYMBOL_GPL ( rockchip_rgb_init ) ;
void rockchip_rgb_fini ( struct rockchip_rgb * rgb )
{
drm_panel_bridge_remove ( rgb - > bridge ) ;
2021-09-13 14:51:08 +02:00
drm_connector_cleanup ( & rgb - > connector ) ;
2023-01-24 06:47:02 +01:00
drm_encoder_cleanup ( & rgb - > encoder . encoder ) ;
2018-08-30 23:12:06 +02:00
}
EXPORT_SYMBOL_GPL ( rockchip_rgb_fini ) ;