On Fri, Jan 27, 2017 at 09:52:05PM +0200, Jani Nikula wrote: > On Fri, 27 Jan 2017, Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> wrote: > > On Thu, Jan 26, 2017 at 09:44:19PM +0200, Jani Nikula wrote: > >> There is some conflation related to sink rates, making this change more > >> complicated than it would otherwise have to be. There are three changes > >> here that are rather difficult to split up: > >> > >> 1) Use the intel_dp->sink_rates array for all DP, not just eDP 1.4. We > >> initialize it from DPCD on eDP 1.4 like before, but generate it based > >> on DP_MAX_LINK_RATE on others. This reduces code complexity when we > >> need to use the sink rates; they are all always in the sink_rates > >> array. > >> > >> 2) Update the sink rate array whenever we read DPCD, and use the > >> information from there. This increases code readability when we need > >> the sink rates. > >> > >> 3) Disentangle fallback rate limiting from sink rates. In the code, the > >> max rate is a dynamic property of the *link*, not of the *sink*. Do > >> the limiting after intersecting the source and sink rates, which are > >> static properties of the devices. > >> > >> This paves the way for follow-up refactoring that I've refrained from > >> doing here to keep this change as simple as it possibly can. > >> > >> Cc: Manasi Navare <manasi.d.navare@xxxxxxxxx> > >> Cc: Ville Syrjälä <ville.syrjala@xxxxxxxxxxxxxxx> > >> Signed-off-by: Jani Nikula <jani.nikula@xxxxxxxxx> > >> --- > >> drivers/gpu/drm/i915/intel_dp.c | 76 ++++++++++++++++++--------- > >> drivers/gpu/drm/i915/intel_dp_link_training.c | 3 +- > >> drivers/gpu/drm/i915/intel_drv.h | 4 +- > >> 3 files changed, 55 insertions(+), 28 deletions(-) > >> > >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > >> index cc2523363c8d..d13ce6746542 100644 > >> --- a/drivers/gpu/drm/i915/intel_dp.c > >> +++ b/drivers/gpu/drm/i915/intel_dp.c > >> @@ -133,6 +133,34 @@ static void vlv_steal_power_sequencer(struct drm_device *dev, > >> enum pipe pipe); > >> static void intel_dp_unset_edid(struct intel_dp *intel_dp); > >> > >> +static int intel_dp_num_rates(u8 link_bw_code) > >> +{ > >> + switch (link_bw_code) { > >> + default: > >> + WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n", > >> + link_bw_code); > >> + case DP_LINK_BW_1_62: > >> + return 1; > >> + case DP_LINK_BW_2_7: > >> + return 2; > >> + case DP_LINK_BW_5_4: > >> + return 3; > >> + } > >> +} > >> + > >> +/* update sink rates from dpcd */ > >> +static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) > >> +{ > >> + int i, num_rates; > >> + > >> + num_rates = intel_dp_num_rates(intel_dp->dpcd[DP_MAX_LINK_RATE]); > >> + > >> + for (i = 0; i < num_rates; i++) > >> + intel_dp->sink_rates[i] = default_rates[i]; > >> + > >> + intel_dp->num_sink_rates = num_rates; > >> +} > >> + > >> static int > >> intel_dp_max_link_bw(struct intel_dp *intel_dp) > >> { > >> @@ -205,19 +233,6 @@ intel_dp_downstream_max_dotclock(struct intel_dp *intel_dp) > >> return max_dotclk; > >> } > >> > >> -static int > >> -intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) > >> -{ > >> - if (intel_dp->num_sink_rates) { > >> - *sink_rates = intel_dp->sink_rates; > >> - return intel_dp->num_sink_rates; > >> - } > >> - > >> - *sink_rates = default_rates; > >> - > >> - return (intel_dp->max_sink_link_bw >> 3) + 1; > >> -} > >> - > >> static void > >> intel_dp_set_source_rates(struct intel_dp *intel_dp) > >> { > >> @@ -285,15 +300,22 @@ static int intel_dp_find_rate(const int *rates, int len, int rate) > >> static int intel_dp_common_rates(struct intel_dp *intel_dp, > >> int *common_rates) > >> { > >> - const int *sink_rates; > >> - int sink_len; > >> + int max_rate = drm_dp_bw_code_to_link_rate(intel_dp->max_sink_link_bw); > >> + int i, common_len; > >> > >> - sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); > >> + common_len = intersect_rates(intel_dp->source_rates, > >> + intel_dp->num_source_rates, > >> + intel_dp->sink_rates, > >> + intel_dp->num_sink_rates, > >> + common_rates); > >> > >> - return intersect_rates(intel_dp->source_rates, > >> - intel_dp->num_source_rates, > >> - sink_rates, sink_len, > >> - common_rates); > >> + /* Limit results by potentially reduced max rate */ > >> + for (i = 0; i < common_len; i++) { > >> + if (common_rates[common_len - i - 1] <= max_rate) > >> + return common_len - i; > >> + } > >> + > >> + return 0; > >> } > >> > >> static int intel_dp_link_rate_index(struct intel_dp *intel_dp, > >> @@ -1501,8 +1523,7 @@ static void snprintf_int_array(char *str, size_t len, > >> > >> static void intel_dp_print_rates(struct intel_dp *intel_dp) > >> { > >> - const int *sink_rates; > >> - int sink_len, common_len; > >> + int common_len; > >> int common_rates[DP_MAX_SUPPORTED_RATES]; > >> char str[128]; /* FIXME: too big for stack? */ > >> > >> @@ -1513,8 +1534,8 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) > >> intel_dp->source_rates, intel_dp->num_source_rates); > >> DRM_DEBUG_KMS("source rates: %s\n", str); > >> > >> - sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); > >> - snprintf_int_array(str, sizeof(str), sink_rates, sink_len); > >> + snprintf_int_array(str, sizeof(str), > >> + intel_dp->sink_rates, intel_dp->num_sink_rates); > >> DRM_DEBUG_KMS("sink rates: %s\n", str); > >> > >> common_len = intel_dp_common_rates(intel_dp, common_rates); > >> @@ -1580,7 +1601,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) > >> void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, > >> uint8_t *link_bw, uint8_t *rate_select) > >> { > >> - if (intel_dp->num_sink_rates) { > >> + /* eDP 1.4 rate select method. */ > >> + if (is_edp(intel_dp) && intel_dp->edp_dpcd[0] >= 0x03) { > > > > I was convinced that this wasn't a mandatory feature, but the spec does > > seem to say "The table must contain at least one non-zero value at the > > first (lowest DPCD address) location." > > > > But given historical evidence I'm still 99% convinced we'll eventually > > run into some panel somewhere that does this wrong, so I don't really > > like this idea. > > Then I think this should be fixed in intel_edp_init_dpcd() by a) > checking that there is at least one non-zero value, falling back to > intel_dp_set_source_rates() if not, and b) setting a new > intel_dp->use_rate_selet field at that time, which will be used instead > of (is_edp(intel_dp) && intel_dp->edp_dpcd[0] >= 0x03). Sound good? Yep. That should preserve the current behaviour. -- Ville Syrjälä Intel OTC _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx