From 0a62148e3796bf8feb39969cbf4e3d4bbe85724d Mon Sep 17 00:00:00 2001 From: Chen Shunqing Date: Fri, 28 Jul 2023 07:58:48 +0000 Subject: [PATCH] drm/bridge/synopsys: dw-hdmi-qp: Add support for external bridge Signed-off-by: Wyon Bi Signed-off-by: Chen Shunqing Change-Id: Ie6fe2e63f24a9c5656af7b7cd0f17ca484a099df --- drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c | 47 ++++++++++++++++++-- drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 15 ++++++- include/drm/bridge/dw_hdmi.h | 1 + 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c index 7ea4a5468986..2f23b7d71163 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c @@ -221,6 +221,7 @@ struct dw_hdmi_phy_data { struct dw_hdmi_qp { struct drm_connector connector; struct drm_bridge bridge; + struct drm_bridge *next_bridge; struct drm_panel *panel; struct platform_device *hdcp_dev; struct platform_device *audio; @@ -256,6 +257,7 @@ struct dw_hdmi_qp { bool cec_enable; bool allm_enable; bool support_hdmi; + bool skip_connector; int force_output; int vp_id; int old_vp_id; @@ -2057,6 +2059,9 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force) if (hdmi->panel) return connector_status_connected; + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_DETECT) + return drm_bridge_detect(hdmi->next_bridge); + if (hdmi->plat_data->left) secondary = hdmi->plat_data->left; else if (hdmi->plat_data->right) @@ -2136,9 +2141,21 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector) void *data = hdmi->plat_data->phy_data; int i, ret = 0; + if (hdmi->plat_data->right && hdmi->plat_data->right->next_bridge) { + struct drm_bridge *bridge = hdmi->plat_data->right->next_bridge; + + if (bridge->ops & DRM_BRIDGE_OP_MODES) { + if (!drm_bridge_get_modes(bridge, connector)) + return 0; + } + } + if (hdmi->panel) return drm_panel_get_modes(hdmi->panel, connector); + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_MODES) + return drm_bridge_get_modes(hdmi->next_bridge, connector); + if (!hdmi->ddc) return 0; @@ -2682,13 +2699,31 @@ static int dw_hdmi_qp_bridge_attach(struct drm_bridge *bridge, struct drm_connector *connector = &hdmi->connector; struct cec_connector_info conn_info; struct cec_notifier *notifier; + bool skip_connector = false; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) + if (hdmi->next_bridge) { + struct drm_bridge *next_bridge = hdmi->next_bridge; + int ret; + + ret = drm_bridge_attach(bridge->encoder, next_bridge, bridge, + next_bridge->ops & DRM_BRIDGE_OP_MODES ? + DRM_BRIDGE_ATTACH_NO_CONNECTOR : 0); + if (ret) { + DRM_ERROR("failed to attach next bridge: %d\n", ret); + return ret; + } + + skip_connector = !(next_bridge->ops & DRM_BRIDGE_OP_MODES); + } + + hdmi->skip_connector = skip_connector; + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR || skip_connector) return 0; connector->interlace_allowed = 1; connector->polled = DRM_CONNECTOR_POLL_HPD; - + if (hdmi->next_bridge && hdmi->next_bridge->ops & DRM_BRIDGE_OP_DETECT) + connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; drm_connector_helper_add(connector, &dw_hdmi_connector_helper_funcs); drm_connector_init(bridge->dev, connector, &dw_hdmi_connector_funcs, @@ -3352,10 +3387,11 @@ __dw_hdmi_probe(struct platform_device *pdev, struct dw_hdmi_qp_cec_data cec; struct resource *iores = NULL; struct drm_panel *panel = NULL; + struct drm_bridge *bridge = NULL; int irq; int ret; - ret = drm_of_find_panel_or_bridge(np, 1, -1, &panel, NULL); + ret = drm_of_find_panel_or_bridge(np, 1, -1, &panel, &bridge); if (ret < 0 && ret != -ENODEV) return ERR_PTR(ret); @@ -3364,6 +3400,7 @@ __dw_hdmi_probe(struct platform_device *pdev, return ERR_PTR(-ENOMEM); hdmi->panel = panel; + hdmi->next_bridge = bridge; hdmi->connector.stereo_allowed = 1; hdmi->plat_data = plat_data; hdmi->dev = dev; @@ -3646,6 +3683,10 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev, } plat_data->connector = &hdmi->connector; + if (hdmi->skip_connector && hdmi->next_bridge) + plat_data->bridge = hdmi->next_bridge; + else + plat_data->bridge = NULL; } if (plat_data->split_mode && !hdmi->plat_data->first_screen) { diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c index fe7f9480e71c..7350c96a998e 100644 --- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c +++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c @@ -3656,7 +3656,20 @@ static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master, drm_encoder_cleanup(&hdmi->encoder); } - if (plat_data->connector) { + if (plat_data->bridge) { + struct drm_connector *connector = NULL; + struct list_head *connector_list = + &plat_data->bridge->dev->mode_config.connector_list; + + list_for_each_entry(connector, connector_list, head) + if (drm_connector_has_possible_encoder(connector, + &hdmi->encoder)) + break; + + hdmi->sub_dev.connector = connector; + hdmi->sub_dev.of_node = dev->of_node; + rockchip_drm_register_sub_dev(&hdmi->sub_dev); + } else if (plat_data->connector) { hdmi->sub_dev.connector = plat_data->connector; hdmi->sub_dev.loader_protect = dw_hdmi_rockchip_encoder_loader_protect; if (secondary && device_property_read_bool(secondary->dev, "split-mode")) diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h index 302e4536a039..84020553cbf8 100644 --- a/include/drm/bridge/dw_hdmi.h +++ b/include/drm/bridge/dw_hdmi.h @@ -260,6 +260,7 @@ struct dw_hdmi_plat_data { /* Vendor Property support */ const struct dw_hdmi_property_ops *property_ops; struct drm_connector *connector; + struct drm_bridge *bridge; }; struct dw_hdmi_cec_wake_ops {