Need to properly handle the max link rate in the dpcd.
This prevents some cases where 5.4 Ghz is selected when
it shouldn't be.

v2: simplify logic, add array bounds check

Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
---
 drivers/gpu/drm/radeon/atombios_dp.c   | 108 +++++++++++----------------------
 drivers/gpu/drm/radeon/radeon_dp_mst.c |  12 +++-
 drivers/gpu/drm/radeon/radeon_mode.h   |   6 +-
 3 files changed, 49 insertions(+), 77 deletions(-)

diff --git a/drivers/gpu/drm/radeon/atombios_dp.c 
b/drivers/gpu/drm/radeon/atombios_dp.c
index bd73b40..44ee72e 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -302,77 +302,31 @@ static int convert_bpc_to_bpp(int bpc)
                return bpc * 3;
 }

-/* get the max pix clock supported by the link rate and lane num */
-static int dp_get_max_dp_pix_clock(int link_rate,
-                                  int lane_num,
-                                  int bpp)
-{
-       return (link_rate * lane_num * 8) / bpp;
-}
-
 /***** radeon specific DP functions *****/

-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                               const u8 dpcd[DP_DPCD_SIZE])
-{
-       int max_link_rate;
-
-       if (radeon_connector_is_dp12_capable(connector))
-               max_link_rate = min(drm_dp_max_link_rate(dpcd), 540000);
-       else
-               max_link_rate = min(drm_dp_max_link_rate(dpcd), 270000);
-
-       return max_link_rate;
-}
-
-/* First get the min lane# when low rate is used according to pixel clock
- * (prefer low rate), second check max lane# supported by DP panel,
- * if the max lane# < low rate lane# then use max lane# instead.
- */
-static int radeon_dp_get_dp_lane_number(struct drm_connector *connector,
-                                       const u8 dpcd[DP_DPCD_SIZE],
-                                       int pix_clock)
-{
-       int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-       int max_link_rate = radeon_dp_get_max_link_rate(connector, dpcd);
-       int max_lane_num = drm_dp_max_lane_count(dpcd);
-       int lane_num;
-       int max_dp_pix_clock;
-
-       for (lane_num = 1; lane_num < max_lane_num; lane_num <<= 1) {
-               max_dp_pix_clock = dp_get_max_dp_pix_clock(max_link_rate, 
lane_num, bpp);
-               if (pix_clock <= max_dp_pix_clock)
-                       break;
-       }
-
-       return lane_num;
-}
-
-static int radeon_dp_get_dp_link_clock(struct drm_connector *connector,
-                                      const u8 dpcd[DP_DPCD_SIZE],
-                                      int pix_clock)
+int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+                                const u8 dpcd[DP_DPCD_SIZE],
+                                unsigned pix_clock,
+                                unsigned *dp_lanes, unsigned *dp_rate)
 {
        int bpp = convert_bpc_to_bpp(radeon_get_monitor_bpc(connector));
-       int lane_num, max_pix_clock;
-
-       if (radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
-           ENCODER_OBJECT_ID_NUTMEG)
-               return 270000;
-
-       lane_num = radeon_dp_get_dp_lane_number(connector, dpcd, pix_clock);
-       max_pix_clock = dp_get_max_dp_pix_clock(162000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 162000;
-       max_pix_clock = dp_get_max_dp_pix_clock(270000, lane_num, bpp);
-       if (pix_clock <= max_pix_clock)
-               return 270000;
-       if (radeon_connector_is_dp12_capable(connector)) {
-               max_pix_clock = dp_get_max_dp_pix_clock(540000, lane_num, bpp);
-               if (pix_clock <= max_pix_clock)
-                       return 540000;
+       static const unsigned link_rates[3] = { 162000, 270000, 540000 };
+       unsigned max_link_rate = drm_dp_max_link_rate(dpcd);
+       unsigned max_lane_num = drm_dp_max_lane_count(dpcd);
+       unsigned lane_num, i, max_pix_clock;
+
+       for (lane_num = 1; lane_num <= max_lane_num; lane_num <<= 1) {
+               for (i = 0; i < ARRAY_SIZE(link_rates) && link_rates[i] <= 
max_link_rate; i++) {
+                       max_pix_clock = (lane_num * link_rates[i] * 8) / bpp;
+                       if (max_pix_clock >= pix_clock) {
+                               *dp_lanes = lane_num;
+                               *dp_rate = link_rates[i];
+                               return 0;
+                       }
+               }
        }

-       return radeon_dp_get_max_link_rate(connector, dpcd);
+       return -EINVAL;
 }

 static u8 radeon_dp_encoder_service(struct radeon_device *rdev,
@@ -491,6 +445,7 @@ void radeon_dp_set_link_config(struct drm_connector 
*connector,
 {
        struct radeon_connector *radeon_connector = 
to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
+       int ret;

        if (!radeon_connector->con_priv)
                return;
@@ -498,10 +453,14 @@ void radeon_dp_set_link_config(struct drm_connector 
*connector,

        if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
            (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
-               dig_connector->dp_clock =
-                       radeon_dp_get_dp_link_clock(connector, 
dig_connector->dpcd, mode->clock);
-               dig_connector->dp_lane_count =
-                       radeon_dp_get_dp_lane_number(connector, 
dig_connector->dpcd, mode->clock);
+               ret = radeon_dp_get_dp_link_config(connector, 
dig_connector->dpcd,
+                                                  mode->clock,
+                                                  
&dig_connector->dp_lane_count,
+                                                  &dig_connector->dp_clock);
+               if (ret) {
+                       dig_connector->dp_clock = 0;
+                       dig_connector->dp_lane_count = 0;
+               }
        }
 }

@@ -510,7 +469,8 @@ int radeon_dp_mode_valid_helper(struct drm_connector 
*connector,
 {
        struct radeon_connector *radeon_connector = 
to_radeon_connector(connector);
        struct radeon_connector_atom_dig *dig_connector;
-       int dp_clock;
+       unsigned dp_clock, dp_lanes;
+       int ret;

        if ((mode->clock > 340000) &&
            (!radeon_connector_is_dp12_capable(connector)))
@@ -520,8 +480,12 @@ int radeon_dp_mode_valid_helper(struct drm_connector 
*connector,
                return MODE_CLOCK_HIGH;
        dig_connector = radeon_connector->con_priv;

-       dp_clock =
-               radeon_dp_get_dp_link_clock(connector, dig_connector->dpcd, 
mode->clock);
+       ret = radeon_dp_get_dp_link_config(connector, dig_connector->dpcd,
+                                          mode->clock,
+                                          &dp_lanes,
+                                          &dp_clock);
+       if (ret)
+               return MODE_CLOCK_HIGH;

        if ((dp_clock == 540000) &&
            (!radeon_connector_is_dp12_capable(connector)))
diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c 
b/drivers/gpu/drm/radeon/radeon_dp_mst.c
index 744f5c4..b431c9c 100644
--- a/drivers/gpu/drm/radeon/radeon_dp_mst.c
+++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c
@@ -525,11 +525,17 @@ static bool radeon_mst_mode_fixup(struct drm_encoder 
*encoder,
        drm_mode_set_crtcinfo(adjusted_mode, 0);
        {
          struct radeon_connector_atom_dig *dig_connector;
+         int ret;

          dig_connector = mst_enc->connector->con_priv;
-         dig_connector->dp_lane_count = 
drm_dp_max_lane_count(dig_connector->dpcd);
-         dig_connector->dp_clock = 
radeon_dp_get_max_link_rate(&mst_enc->connector->base,
-                                                               
dig_connector->dpcd);
+         ret = radeon_dp_get_dp_link_config(&mst_enc->connector->base,
+                                            dig_connector->dpcd, 
adjusted_mode->clock,
+                                            &dig_connector->dp_lane_count,
+                                            &dig_connector->dp_clock);
+         if (ret) {
+                 dig_connector->dp_lane_count = 0;
+                 dig_connector->dp_clock = 0;
+         }
          DRM_DEBUG_KMS("dig clock %p %d %d\n", dig_connector,
                        dig_connector->dp_lane_count, dig_connector->dp_clock);
        }
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h 
b/drivers/gpu/drm/radeon/radeon_mode.h
index d8babb8..2c83310 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -756,8 +756,10 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector 
*radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
-int radeon_dp_get_max_link_rate(struct drm_connector *connector,
-                               const u8 *dpcd);
+extern int radeon_dp_get_dp_link_config(struct drm_connector *connector,
+                                       const u8 *dpcd,
+                                       unsigned pix_clock,
+                                       unsigned *dp_lanes, unsigned *dp_rate);
 extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
                                         u8 power_state);
 extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
-- 
2.5.0

Reply via email to