Re: [PATCH 7/8] drm/i915: Move max voltage and pre emphasis to intel_dp_link_training.c

Thulasimani, Sivakumar
2015-10-19T06:13:22Z

On 10/19/2015 11:29 AM, Ander Conselvan De Oliveira wrote:
> On Mon, 2015-10-19 at 10:44 +0530, Thulasimani, Sivakumar wrote:
>> As an FYI, both of these functions need to be rewritten when we want the
>> code to be
>> compliant to DP spec.
>> We should read the pre-emphasis given by the panel and if vwing exeeds
>> max value
>> we should use the max vswing supported for that pre-emphasis but current
>> code
>> is opposite of that. you can read more detailed logic in section
>> "3.5.1.2 Link Training"
>> in DP Spec.
> Yeah, the spec is pretty clear on that.
>
>
>> by the way same is true for much of the link training logic and related
>> functions
> Do you have a list of other spec violations? I'm aware that we don't fallback to
> lower bandwidth when link training fails, but that problem can't be solved with
> the driver alone. Since we already pick the lowest bandwidth that can support
> the mode chosen by userspace, the fallback needs to allow it to choose a new
> mode.
>
> There's been some discussion on how to solve this, but I don't know if there was
> any conclusions. One of the possibilities was to send an uevent to userspace to
> tell it to to choose a smaller mode.
here is a list of changes i had to do for local branch, that i should be
upstreaming in the future

drm/i915: Fix swing & emphasis usage (this is the patch for issue i
talked about above)
drm/i915: EQ retry must be 5 times only
drm/i915: Start link training from max link rate
drm/i915: Fix Clock recovery sequence ( fixes the whole clock recovery
to be per spec)
drm/i915: Fix EQ sequence in Link training (fixes the whole EQ to be per
spec)
drm/i915: Check EQ only if CR passed (This seems to be in place in your
changes)

All these are just related to link training, i have been asked for list
of issues recently
as well, so i will probably file each of them in bugzilla/freedesktop so
someone
will track it.

regards,
Sivakumar
>
>> i don't know if such rewriting should be done after fixing those or
>> before :(.
> I have posted a new version of the refactoring patches which I believed are
> ready to go. So I'd go for getting those changes in and fix the max voltage vs.
> pre-emphasis problem on top of that.
>
> Thanks,
> Ander
>
>> regards,
>> Sivakumar.
>>
>> On 9/8/2015 6:31 PM, Ville Syrjälä wrote:
>>> On Tue, Sep 08, 2015 at 03:27:58PM +0300, Ander Conselvan de Oliveira wrote:
>>>> So link training tests can use real hardware limits.
>>> These need to be kept in sync with the _signal_levels() functions, so
>>> moving them to a separate file is a bit questionable.
>>>
>>> I suggest that we should attempt to restructure this information as
>>> some kind of tables, from which we can look up the max values as
>>> well as the hardware specific values for each setting.
>>>
>>> That of course won't solve your problem. So far I don't know what your
>>> test even does and why does it need this information, so I guess I'll
>>> need to read on...
>>>
>>>> ---
>>>> drivers/gpu/drm/i915/intel_dp.c | 99 ---------------------
>>>> ------
>>>> drivers/gpu/drm/i915/intel_dp_link_training.c | 92
>>>> +++++++++++++++++++++++++
>>>> drivers/gpu/drm/i915/intel_drv.h | 11 +--
>>>> 3 files changed, 99 insertions(+), 103 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/i915/intel_dp.c
>>>> b/drivers/gpu/drm/i915/intel_dp.c
>>>> index 5778059..da87aef 100644
>>>> --- a/drivers/gpu/drm/i915/intel_dp.c
>>>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>>>> @@ -111,13 +111,6 @@ static bool is_edp(struct intel_dp *intel_dp)
>>>> return intel_dig_port->base.type == INTEL_OUTPUT_EDP;
>>>> }
>>>>
>>>> -static struct drm_device *intel_dp_to_dev(struct intel_dp *intel_dp)
>>>> -{
>>>> - struct intel_digital_port *intel_dig_port =
>>>> dp_to_dig_port(intel_dp);
>>>> -
>>>> - return intel_dig_port->base.base.dev;
>>>> -}
>>>> -
>>>> static struct intel_dp *intel_attached_dp(struct drm_connector
>>>> *connector)
>>>> {
>>>> return enc_to_intel_dp(&intel_attached_encoder(connector)
>>>> ->base);
>>>> @@ -3054,98 +3047,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp,
>>>> uint8_t link_status[DP_LINK_
>>>> DP_LINK_STATUS_SIZE) ==
>>>> DP_LINK_STATUS_SIZE;
>>>> }
>>>>
>>>> -/* These are source-specific values. */
>>>> -uint8_t
>>>> -intel_dp_voltage_max(struct intel_dp *intel_dp)
>>>> -{
>>>> - struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>>> - struct drm_i915_private *dev_priv = dev->dev_private;
>>>> - enum port port = dp_to_dig_port(intel_dp)->port;
>>>> -
>>>> - if (IS_BROXTON(dev))
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> - else if (INTEL_INFO(dev)->gen >= 9) {
>>>> - if (dev_priv->edp_low_vswing && port == PORT_A)
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> - } else if (IS_VALLEYVIEW(dev))
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> - else if (IS_GEN7(dev) && port == PORT_A)
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> - else if (HAS_PCH_CPT(dev) && port != PORT_A)
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> - else
>>>> - return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> -}
>>>> -
>>>> -uint8_t
>>>> -intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t
>>>> voltage_swing)
>>>> -{
>>>> - struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>>> - enum port port = dp_to_dig_port(intel_dp)->port;
>>>> -
>>>> - if (INTEL_INFO(dev)->gen >= 9) {
>>>> - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - default:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - }
>>>> - } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
>>>> - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> - default:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - }
>>>> - } else if (IS_VALLEYVIEW(dev)) {
>>>> - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> - default:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - }
>>>> - } else if (IS_GEN7(dev) && port == PORT_A) {
>>>> - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> - default:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - }
>>>> - } else {
>>>> - switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> - default:
>>>> - return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> - }
>>>> - }
>>>> -}
>>>> -
>>>> static uint32_t vlv_signal_levels(struct intel_dp *intel_dp)
>>>> {
>>>> struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>>> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
>>>> b/drivers/gpu/drm/i915/intel_dp_link_training.c
>>>> index f33cbbb..8d27dce 100644
>>>> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
>>>> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
>>>> @@ -23,6 +23,98 @@
>>>>
>>>> #include "intel_drv.h"
>>>>
>>>> +/* These are source-specific values. */
>>>> +static uint8_t
>>>> +intel_dp_voltage_max(struct intel_dp *intel_dp)
>>>> +{
>>>> + struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>>> + struct drm_i915_private *dev_priv = dev->dev_private;
>>>> + enum port port = dp_to_dig_port(intel_dp)->port;
>>>> +
>>>> + if (IS_BROXTON(dev))
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> + else if (INTEL_INFO(dev)->gen >= 9) {
>>>> + if (dev_priv->edp_low_vswing && port == PORT_A)
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> + } else if (IS_VALLEYVIEW(dev))
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> + else if (IS_GEN7(dev) && port == PORT_A)
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> + else if (HAS_PCH_CPT(dev) && port != PORT_A)
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_3;
>>>> + else
>>>> + return DP_TRAIN_VOLTAGE_SWING_LEVEL_2;
>>>> +}
>>>> +
>>>> +static uint8_t
>>>> +intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t
>>>> voltage_swing)
>>>> +{
>>>> + struct drm_device *dev = intel_dp_to_dev(intel_dp);
>>>> + enum port port = dp_to_dig_port(intel_dp)->port;
>>>> +
>>>> + if (INTEL_INFO(dev)->gen >= 9) {
>>>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + default:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + }
>>>> + } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
>>>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> + default:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + }
>>>> + } else if (IS_VALLEYVIEW(dev)) {
>>>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_3;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> + default:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + }
>>>> + } else if (IS_GEN7(dev) && port == PORT_A) {
>>>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> + default:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + }
>>>> + } else {
>>>> + switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_2;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_1;
>>>> + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3:
>>>> + default:
>>>> + return DP_TRAIN_PRE_EMPH_LEVEL_0;
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>> static void
>>>> intel_get_adjust_train(struct intel_dp *intel_dp,
>>>> const uint8_t link_status[DP_LINK_STATUS_SIZE])
>>>> diff --git a/drivers/gpu/drm/i915/intel_drv.h
>>>> b/drivers/gpu/drm/i915/intel_drv.h
>>>> index 29ae4bb..671a20f 100644
>>>> --- a/drivers/gpu/drm/i915/intel_drv.h
>>>> +++ b/drivers/gpu/drm/i915/intel_drv.h
>>>> @@ -1216,15 +1216,18 @@ intel_dp_program_link_training_pattern(struct
>>>> intel_dp *intel_dp,
>>>> void
>>>> intel_dp_update_signal_levels(struct intel_dp *intel_dp);
>>>> void intel_dp_set_idle_link_train(struct intel_dp *intel_dp);
>>>> -uint8_t
>>>> -intel_dp_voltage_max(struct intel_dp *intel_dp);
>>>> -uint8_t
>>>> -intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t
>>>> voltage_swing);
>>>> void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
>>>> uint8_t *link_bw, uint8_t *rate_select);
>>>> bool intel_dp_source_supports_hbr2(struct drm_device *dev);
>>>> bool
>>>> intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t
>>>> link_status[DP_LINK_STATUS_SIZE]);
>>>> +static inline struct drm_device *intel_dp_to_dev(struct intel_dp
>>>> *intel_dp)
>>>> +{
>>>> + struct intel_digital_port *intel_dig_port =
>>>> dp_to_dig_port(intel_dp);
>>>> +
>>>> + return intel_dig_port->base.base.dev;
>>>> +}
>>>> +
>>>>
>>>> /* intel_dp_mst.c */
>>>> int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port,
>>>> int conn_id);