drm/msm/dp: Read DPCD and sink count in bridge detect()

Instead of relying on the link_ready flag to specify if DP is connected,
read the DPCD bits and get the sink count to accurately detect if DP is
connected.

Signed-off-by: Jessica Zhang <jessica.zhang@oss.qualcomm.com>
Tested-by: Val Packett <val@packett.cool> # x1e80100-dell-latitude-7455
Tested-by: Yongxing Mou <yongxing.mou@oss.qualcomm.com> # Hamoa IOT EVK, QCS8300 Ride
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Patchwork: https://patchwork.freedesktop.org/patch/727603/
Link: https://lore.kernel.org/r/20260524-hpd-refactor-v6-3-cf3ab488dd7b@oss.qualcomm.com
This commit is contained in:
Jessica Zhang 2026-05-24 13:33:31 +03:00 committed by Dmitry Baryshkov
parent 3fbfdc3b1d
commit 0f2293dfb5
3 changed files with 65 additions and 20 deletions

View File

@ -1152,6 +1152,69 @@ static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_p
return 0;
}
/**
* msm_dp_bridge_detect - callback to determine if connector is connected
*
* @bridge: Pointer to drm bridge structure
* @connector: Pointer to drm connector structure
*
* Returns: where there is a display connected to the DPTX (returning
* disconnected for branch devices without DP Sinks being connected).
*/
enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
struct drm_connector *connector)
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int status = connector_status_disconnected;
struct msm_dp_display_private *priv;
u8 dpcd[DP_RECEIVER_CAP_SIZE];
struct drm_dp_desc desc;
int ret;
dp = to_dp_bridge(bridge)->msm_dp_display;
priv = container_of(dp, struct msm_dp_display_private, msm_dp_display);
if (!dp->link_ready)
return status;
msm_dp_aux_enable_xfers(priv->aux, true);
ret = pm_runtime_resume_and_get(&dp->pdev->dev);
if (ret) {
DRM_ERROR("failed to pm_runtime_resume\n");
msm_dp_aux_enable_xfers(priv->aux, false);
return status;
}
ret = msm_dp_aux_is_link_connected(priv->aux);
if (dp->internal_hpd && !ret)
goto end;
ret = drm_dp_read_dpcd_caps(priv->aux, dpcd);
if (ret)
goto end;
ret = drm_dp_read_desc(priv->aux, &desc, drm_dp_is_branch(dpcd));
if (ret)
goto end;
status = connector_status_connected;
if (drm_dp_read_sink_count_cap(connector, dpcd, &desc)) {
int sink_count = drm_dp_read_sink_count(priv->aux);
drm_dbg_dp(dp->drm_dev, "sink_count = %d\n", sink_count);
if (sink_count <= 0)
status = connector_status_disconnected;
}
end:
pm_runtime_put_sync(&dp->pdev->dev);
return status;
}
static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
{
struct msm_dp_display_private *dp = dev_id;

View File

@ -15,26 +15,6 @@
#include "dp_audio.h"
#include "dp_drm.h"
/**
* msm_dp_bridge_detect - callback to determine if connector is connected
* @bridge: Pointer to drm bridge structure
* @connector: Pointer to drm connector structure
* Returns: Bridge's 'is connected' status
*/
static enum drm_connector_status
msm_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector)
{
struct msm_dp *dp;
dp = to_dp_bridge(bridge)->msm_dp_display;
drm_dbg_dp(dp->drm_dev, "link_ready = %s\n",
str_true_false(dp->link_ready));
return (dp->link_ready) ? connector_status_connected :
connector_status_disconnected;
}
static int msm_dp_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,

View File

@ -25,6 +25,8 @@ int msm_dp_bridge_init(struct msm_dp *msm_dp_display, struct drm_device *dev,
struct drm_encoder *encoder,
bool yuv_supported);
enum drm_connector_status msm_dp_bridge_detect(struct drm_bridge *bridge,
struct drm_connector *connector);
void msm_dp_bridge_atomic_enable(struct drm_bridge *drm_bridge,
struct drm_atomic_state *state);
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,