diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0033-drm-amdgpu-fix-dp-link-rate-selection-v2.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0033-drm-amdgpu-fix-dp-link-rate-selection-v2.patch | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0033-drm-amdgpu-fix-dp-link-rate-selection-v2.patch b/common/recipes-kernel/linux/files/0033-drm-amdgpu-fix-dp-link-rate-selection-v2.patch new file mode 100644 index 00000000..585ce1a5 --- /dev/null +++ b/common/recipes-kernel/linux/files/0033-drm-amdgpu-fix-dp-link-rate-selection-v2.patch @@ -0,0 +1,166 @@ +From 9057e8ec3a72b7ffcd95ed553843265f4ef966d3 Mon Sep 17 00:00:00 2001 +From: Alex Deucher <alexander.deucher@amd.com> +Date: Thu, 17 Dec 2015 09:57:49 -0500 +Subject: [PATCH 0033/1110] drm/amdgpu: fix dp link rate selection (v2) + +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 + +Reviewed-by: Tom St Denis <tom.stdenis@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/amdgpu/atombios_dp.c | 96 ++++++++++++-------------------- + 1 file changed, 36 insertions(+), 60 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +index 92b6aca..21aacc1 100644 +--- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c ++++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +@@ -243,7 +243,7 @@ static void amdgpu_atombios_dp_get_adjust_train(const u8 link_status[DP_LINK_STA + + /* convert bits per color to bits per pixel */ + /* get bpc from the EDID */ +-static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) ++static unsigned amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) + { + if (bpc == 0) + return 24; +@@ -251,64 +251,32 @@ static int amdgpu_atombios_dp_convert_bpc_to_bpp(int bpc) + return bpc * 3; + } + +-/* get the max pix clock supported by the link rate and lane num */ +-static int amdgpu_atombios_dp_get_max_dp_pix_clock(int link_rate, +- int lane_num, +- int bpp) +-{ +- return (link_rate * lane_num * 8) / bpp; +-} +- + /***** amdgpu specific DP functions *****/ + +-/* 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 amdgpu_atombios_dp_get_dp_lane_number(struct drm_connector *connector, ++static int amdgpu_atombios_dp_get_dp_link_config(struct drm_connector *connector, + const u8 dpcd[DP_DPCD_SIZE], +- int pix_clock) +-{ +- int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); +- int max_link_rate = drm_dp_max_link_rate(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 = amdgpu_atombios_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 amdgpu_atombios_dp_get_dp_link_clock(struct drm_connector *connector, +- const u8 dpcd[DP_DPCD_SIZE], +- int pix_clock) ++ unsigned pix_clock, ++ unsigned *dp_lanes, unsigned *dp_rate) + { +- int bpp = amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); +- int lane_num, max_pix_clock; +- +- if (amdgpu_connector_encoder_get_dp_bridge_encoder_id(connector) == +- ENCODER_OBJECT_ID_NUTMEG) +- return 270000; +- +- lane_num = amdgpu_atombios_dp_get_dp_lane_number(connector, dpcd, pix_clock); +- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(162000, lane_num, bpp); +- if (pix_clock <= max_pix_clock) +- return 162000; +- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(270000, lane_num, bpp); +- if (pix_clock <= max_pix_clock) +- return 270000; +- if (amdgpu_connector_is_dp12_capable(connector)) { +- max_pix_clock = amdgpu_atombios_dp_get_max_dp_pix_clock(540000, lane_num, bpp); +- if (pix_clock <= max_pix_clock) +- return 540000; ++ unsigned bpp = ++ amdgpu_atombios_dp_convert_bpc_to_bpp(amdgpu_connector_get_monitor_bpc(connector)); ++ 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 drm_dp_max_link_rate(dpcd); ++ return -EINVAL; + } + + static u8 amdgpu_atombios_dp_encoder_service(struct amdgpu_device *adev, +@@ -422,6 +390,7 @@ void amdgpu_atombios_dp_set_link_config(struct drm_connector *connector, + { + struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); + struct amdgpu_connector_atom_dig *dig_connector; ++ int ret; + + if (!amdgpu_connector->con_priv) + return; +@@ -429,10 +398,14 @@ void amdgpu_atombios_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 = +- amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); +- dig_connector->dp_lane_count = +- amdgpu_atombios_dp_get_dp_lane_number(connector, dig_connector->dpcd, mode->clock); ++ ret = amdgpu_atombios_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; ++ } + } + } + +@@ -441,14 +414,17 @@ int amdgpu_atombios_dp_mode_valid_helper(struct drm_connector *connector, + { + struct amdgpu_connector *amdgpu_connector = to_amdgpu_connector(connector); + struct amdgpu_connector_atom_dig *dig_connector; +- int dp_clock; ++ unsigned dp_lanes, dp_clock; ++ int ret; + + if (!amdgpu_connector->con_priv) + return MODE_CLOCK_HIGH; + dig_connector = amdgpu_connector->con_priv; + +- dp_clock = +- amdgpu_atombios_dp_get_dp_link_clock(connector, dig_connector->dpcd, mode->clock); ++ ret = amdgpu_atombios_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) && + (!amdgpu_connector_is_dp12_capable(connector))) +-- +2.7.4 + |