[PATCH] drm/rockchip: cdn-dp: Convert to drm bridge

Chaoyi Chen chaoyi.chen at rock-chips.com
Thu May 22 01:31:02 UTC 2025


Hi Andy,

On 2025/5/21 20:09, Andy Yan wrote:
> Hi Chaoyi,
>
> At 2025-05-07 11:51:48, "Chaoyi Chen" <kernel at airkyi.com> wrote:
>> From: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>>
>> Convert it to drm bridge driver, it will be convenient for us to
>> migrate the connector part to the display driver later.
>>
>> Tested with RK3399 EVB IND board.
>>
>> Signed-off-by: Chaoyi Chen <chaoyi.chen at rock-chips.com>
>> ---
>> drivers/gpu/drm/rockchip/cdn-dp-core.c | 163 +++++++++++++------------
>> drivers/gpu/drm/rockchip/cdn-dp-core.h |   5 +-
>> 2 files changed, 86 insertions(+), 82 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> index 292c31de18f1..bc70dae8ff72 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
>> @@ -25,9 +25,9 @@
>> #include "cdn-dp-core.h"
>> #include "cdn-dp-reg.h"
>>
>> -static inline struct cdn_dp_device *connector_to_dp(struct drm_connector *connector)
>> +static inline struct cdn_dp_device *bridge_to_dp(struct drm_bridge *bridge)
>> {
>> -	return container_of(connector, struct cdn_dp_device, connector);
>> +	return container_of(bridge, struct cdn_dp_device, bridge);
>> }
>>
>> static inline struct cdn_dp_device *encoder_to_dp(struct drm_encoder *encoder)
>> @@ -231,9 +231,9 @@ static bool cdn_dp_check_sink_connection(struct cdn_dp_device *dp)
>> }
>>
>> static enum drm_connector_status
>> -cdn_dp_connector_detect(struct drm_connector *connector, bool force)
>> +cdn_dp_bridge_detect(struct drm_bridge *bridge)
>> {
>> -	struct cdn_dp_device *dp = connector_to_dp(connector);
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> 	enum drm_connector_status status = connector_status_disconnected;
>>
>> 	mutex_lock(&dp->lock);
>> @@ -244,41 +244,26 @@ cdn_dp_connector_detect(struct drm_connector *connector, bool force)
>> 	return status;
>> }
>>
>> -static void cdn_dp_connector_destroy(struct drm_connector *connector)
>> +static const struct drm_edid *
>> +cdn_dp_connector_edid_read(struct drm_bridge *bridge, struct drm_connector *connector)
> This should be cdn_dp_bridge_edid_read

Will fix in v2.


>
>> {
>> -	drm_connector_unregister(connector);
>> -	drm_connector_cleanup(connector);
>> -}
>> -
>> -static const struct drm_connector_funcs cdn_dp_atomic_connector_funcs = {
>> -	.detect = cdn_dp_connector_detect,
>> -	.destroy = cdn_dp_connector_destroy,
>> -	.fill_modes = drm_helper_probe_single_connector_modes,
>> -	.reset = drm_atomic_helper_connector_reset,
>> -	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
>> -	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
>> -};
>> -
>> -static int cdn_dp_connector_get_modes(struct drm_connector *connector)
>> -{
>> -	struct cdn_dp_device *dp = connector_to_dp(connector);
>> -	int ret = 0;
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> +	const struct drm_edid *drm_edid;
>>
>> 	mutex_lock(&dp->lock);
>> -
>> -	ret = drm_edid_connector_add_modes(connector);
>> -
>> +	drm_edid = drm_edid_read_custom(dp->connector,
>> +					cdn_dp_get_edid_block, dp);
> Use drm_edid_read_ddc

drm_edid_read_ddc() need a i2c_adapter, but cdn-dp doesn't have it.


>
>> 	mutex_unlock(&dp->lock);
>>
>> -	return ret;
>> +	return drm_edid;
>> }
>>
>> static enum drm_mode_status
>> -cdn_dp_connector_mode_valid(struct drm_connector *connector,
>> -			    const struct drm_display_mode *mode)
>> +cdn_dp_bridge_mode_valid(struct drm_bridge *bridge,
>> +			 const struct drm_display_info *display_info,
>> +			 const struct drm_display_mode *mode)
>> {
>> -	struct cdn_dp_device *dp = connector_to_dp(connector);
>> -	struct drm_display_info *display_info = &dp->connector.display_info;
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> 	u32 requested, actual, rate, sink_max, source_max = 0;
>> 	u8 lanes, bpc;
>>
>> @@ -323,11 +308,6 @@ cdn_dp_connector_mode_valid(struct drm_connector *connector,
>> 	return MODE_OK;
>> }
>>
>> -static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = {
>> -	.get_modes = cdn_dp_connector_get_modes,
>> -	.mode_valid = cdn_dp_connector_mode_valid,
>> -};
>> -
>> static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
>> {
>> 	int ret;
>> @@ -360,7 +340,7 @@ static int cdn_dp_firmware_init(struct cdn_dp_device *dp)
>>
>> static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
>> {
>> -	const struct drm_display_info *info = &dp->connector.display_info;
>> +	const struct drm_display_info *info = &dp->connector->display_info;
>> 	int ret;
>>
>> 	if (!cdn_dp_check_sink_connection(dp))
>> @@ -374,9 +354,9 @@ static int cdn_dp_get_sink_capability(struct cdn_dp_device *dp)
>> 	}
>>
>> 	drm_edid_free(dp->drm_edid);
>> -	dp->drm_edid = drm_edid_read_custom(&dp->connector,
>> +	dp->drm_edid = drm_edid_read_custom(dp->connector,
>> 					    cdn_dp_get_edid_block, dp);
>> -	drm_edid_connector_update(&dp->connector, dp->drm_edid);
>> +	drm_edid_connector_update(dp->connector, dp->drm_edid);
>>
>> 	dp->sink_has_audio = info->has_audio;
>>
>> @@ -416,11 +396,11 @@ static int cdn_dp_enable_phy(struct cdn_dp_device *dp, struct cdn_dp_port *port)
>> 		goto err_power_on;
>> 	}
>>
>> -	ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
>> -				  EXTCON_PROP_USB_TYPEC_POLARITY, &property);
>> -	if (ret) {
>> -		DRM_DEV_ERROR(dp->dev, "get property failed\n");
>> -		goto err_power_on;
>> +		ret = extcon_get_property(port->extcon, EXTCON_DISP_DP,
>> +					EXTCON_PROP_USB_TYPEC_POLARITY, &property);
>> +		if (ret) {
>> +			DRM_DEV_ERROR(dp->dev, "get property failed\n");
>> +			goto err_power_on;
>> 	}
>>
>> 	port->lanes = cdn_dp_get_port_lanes(port);
>> @@ -551,7 +531,7 @@ static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
>> 				    struct drm_display_mode *adjusted)
>> {
>> 	struct cdn_dp_device *dp = encoder_to_dp(encoder);
>> -	struct drm_display_info *display_info = &dp->connector.display_info;
>> +	struct drm_display_info *display_info = &dp->connector->display_info;
>> 	struct video_info *video = &dp->video_info;
>>
>> 	switch (display_info->bpc) {
>> @@ -599,12 +579,12 @@ static void cdn_dp_audio_handle_plugged_change(struct cdn_dp_device *dp,
>> 		dp->plugged_cb(dp->codec_dev, plugged);
>> }
>>
>> -static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
>> +static void cdn_dp_bridge_atomic_enable(struct drm_bridge *bridge, struct drm_atomic_state *state)
>> {
>> -	struct cdn_dp_device *dp = encoder_to_dp(encoder);
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> 	int ret, val;
>>
>> -	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
>> +	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, &dp->encoder.encoder);
>> 	if (ret < 0) {
>> 		DRM_DEV_ERROR(dp->dev, "Could not get vop id, %d", ret);
>> 		return;
>> @@ -625,7 +605,7 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
>>
>> 	ret = cdn_dp_enable(dp);
>> 	if (ret) {
>> -		DRM_DEV_ERROR(dp->dev, "Failed to enable encoder %d\n",
>> +		DRM_DEV_ERROR(dp->dev, "Failed to enable bridge %d\n",
>> 			      ret);
>> 		goto out;
>> 	}
>> @@ -661,9 +641,9 @@ static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
>> 	mutex_unlock(&dp->lock);
>> }
>>
>> -static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
>> +static void cdn_dp_bridge_atomic_disable(struct drm_bridge *bridge, struct drm_atomic_state *state)
>> {
>> -	struct cdn_dp_device *dp = encoder_to_dp(encoder);
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> 	int ret;
>>
>> 	mutex_lock(&dp->lock);
>> @@ -672,7 +652,7 @@ static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
>> 	if (dp->active) {
>> 		ret = cdn_dp_disable(dp);
>> 		if (ret) {
>> -			DRM_DEV_ERROR(dp->dev, "Failed to disable encoder %d\n",
>> +			DRM_DEV_ERROR(dp->dev, "Failed to disable bridge %d\n",
>> 				      ret);
>> 		}
>> 	}
>> @@ -703,13 +683,31 @@ static int cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
>> 	return 0;
>> }
>>
>> +static void cdn_dp_hpd_notify(struct drm_bridge *bridge,
>> +			   enum drm_connector_status status)
>> +{
>> +	struct cdn_dp_device *dp = bridge_to_dp(bridge);
>> +
>> +	schedule_work(&dp->event_work);
>> +}
>> +
>> static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
>> 	.mode_set = cdn_dp_encoder_mode_set,
>> -	.enable = cdn_dp_encoder_enable,
>> -	.disable = cdn_dp_encoder_disable,
>> 	.atomic_check = cdn_dp_encoder_atomic_check,
>> };
>>
>> +static const struct drm_bridge_funcs cdn_dp_bridge_funcs = {
>> +	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
>> +	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
>> +	.atomic_reset = drm_atomic_helper_bridge_reset,
>> +	.detect = cdn_dp_bridge_detect,
>> +	.edid_read = cdn_dp_connector_edid_read,
>> +	.atomic_enable = cdn_dp_bridge_atomic_enable,
>> +	.atomic_disable = cdn_dp_bridge_atomic_disable,
>> +	.mode_valid = cdn_dp_bridge_mode_valid,
>> +	.hpd_notify = cdn_dp_hpd_notify,
>> +};
>> +
>> static int cdn_dp_parse_dt(struct cdn_dp_device *dp)
>> {
>> 	struct device *dev = dp->dev;
>> @@ -859,7 +857,7 @@ static int cdn_dp_audio_get_eld(struct device *dev, void *data,
>> {
>> 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
>>
>> -	memcpy(buf, dp->connector.eld, min(sizeof(dp->connector.eld), len));
>> +	memcpy(buf, dp->connector->eld, min(sizeof(dp->connector->eld), len));
>>
>> 	return 0;
>> }
>> @@ -1006,7 +1004,6 @@ static void cdn_dp_pd_event_work(struct work_struct *work)
>>
>> out:
>> 	mutex_unlock(&dp->lock);
>> -	drm_connector_helper_hpd_irq_event(&dp->connector);
>> }
>>
>> static int cdn_dp_pd_event(struct notifier_block *nb,
>> @@ -1030,7 +1027,6 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
>> {
>> 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
>> 	struct drm_encoder *encoder;
>> -	struct drm_connector *connector;
>> 	struct cdn_dp_port *port;
>> 	struct drm_device *drm_dev = data;
>> 	int ret, i;
>> @@ -1053,6 +1049,15 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
>> 							     dev->of_node);
>> 	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
>>
>> +	/*
>> +	 * If we failed to find the CRTC(s) which this encoder is
>> +	 * supposed to be connected to, it's because the CRTC has
>> +	 * not been registered yet. Defer probing, and hope that
>> +	 * the required CRTC is added later.
>> +	 */
>> +	if (encoder->possible_crtcs == 0)
>> +		return -EPROBE_DEFER;
>> +
>> 	ret = drm_simple_encoder_init(drm_dev, encoder,
>> 				      DRM_MODE_ENCODER_TMDS);
>> 	if (ret) {
>> @@ -1062,26 +1067,31 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
>>
>> 	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
>>
>> -	connector = &dp->connector;
>> -	connector->polled = DRM_CONNECTOR_POLL_HPD;
>> -	connector->dpms = DRM_MODE_DPMS_OFF;
>> +	dp->bridge.driver_private = dp;
>> +	dp->bridge.funcs = &cdn_dp_bridge_funcs;
> Try use devm_drm_bridge_alloc

Okay, I will try to use this in v2.


>
>> +	dp->bridge.ops = DRM_BRIDGE_OP_DETECT |
>> +			   DRM_BRIDGE_OP_EDID |
>> +			   DRM_BRIDGE_OP_HPD;
>> +	dp->bridge.of_node = dp->dev->of_node;
>> +	dp->bridge.type = DRM_MODE_CONNECTOR_DisplayPort;
>>
>> -	ret = drm_connector_init(drm_dev, connector,
>> -				 &cdn_dp_atomic_connector_funcs,
>> -				 DRM_MODE_CONNECTOR_DisplayPort);
>> -	if (ret) {
>> -		DRM_ERROR("failed to initialize connector with drm\n");
>> -		goto err_free_encoder;
>> -	}
>> +	ret = devm_drm_bridge_add(dev, &dp->bridge);
>> +	if (ret)
>> +		return ret;
>>
>> -	drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs);
>> +	ret = drm_bridge_attach(encoder, &dp->bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR);
>> +	if (ret)
>> +		return ret;
>>
>> -	ret = drm_connector_attach_encoder(connector, encoder);
>> -	if (ret) {
>> -		DRM_ERROR("failed to attach connector and encoder\n");
>> -		goto err_free_connector;
>> +	dp->connector = drm_bridge_connector_init(drm_dev, encoder);
>> +	if (IS_ERR(dp->connector)) {
>> +		ret = PTR_ERR(dp->connector);
>> +		dev_err(dp->dev, "failed to init bridge connector: %d\n", ret);
>> +		return ret;
>> 	}
>         Don't store connector here, we will move connector init to display controller side in the future.
>
>        You can get connector by: connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
>        at atomic enable.

Will fix in v2.


>
>> +	drm_connector_attach_encoder(dp->connector, encoder);
>> +
>> 	for (i = 0; i < dp->ports; i++) {
>> 		port = dp->port[i];
>>
>> @@ -1092,7 +1102,7 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
>> 		if (ret) {
>> 			DRM_DEV_ERROR(dev,
>> 				      "register EXTCON_DISP_DP notifier err\n");
>> -			goto err_free_connector;
>> +			return ret;
>> 		}
>> 	}
>>
>> @@ -1101,24 +1111,15 @@ static int cdn_dp_bind(struct device *dev, struct device *master, void *data)
>> 	schedule_work(&dp->event_work);
>>
>> 	return 0;
>> -
>> -err_free_connector:
>> -	drm_connector_cleanup(connector);
>> -err_free_encoder:
>> -	drm_encoder_cleanup(encoder);
>> -	return ret;
>> }
>>
>> static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
>> {
>> 	struct cdn_dp_device *dp = dev_get_drvdata(dev);
>> 	struct drm_encoder *encoder = &dp->encoder.encoder;
>> -	struct drm_connector *connector = &dp->connector;
>>
>> 	cancel_work_sync(&dp->event_work);
>> -	cdn_dp_encoder_disable(encoder);
>> 	encoder->funcs->destroy(encoder);
>> -	connector->funcs->destroy(connector);
>>
>> 	pm_runtime_disable(dev);
>> 	if (dp->fw_loaded)
>> diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> index 17498f576ce7..d2778f7a5b31 100644
>> --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
>> @@ -8,6 +8,8 @@
>> #define _CDN_DP_CORE_H
>>
>> #include <drm/display/drm_dp_helper.h>
>> +#include <drm/drm_bridge.h>
>> +#include <drm/drm_bridge_connector.h>
>> #include <drm/drm_panel.h>
>> #include <drm/drm_probe_helper.h>
>> #include <sound/hdmi-codec.h>
>> @@ -65,7 +67,8 @@ struct cdn_dp_port {
>> struct cdn_dp_device {
>> 	struct device *dev;
>> 	struct drm_device *drm_dev;
>> -	struct drm_connector connector;
>> +	struct drm_bridge bridge;
>> +	struct drm_connector *connector;
>> 	struct rockchip_encoder encoder;
>> 	struct drm_display_mode mode;
>> 	struct platform_device *audio_pdev;
>> -- 
>> 2.49.0


More information about the dri-devel mailing list