[PATCH 2/2] drm/i915/dp: Add device specific quirk to limit eDP rate to HBR2
Nautiyal, Ankit K
ankit.k.nautiyal at intel.com
Thu Jul 10 04:46:27 UTC 2025
On 7/9/2025 11:35 PM, Ville Syrjälä wrote:
> On Wed, Jul 09, 2025 at 11:21:43AM +0530, Ankit Nautiyal wrote:
>> Some ICL/TGL platforms with combo PHY ports suffer from signal integrity
>> issues at HBR3. While certain systems include a Parade PS8461 mux to
>> mitigate this, its presence cannot be reliably detected. Furthermore,
>> broken or missing VBT entries make it unsafe to rely on VBT for enforcing
>> link rate limits.
>>
>> To address this introduce a device specific quirk to cap the eDP link rate
>> to HBR2 (540000 kHz). This will override any higher advertised rates from
>> the sink or DPCD for specific devices.
>>
>> Currently, the quirk is added for Dell XPS 13 7390 2-in-1 which is reported
>> in gitlab issue #5969 [1].
>>
>> [1] https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5969
>>
>> v2: Align the quirk with the intended quirk name and refactor the
>> condition to use min(). (Jani)
>>
>> Cc: Jani Nikula <jani.nikula at linux.intel.com>
>> Cc: Ville Syrjälä <ville.syrjala at linux.intel.com>
>> Closes: https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/5969
>> Signed-off-by: Ankit Nautiyal <ankit.k.nautiyal at intel.com>
>> ---
>> drivers/gpu/drm/i915/display/intel_dp.c | 41 +++++++++++++++++----
>> drivers/gpu/drm/i915/display/intel_quirks.c | 9 +++++
>> drivers/gpu/drm/i915/display/intel_quirks.h | 1 +
>> 3 files changed, 44 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
>> index 92abf819e60e..7d2eaa0cff73 100644
>> --- a/drivers/gpu/drm/i915/display/intel_dp.c
>> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
>> @@ -173,10 +173,24 @@ int intel_dp_link_symbol_clock(int rate)
>>
>> static int max_dprx_rate(struct intel_dp *intel_dp)
>> {
>> + struct intel_display *display = to_intel_display(intel_dp);
>> + int max_rate;
>> +
>> if (intel_dp_tunnel_bw_alloc_is_enabled(intel_dp))
>> - return drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel);
>> + max_rate = drm_dp_tunnel_max_dprx_rate(intel_dp->tunnel);
>> + else
>> + max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
>> +
>> + /*
>> + * Some platforms + eDP panels may not reliably support HBR3
>> + * due to signal integrity limitations, despite advertising it.
>> + * Cap the link rate to HBR2 to avoid unstable configurations for the
>> + * known machines.
>> + */
>> + if (intel_dp_is_edp(intel_dp) && intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2))
>> + max_rate = min(max_rate, 540000);
>>
>> - return drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
>> + return max_rate;
>> }
>>
>> static int max_dprx_lane_count(struct intel_dp *intel_dp)
>> @@ -4255,6 +4269,8 @@ static void intel_edp_mso_init(struct intel_dp *intel_dp)
>> static void
>> intel_edp_set_sink_rates(struct intel_dp *intel_dp)
>> {
>> + struct intel_display *display = to_intel_display(intel_dp);
>> +
>> intel_dp->num_sink_rates = 0;
>>
>> if (intel_dp->edp_dpcd[0] >= DP_EDP_14) {
>> @@ -4265,10 +4281,7 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp)
>> sink_rates, sizeof(sink_rates));
>>
>> for (i = 0; i < ARRAY_SIZE(sink_rates); i++) {
>> - int val = le16_to_cpu(sink_rates[i]);
>> -
>> - if (val == 0)
>> - break;
>> + int rate;
>>
>> /* Value read multiplied by 200kHz gives the per-lane
>> * link rate in kHz. The source rates are, however,
>> @@ -4276,7 +4289,21 @@ intel_edp_set_sink_rates(struct intel_dp *intel_dp)
>> * back to symbols is
>> * (val * 200kHz)*(8/10 ch. encoding)*(1/8 bit to Byte)
>> */
>> - intel_dp->sink_rates[i] = (val * 200) / 10;
>> + rate = (le16_to_cpu(sink_rates[i]) * 200) / 10;
> Might as well drop the unnecessary parens while at it.
Right, the parens are not required, will drop it.
>
>> +
>> + if (rate == 0)
>> + break;
>> +
>> + /*
>> + * Some platforms cannot reliably drive HBR3 rates due to PHY limitations,
>> + * even if the sink advertises support. Reject any sink rates above HBR2 on
>> + * the known machines for stable output.
>> + */
>> + if (rate >= 810000 &&
>> + intel_has_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2))
> If the quirk sasy "HBR2" then we should probably check for >540000 instead.
I think I had earlier HBR3 in the name, but changed to HBR2.
Checking for > 540000 for ..LIMIT_RATE_HBR2 makes sense.
>
>> + break;
>> +
>> + intel_dp->sink_rates[i] = rate;
>> }
>> intel_dp->num_sink_rates = i;
>> }
>> diff --git a/drivers/gpu/drm/i915/display/intel_quirks.c b/drivers/gpu/drm/i915/display/intel_quirks.c
>> index a32fae510ed2..d2e16b79d6be 100644
>> --- a/drivers/gpu/drm/i915/display/intel_quirks.c
>> +++ b/drivers/gpu/drm/i915/display/intel_quirks.c
>> @@ -80,6 +80,12 @@ static void quirk_fw_sync_len(struct intel_dp *intel_dp)
>> drm_info(display->drm, "Applying Fast Wake sync pulse count quirk\n");
>> }
>>
>> +static void quirk_edp_limit_rate_hbr2(struct intel_display *display)
>> +{
>> + intel_set_quirk(display, QUIRK_EDP_LIMIT_RATE_HBR2);
>> + drm_info(display->drm, "Applying eDP Limit rate to HBR2 quirk\n");
>> +}
>> +
>> struct intel_quirk {
>> int device;
>> int subsystem_vendor;
>> @@ -231,6 +237,9 @@ static struct intel_quirk intel_quirks[] = {
>> { 0x3184, 0x1019, 0xa94d, quirk_increase_ddi_disabled_time },
>> /* HP Notebook - 14-r206nv */
>> { 0x0f31, 0x103c, 0x220f, quirk_invert_brightness },
>> +
>> + /* Dell XPS 13 7390 2-in-1 */
>> + { 0x8a12, 0x1028, 0x08b0, quirk_edp_limit_rate_hbr2 },
> Hmm. I wonder if different modesl of that same machine might
> come with different panels, some of which might work with/need
> HBR3...
>
> But I suppose we don't have any nice way to combine different types
> of quirks (ie. PCI ID + DPCD, DMI + EDID, etc.). We should probably
> think about coming up with some kind of generic quirk framework that
> can do such things nicely.
In this specific case the Panel desc only had OUI details and device ID
read as "ABCDEF" from DPCD.
So, I just went with device specific quirk. But you are right, we need a
mechanism to combine quirks.
>
> Anyways I guess this is fine for now. But we might have to revise this
> later if it turns out there are other variants of that machine around.
Yes lets see, if we get further issues with different panels with same
device id.
Thanks for the comments and suggestions, I will send the updated
revision soon.
Regards,
Ankit
>
>> };
>>
>> static const struct intel_dpcd_quirk intel_dpcd_quirks[] = {
>> diff --git a/drivers/gpu/drm/i915/display/intel_quirks.h b/drivers/gpu/drm/i915/display/intel_quirks.h
>> index cafdebda7535..06da0e286c67 100644
>> --- a/drivers/gpu/drm/i915/display/intel_quirks.h
>> +++ b/drivers/gpu/drm/i915/display/intel_quirks.h
>> @@ -20,6 +20,7 @@ enum intel_quirk_id {
>> QUIRK_LVDS_SSC_DISABLE,
>> QUIRK_NO_PPS_BACKLIGHT_POWER_HOOK,
>> QUIRK_FW_SYNC_LEN,
>> + QUIRK_EDP_LIMIT_RATE_HBR2,
>> };
>>
>> void intel_init_quirks(struct intel_display *display);
>> --
>> 2.45.2
More information about the Intel-xe
mailing list