Skip to content

Commit b87ed52

Browse files
committed
drm/dp: Add an EDID quirk for the DPCD register access probe
Reading DPCD registers has side-effects and some of these can cause a problem for instance during link training. Based on this it's better to avoid the probing quirk done before each DPCD register read, limiting this to the monitor which requires it. Add an EDID quirk for this. Leave the quirk enabled by default, allowing it to be disabled after the monitor is detected. v2: Fix lockdep wrt. drm_dp_aux::hw_mutex when calling drm_dp_dpcd_set_probe_quirk() with a dependent lock already held. v3: Add a helper for determining if DPCD probing is needed. (Jani) v4: - s/drm_dp_dpcd_set_probe_quirk/drm_dp_dpcd_set_probe (Jani) - Fix documentation of drm_dp_dpcd_set_probe(). - Add comment at the end of internal quirk entries. Cc: Ville Syrjälä <[email protected]> Cc: Jani Nikula <[email protected]> Reviewed-by: Jani Nikula <[email protected]> Signed-off-by: Imre Deak <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 0b4aa85 commit b87ed52

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

drivers/gpu/drm/display/drm_dp_helper.c

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,34 @@ void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered)
691691
}
692692
EXPORT_SYMBOL(drm_dp_dpcd_set_powered);
693693

694+
/**
695+
* drm_dp_dpcd_set_probe() - Set whether a probing before DPCD access is done
696+
* @aux: DisplayPort AUX channel
697+
* @enable: Enable the probing if required
698+
*/
699+
void drm_dp_dpcd_set_probe(struct drm_dp_aux *aux, bool enable)
700+
{
701+
WRITE_ONCE(aux->dpcd_probe_disabled, !enable);
702+
}
703+
EXPORT_SYMBOL(drm_dp_dpcd_set_probe);
704+
705+
static bool dpcd_access_needs_probe(struct drm_dp_aux *aux)
706+
{
707+
/*
708+
* HP ZR24w corrupts the first DPCD access after entering power save
709+
* mode. Eg. on a read, the entire buffer will be filled with the same
710+
* byte. Do a throw away read to avoid corrupting anything we care
711+
* about. Afterwards things will work correctly until the monitor
712+
* gets woken up and subsequently re-enters power save mode.
713+
*
714+
* The user pressing any button on the monitor is enough to wake it
715+
* up, so there is no particularly good place to do the workaround.
716+
* We just have to do it before any DPCD access and hope that the
717+
* monitor doesn't power down exactly after the throw away read.
718+
*/
719+
return !aux->is_remote && !READ_ONCE(aux->dpcd_probe_disabled);
720+
}
721+
694722
/**
695723
* drm_dp_dpcd_read() - read a series of bytes from the DPCD
696724
* @aux: DisplayPort AUX channel (SST or MST)
@@ -712,19 +740,7 @@ ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
712740
{
713741
int ret;
714742

715-
/*
716-
* HP ZR24w corrupts the first DPCD access after entering power save
717-
* mode. Eg. on a read, the entire buffer will be filled with the same
718-
* byte. Do a throw away read to avoid corrupting anything we care
719-
* about. Afterwards things will work correctly until the monitor
720-
* gets woken up and subsequently re-enters power save mode.
721-
*
722-
* The user pressing any button on the monitor is enough to wake it
723-
* up, so there is no particularly good place to do the workaround.
724-
* We just have to do it before any DPCD access and hope that the
725-
* monitor doesn't power down exactly after the throw away read.
726-
*/
727-
if (!aux->is_remote) {
743+
if (dpcd_access_needs_probe(aux)) {
728744
ret = drm_dp_dpcd_probe(aux, DP_LANE0_1_STATUS);
729745
if (ret < 0)
730746
return ret;

drivers/gpu/drm/drm_edid.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,14 @@ static const struct edid_quirk {
248248
/* OSVR HDK and HDK2 VR Headsets */
249249
EDID_QUIRK('S', 'V', 'R', 0x1019, BIT(EDID_QUIRK_NON_DESKTOP)),
250250
EDID_QUIRK('A', 'U', 'O', 0x1111, BIT(EDID_QUIRK_NON_DESKTOP)),
251+
252+
/*
253+
* @drm_edid_internal_quirk entries end here, following with the
254+
* @drm_edid_quirk entries.
255+
*/
256+
257+
/* HP ZR24w DP AUX DPCD access requires probing to prevent corruption. */
258+
EDID_QUIRK('H', 'W', 'P', 0x2869, BIT(DRM_EDID_QUIRK_DP_DPCD_PROBE)),
251259
};
252260

253261
/*

include/drm/display/drm_dp_helper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,10 +523,16 @@ struct drm_dp_aux {
523523
* @no_zero_sized: If the hw can't use zero sized transfers (NVIDIA)
524524
*/
525525
bool no_zero_sized;
526+
527+
/**
528+
* @dpcd_probe_disabled: If probing before a DPCD access is disabled.
529+
*/
530+
bool dpcd_probe_disabled;
526531
};
527532

528533
int drm_dp_dpcd_probe(struct drm_dp_aux *aux, unsigned int offset);
529534
void drm_dp_dpcd_set_powered(struct drm_dp_aux *aux, bool powered);
535+
void drm_dp_dpcd_set_probe(struct drm_dp_aux *aux, bool enable);
530536
ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
531537
void *buffer, size_t size);
532538
ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,

include/drm/drm_edid.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ struct detailed_data_string {
110110
#define DRM_EDID_CVT_FLAGS_REDUCED_BLANKING (1 << 4)
111111

112112
enum drm_edid_quirk {
113+
/* Do a dummy read before DPCD accesses, to prevent corruption. */
114+
DRM_EDID_QUIRK_DP_DPCD_PROBE,
115+
113116
DRM_EDID_QUIRK_NUM,
114117
};
115118

0 commit comments

Comments
 (0)