* [PATCH 0/3] drm: zynqmp_dp: Retrain link after HPD if necessary
@ 2025-10-24 19:17 Sean Anderson
2025-10-24 19:17 ` [PATCH 1/3] drm: zynqmp_dp: Update connector state before AUX transfers Sean Anderson
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Sean Anderson @ 2025-10-24 19:17 UTC (permalink / raw)
To: Laurent Pinchart, Tomi Valkeinen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, dri-devel
Cc: linux-kernel, David Airlie, Hyun Kwon, Simona Vetter,
Michal Simek, linux-arm-kernel, Sean Anderson
I noticed that after reconnecting a mini-displayport cable, the sink
would not display an image. But if I forced the link to re-train, the
image would come back.
Some digging revealed that the DP spec requires retraining after a HPD
event if the sink syas the link has gone down. So implement that since
it fixes my problem and it's required by spec.
Sean Anderson (3):
drm: zynqmp_dp: Update connector state before AUX transfers
drm: zynqmp_dp: Use smp_load/store for status
drm: zynqmp_dp: Retrain link after HPD if necessary
drivers/gpu/drm/xlnx/zynqmp_dp.c | 43 +++++++++++++++++++-------------
1 file changed, 26 insertions(+), 17 deletions(-)
--
2.35.1.1320.gc452695387.dirty
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/3] drm: zynqmp_dp: Update connector state before AUX transfers
2025-10-24 19:17 [PATCH 0/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
@ 2025-10-24 19:17 ` Sean Anderson
2025-10-24 19:17 ` [PATCH 2/3] drm: zynqmp_dp: Use smp_load/store for status Sean Anderson
2025-10-24 19:17 ` [PATCH 3/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
2 siblings, 0 replies; 4+ messages in thread
From: Sean Anderson @ 2025-10-24 19:17 UTC (permalink / raw)
To: Laurent Pinchart, Tomi Valkeinen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, dri-devel
Cc: linux-kernel, David Airlie, Hyun Kwon, Simona Vetter,
Michal Simek, linux-arm-kernel, Sean Anderson
We still want to retry AUX transfers even when the connector is first
plugged in. Update the connector state before reading the DPDC to ensure
the AUX bus sees the most-recent state.
Fixes: d76271d22694 ("drm: xlnx: DRM/KMS driver for Xilinx ZynqMP DisplayPort Subsystem")
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
---
drivers/gpu/drm/xlnx/zynqmp_dp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index 34ddbf98e81d..f39c78b08e6a 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1697,6 +1697,7 @@ static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
}
if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD) {
+ dp->status = connector_status_connected;
ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd,
sizeof(dp->dpcd));
if (ret < 0) {
@@ -1711,7 +1712,6 @@ static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
drm_dp_max_lane_count(dp->dpcd),
dp->num_lanes);
- dp->status = connector_status_connected;
return connector_status_connected;
}
--
2.35.1.1320.gc452695387.dirty
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 2/3] drm: zynqmp_dp: Use smp_load/store for status
2025-10-24 19:17 [PATCH 0/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
2025-10-24 19:17 ` [PATCH 1/3] drm: zynqmp_dp: Update connector state before AUX transfers Sean Anderson
@ 2025-10-24 19:17 ` Sean Anderson
2025-10-24 19:17 ` [PATCH 3/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
2 siblings, 0 replies; 4+ messages in thread
From: Sean Anderson @ 2025-10-24 19:17 UTC (permalink / raw)
To: Laurent Pinchart, Tomi Valkeinen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, dri-devel
Cc: linux-kernel, David Airlie, Hyun Kwon, Simona Vetter,
Michal Simek, linux-arm-kernel, Sean Anderson
dp->status is read asynchronously by the AUX bus. Therefore, all reads
outside of dp->lock must be atomic. Similarly, writes must be atomic as
well. Reads with dp->lock held do not need to be atomic.
Fixes: a7d5eeaa57d7 ("drm: zynqmp_dp: Add locking")
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
---
drivers/gpu/drm/xlnx/zynqmp_dp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index f39c78b08e6a..caf2e0ce3644 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1111,7 +1111,7 @@ zynqmp_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
return msg->size;
}
- if (dp->status == connector_status_disconnected) {
+ if (READ_ONCE(dp->status) == connector_status_disconnected) {
dev_dbg(dp->dev, "no connected aux device\n");
if (dp->ignore_aux_errors)
goto fake_response;
@@ -1697,7 +1697,7 @@ static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
}
if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD) {
- dp->status = connector_status_connected;
+ WRITE_ONCE(dp->status, connector_status_connected);
ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd,
sizeof(dp->dpcd));
if (ret < 0) {
@@ -1716,7 +1716,7 @@ static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
}
disconnected:
- dp->status = connector_status_disconnected;
+ WRITE_ONCE(dp->status, connector_status_disconnected);
return connector_status_disconnected;
}
--
2.35.1.1320.gc452695387.dirty
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 3/3] drm: zynqmp_dp: Retrain link after HPD if necessary
2025-10-24 19:17 [PATCH 0/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
2025-10-24 19:17 ` [PATCH 1/3] drm: zynqmp_dp: Update connector state before AUX transfers Sean Anderson
2025-10-24 19:17 ` [PATCH 2/3] drm: zynqmp_dp: Use smp_load/store for status Sean Anderson
@ 2025-10-24 19:17 ` Sean Anderson
2 siblings, 0 replies; 4+ messages in thread
From: Sean Anderson @ 2025-10-24 19:17 UTC (permalink / raw)
To: Laurent Pinchart, Tomi Valkeinen, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, dri-devel
Cc: linux-kernel, David Airlie, Hyun Kwon, Simona Vetter,
Michal Simek, linux-arm-kernel, Sean Anderson
The section 5.1.4 of the v1.2 DisplayPort standard says
> The Source device shall respond to Hot Plug event/Hot Re-plug event by
> first reading DPCD Link/Sink Device Status registers at DPCD 00200h
> through 00205h.... If the link is unstable or lost, the Source device
> then reads the DPCD Receiver Capabilities registers at DPCD 00000h
> through 0000Fh to determine the appropriate information needed to
> train the link. The Source device shall then initiate link training.
However, zynqmp_dp_hpd_work_func does not check the link status. This
may prevent the sink from detecting the source if, for example, the user
disconnects the cable and then reconnects it. I encountered this problem
when testing a mini DP connector (although I had no problem when using a
full-size connector with the existing driver).
Follow the spec by checking the link status after a HPD event and
retraining if necessary.
Fixes: d76271d22694 ("drm: xlnx: DRM/KMS driver for Xilinx ZynqMP DisplayPort Subsystem")
Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
---
drivers/gpu/drm/xlnx/zynqmp_dp.c | 37 ++++++++++++++++++++------------
1 file changed, 23 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index caf2e0ce3644..a90bc0e406f6 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1677,6 +1677,24 @@ static int zynqmp_dp_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
+static bool zynqmp_hpd_needs_retain(struct zynqmp_dp *dp)
+{
+ u8 status[DP_LINK_STATUS_SIZE + 2];
+ int err;
+
+ err = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status,
+ DP_LINK_STATUS_SIZE + 2);
+ if (err < 0) {
+ dev_dbg_ratelimited(dp->dev,
+ "could not read sink status: %d\n", err);
+ return false;
+ }
+
+ return status[4] & DP_LINK_STATUS_UPDATED ||
+ !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) ||
+ !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt);
+}
+
static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
{
struct zynqmp_dp_link_config *link_config = &dp->link_config;
@@ -1698,6 +1716,9 @@ static enum drm_connector_status __zynqmp_dp_bridge_detect(struct zynqmp_dp *dp)
if (state & ZYNQMP_DP_INTERRUPT_SIGNAL_STATE_HPD) {
WRITE_ONCE(dp->status, connector_status_connected);
+ if (!zynqmp_hpd_needs_retain(dp))
+ return connector_status_connected;
+
ret = drm_dp_dpcd_read(&dp->aux, 0x0, dp->dpcd,
sizeof(dp->dpcd));
if (ret < 0) {
@@ -2335,25 +2356,13 @@ static void zynqmp_dp_hpd_irq_work_func(struct work_struct *work)
{
struct zynqmp_dp *dp = container_of(work, struct zynqmp_dp,
hpd_irq_work);
- u8 status[DP_LINK_STATUS_SIZE + 2];
- int err;
guard(mutex)(&dp->lock);
if (dp->ignore_hpd)
return;
- err = drm_dp_dpcd_read(&dp->aux, DP_SINK_COUNT, status,
- DP_LINK_STATUS_SIZE + 2);
- if (err < 0) {
- dev_dbg_ratelimited(dp->dev,
- "could not read sink status: %d\n", err);
- } else {
- if (status[4] & DP_LINK_STATUS_UPDATED ||
- !drm_dp_clock_recovery_ok(&status[2], dp->mode.lane_cnt) ||
- !drm_dp_channel_eq_ok(&status[2], dp->mode.lane_cnt)) {
- zynqmp_dp_train_loop(dp);
- }
- }
+ if (zynqmp_hpd_needs_retain(dp))
+ zynqmp_dp_train_loop(dp);
}
static irqreturn_t zynqmp_dp_irq_handler(int irq, void *data)
--
2.35.1.1320.gc452695387.dirty
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-10-24 19:23 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-24 19:17 [PATCH 0/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
2025-10-24 19:17 ` [PATCH 1/3] drm: zynqmp_dp: Update connector state before AUX transfers Sean Anderson
2025-10-24 19:17 ` [PATCH 2/3] drm: zynqmp_dp: Use smp_load/store for status Sean Anderson
2025-10-24 19:17 ` [PATCH 3/3] drm: zynqmp_dp: Retrain link after HPD if necessary Sean Anderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).