From 06a139f7a0885fa2c84962300edd181821ddc2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 25 Mar 2014 11:41:40 +0100 Subject: [PATCH 1/7] drm/radeon: clear needs_reset flag if IB test fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the IB test fails we don't want to reset the card over and over again, just accept that it isn't working. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=76501 Signed-off-by: Christian König Reviewed-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_ring.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 8b0dfdd23793..f8050f5429e2 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -262,6 +262,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) r = radeon_ib_test(rdev, i, ring); if (r) { ring->ready = false; + rdev->needs_reset = false; if (i == RADEON_RING_TYPE_GFX_INDEX) { /* oh, oh, that's really bad */ From 1d8eec8ba4a38fcee9d30e4fb5b3d67a9bff9db3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 27 Mar 2014 14:09:18 +1000 Subject: [PATCH 2/7] drm/radeon: fix runtime suspend breaking secondary GPUs Same fix as for nouveau, when we fail with EINVAL, subsequent gets fail hard, causing the device not to open. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_drv.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index e8b0284e34bb..d0eba48dd74e 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -405,11 +405,15 @@ static int radeon_pmops_runtime_suspend(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); int ret; - if (radeon_runtime_pm == 0) - return -EINVAL; + if (radeon_runtime_pm == 0) { + pm_runtime_forbid(dev); + return -EBUSY; + } - if (radeon_runtime_pm == -1 && !radeon_is_px()) - return -EINVAL; + if (radeon_runtime_pm == -1 && !radeon_is_px()) { + pm_runtime_forbid(dev); + return -EBUSY; + } drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; drm_kms_helper_poll_disable(drm_dev); @@ -458,12 +462,15 @@ static int radeon_pmops_runtime_idle(struct device *dev) struct drm_device *drm_dev = pci_get_drvdata(pdev); struct drm_crtc *crtc; - if (radeon_runtime_pm == 0) + if (radeon_runtime_pm == 0) { + pm_runtime_forbid(dev); return -EBUSY; + } /* are we PX enabled? */ if (radeon_runtime_pm == -1 && !radeon_is_px()) { DRM_DEBUG_DRIVER("failing to power off - not px\n"); + pm_runtime_forbid(dev); return -EBUSY; } From ec9954fc26719482c041991607f4329d563c4bbb Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 27 Mar 2014 14:09:19 +1000 Subject: [PATCH 3/7] drm/radeon: fix resuming mode in pm runtime resume path For runtime pm we'd never suspend with the modesetting hw turned on, so don't try and resume the modesetting hw, as that path will take locks that the interface that is causing us to wake up might also take. Signed-off-by: Dave Airlie --- drivers/gpu/drm/radeon/radeon_device.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 15f954cd81cb..835516d2d257 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1551,10 +1551,12 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) /* reset hpd state */ radeon_hpd_init(rdev); /* blat the mode back in */ - drm_helper_resume_force_mode(dev); - /* turn on display hw */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + if (fbcon) { + drm_helper_resume_force_mode(dev); + /* turn on display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } } drm_kms_helper_poll_enable(dev); From 32167016076f714f0e35e287fbead7de0f1fb179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 28 Mar 2014 18:55:10 +0100 Subject: [PATCH 4/7] drm/radeon: rework finding display PLL numbers v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This completely reworks how the PLL parameters are generated and should result in better matching dot clock frequencies. Probably needs quite a bit of testing. bugs: https://bugs.freedesktop.org/show_bug.cgi?id=76564 v2: more cleanup and comments. Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/radeon/radeon_display.c | 247 +++++++++++++++--------- 1 file changed, 155 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5701fbb36b3c..63d54ef758fc 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -34,6 +34,8 @@ #include #include +#include + static void avivo_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -799,66 +801,57 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) } /* avivo */ -static void avivo_get_fb_div(struct radeon_pll *pll, - u32 target_clock, - u32 post_div, - u32 ref_div, - u32 *fb_div, - u32 *frac_fb_div) + +/** + * avivo_reduce_ratio - fractional number reduction + * + * @nom: nominator + * @den: denominator + * @nom_min: minimum value for nominator + * @den_min: minimum value for denominator + * + * Find the greatest common divisor and apply it on both nominator and + * denominator, but make nominator and denominator are at least as large + * as their minimum values. + */ +static void avivo_reduce_ratio(unsigned *nom, unsigned *den, + unsigned nom_min, unsigned den_min) { - u32 tmp = post_div * ref_div; + unsigned tmp; - tmp *= target_clock; - *fb_div = tmp / pll->reference_freq; - *frac_fb_div = tmp % pll->reference_freq; + /* reduce the numbers to a simpler ratio */ + tmp = gcd(*nom, *den); + *nom /= tmp; + *den /= tmp; - if (*fb_div > pll->max_feedback_div) - *fb_div = pll->max_feedback_div; - else if (*fb_div < pll->min_feedback_div) - *fb_div = pll->min_feedback_div; -} - -static u32 avivo_get_post_div(struct radeon_pll *pll, - u32 target_clock) -{ - u32 vco, post_div, tmp; - - if (pll->flags & RADEON_PLL_USE_POST_DIV) - return pll->post_div; - - if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { - if (pll->flags & RADEON_PLL_IS_LCD) - vco = pll->lcd_pll_out_min; - else - vco = pll->pll_out_min; - } else { - if (pll->flags & RADEON_PLL_IS_LCD) - vco = pll->lcd_pll_out_max; - else - vco = pll->pll_out_max; + /* make sure nominator is large enough */ + if (*nom < nom_min) { + tmp = (nom_min + *nom - 1) / *nom; + *nom *= tmp; + *den *= tmp; } - post_div = vco / target_clock; - tmp = vco % target_clock; - - if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { - if (tmp) - post_div++; - } else { - if (!tmp) - post_div--; + /* make sure the denominator is large enough */ + if (*den < den_min) { + tmp = (den_min + *den - 1) / *den; + *nom *= tmp; + *den *= tmp; } - - if (post_div > pll->max_post_div) - post_div = pll->max_post_div; - else if (post_div < pll->min_post_div) - post_div = pll->min_post_div; - - return post_div; } -#define MAX_TOLERANCE 10 - +/** + * radeon_compute_pll_avivo - compute PLL paramaters + * + * @pll: information about the PLL + * @dot_clock_p: resulting pixel clock + * fb_div_p: resulting feedback divider + * frac_fb_div_p: fractional part of the feedback divider + * ref_div_p: resulting reference divider + * post_div_p: resulting reference divider + * + * Try to calculate the PLL parameters to generate the given frequency: + * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div) + */ void radeon_compute_pll_avivo(struct radeon_pll *pll, u32 freq, u32 *dot_clock_p, @@ -867,53 +860,123 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, u32 *ref_div_p, u32 *post_div_p) { - u32 target_clock = freq / 10; - u32 post_div = avivo_get_post_div(pll, target_clock); - u32 ref_div = pll->min_ref_div; - u32 fb_div = 0, frac_fb_div = 0, tmp; + unsigned fb_div_min, fb_div_max, fb_div; + unsigned post_div_min, post_div_max, post_div; + unsigned ref_div_min, ref_div_max, ref_div; + unsigned post_div_best, diff_best; + unsigned nom, den, tmp; - if (pll->flags & RADEON_PLL_USE_REF_DIV) - ref_div = pll->reference_div; + /* determine allowed feedback divider range */ + fb_div_min = pll->min_feedback_div; + fb_div_max = pll->max_feedback_div; if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { - avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); - frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; - if (frac_fb_div >= 5) { - frac_fb_div -= 5; - frac_fb_div = frac_fb_div / 10; - frac_fb_div++; - } - if (frac_fb_div >= 10) { - fb_div++; - frac_fb_div = 0; - } - } else { - while (ref_div <= pll->max_ref_div) { - avivo_get_fb_div(pll, target_clock, post_div, ref_div, - &fb_div, &frac_fb_div); - if (frac_fb_div >= (pll->reference_freq / 2)) - fb_div++; - frac_fb_div = 0; - tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); - tmp = (tmp * 10000) / target_clock; - - if (tmp > (10000 + MAX_TOLERANCE)) - ref_div++; - else if (tmp >= (10000 - MAX_TOLERANCE)) - break; - else - ref_div++; - } + fb_div_min *= 10; + fb_div_max *= 10; } - *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / - (ref_div * post_div * 10); - *fb_div_p = fb_div; - *frac_fb_div_p = frac_fb_div; + /* determine allowed ref divider range */ + if (pll->flags & RADEON_PLL_USE_REF_DIV) + ref_div_min = pll->reference_div; + else + ref_div_min = pll->min_ref_div; + ref_div_max = pll->max_ref_div; + + /* determine allowed post divider range */ + if (pll->flags & RADEON_PLL_USE_POST_DIV) { + post_div_min = pll->post_div; + post_div_max = pll->post_div; + } else { + unsigned target_clock = freq / 10; + unsigned vco_min, vco_max; + + if (pll->flags & RADEON_PLL_IS_LCD) { + vco_min = pll->lcd_pll_out_min; + vco_max = pll->lcd_pll_out_max; + } else { + vco_min = pll->pll_out_min; + vco_max = pll->pll_out_max; + } + + post_div_min = vco_min / target_clock; + if ((target_clock * post_div_min) < vco_min) + ++post_div_min; + if (post_div_min < pll->min_post_div) + post_div_min = pll->min_post_div; + + post_div_max = vco_max / target_clock; + if ((target_clock * post_div_max) > vco_max) + --post_div_max; + if (post_div_max > pll->max_post_div) + post_div_max = pll->max_post_div; + } + + /* represent the searched ratio as fractional number */ + nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; + den = pll->reference_freq; + + /* reduce the numbers to a simpler ratio */ + avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min); + + /* now search for a post divider */ + if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) + post_div_best = post_div_min; + else + post_div_best = post_div_max; + diff_best = ~0; + + for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { + unsigned diff = abs(den - den / post_div * post_div); + if (diff < diff_best || (diff == diff_best && + !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { + + post_div_best = post_div; + diff_best = diff; + } + } + post_div = post_div_best; + + /* get matching reference and feedback divider */ + ref_div = max(den / post_div, 1u); + fb_div = nom; + + /* we're almost done, but reference and feedback + divider might be to large now */ + + tmp = ref_div; + + if (fb_div > fb_div_max) { + ref_div = ref_div * fb_div_max / fb_div; + fb_div = fb_div_max; + } + + if (ref_div > ref_div_max) { + ref_div = ref_div_max; + fb_div = nom * ref_div_max / tmp; + } + + /* reduce the numbers to a simpler ratio once more */ + /* this also makes sure that the reference divider is large enough */ + avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); + + /* and finally save the result */ + if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { + *fb_div_p = fb_div / 10; + *frac_fb_div_p = fb_div % 10; + } else { + *fb_div_p = fb_div; + *frac_fb_div_p = 0; + } + + *dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) + + (pll->reference_freq * *frac_fb_div_p)) / + (ref_div * post_div * 10); *ref_div_p = ref_div; *post_div_p = post_div; - DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n", - *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div); + + DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", + freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, + ref_div, post_div); } /* pre-avivo */ From 16086279353cbfecbb3ead474072dced17b97ddc Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 31 Mar 2014 11:19:46 -0400 Subject: [PATCH 5/7] drm/radeon: call drm_edid_to_eld when we update the edid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This needs to be done to update some of the fields in the connector structure used by the audio code. Noticed by several users on irc. Signed-off-by: Alex Deucher Signed-off-by: Christian König Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 63d54ef758fc..386cfa4c194d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -794,6 +794,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (radeon_connector->edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); + drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); From a8947f576728a66bd3aac629bd8ca021a010c808 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 2 Apr 2014 08:42:48 -0400 Subject: [PATCH 6/7] drm/radeon: fix endian swap on hawaii clear state buffer setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need to swap on BE. Signed-off-by: Alex Deucher Reviewed-by: Christian König Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 62fefbbaf263..581f9e06d354 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -6542,8 +6542,8 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer) buffer[count++] = cpu_to_le32(0x00000000); break; case CHIP_HAWAII: - buffer[count++] = 0x3a00161a; - buffer[count++] = 0x0000002e; + buffer[count++] = cpu_to_le32(0x3a00161a); + buffer[count++] = cpu_to_le32(0x0000002e); break; default: buffer[count++] = cpu_to_le32(0x00000000); From f1553174a207f68a4ec19d436003097e0a4dc405 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 2 Apr 2014 08:42:49 -0400 Subject: [PATCH 7/7] drm/radeon: fix typo in spectre_golden_registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Alex Deucher Reviewed-by: Christian König Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/cik.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 581f9e06d354..745143c2358f 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -1096,7 +1096,7 @@ static const u32 spectre_golden_registers[] = 0x8a14, 0xf000003f, 0x00000007, 0x8b24, 0xffffffff, 0x00ffffff, 0x28350, 0x3f3f3fff, 0x00000082, - 0x28355, 0x0000003f, 0x00000000, + 0x28354, 0x0000003f, 0x00000000, 0x3e78, 0x00000001, 0x00000002, 0x913c, 0xffff03df, 0x00000004, 0xc768, 0x00000008, 0x00000008,