Commit 6db8148c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux

Pull radeon drm fixes from Dave Airlie:
 "This is just radeon fixes, primarily the two pll fix and the aux fix,
  it also disables dpm on rv770 gpus, fixes driver reloading, and fixes
  two issues with runtime PM on some GPUS"

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
  drm/radeon: don't allow runpm=1 on systems with out ATPX
  drm/radeon: fix ATPX detection on non-VGA GPUs
  drm/radeon/pm: don't walk the crtc list before it has been initialized (v2)
  drm/radeon: properly unregister hwmon interface (v2)
  drm/radeon: fix count in cik_sdma_ring_test()
  drm/radeon/aux: fix hpd assignment for aux bus
  drm/radeon: improve PLL limit handling in post div calculation
  drm/radeon: use fixed PPL ref divider if needed
  drm/radeon: disable dpm on rv770 by default
parents 1b17844b abaafc0a
...@@ -209,6 +209,7 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector) ...@@ -209,6 +209,7 @@ void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
{ {
int ret; int ret;
radeon_connector->ddc_bus->rec.hpd = radeon_connector->hpd.hpd;
radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev; radeon_connector->ddc_bus->aux.dev = radeon_connector->base.kdev;
radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer; radeon_connector->ddc_bus->aux.transfer = radeon_dp_aux_transfer;
ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux); ret = drm_dp_aux_register_i2c_bus(&radeon_connector->ddc_bus->aux);
......
...@@ -597,7 +597,7 @@ int cik_sdma_ring_test(struct radeon_device *rdev, ...@@ -597,7 +597,7 @@ int cik_sdma_ring_test(struct radeon_device *rdev,
tmp = 0xCAFEDEAD; tmp = 0xCAFEDEAD;
writel(tmp, ptr); writel(tmp, ptr);
r = radeon_ring_lock(rdev, ring, 4); r = radeon_ring_lock(rdev, ring, 5);
if (r) { if (r) {
DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r); DRM_ERROR("radeon: dma failed to lock ring %d (%d).\n", ring->idx, r);
return r; return r;
......
...@@ -158,16 +158,18 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev) ...@@ -158,16 +158,18 @@ u32 r600_dpm_get_vblank_time(struct radeon_device *rdev)
u32 line_time_us, vblank_lines; u32 line_time_us, vblank_lines;
u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */ u32 vblank_time_us = 0xffffffff; /* if the displays are off, vblank time is max */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
radeon_crtc = to_radeon_crtc(crtc); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { radeon_crtc = to_radeon_crtc(crtc);
line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) / if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
radeon_crtc->hw_mode.clock; line_time_us = (radeon_crtc->hw_mode.crtc_htotal * 1000) /
vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end - radeon_crtc->hw_mode.clock;
radeon_crtc->hw_mode.crtc_vdisplay + vblank_lines = radeon_crtc->hw_mode.crtc_vblank_end -
(radeon_crtc->v_border * 2); radeon_crtc->hw_mode.crtc_vdisplay +
vblank_time_us = vblank_lines * line_time_us; (radeon_crtc->v_border * 2);
break; vblank_time_us = vblank_lines * line_time_us;
break;
}
} }
} }
...@@ -181,14 +183,15 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev) ...@@ -181,14 +183,15 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)
struct radeon_crtc *radeon_crtc; struct radeon_crtc *radeon_crtc;
u32 vrefresh = 0; u32 vrefresh = 0;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
radeon_crtc = to_radeon_crtc(crtc); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) { radeon_crtc = to_radeon_crtc(crtc);
vrefresh = radeon_crtc->hw_mode.vrefresh; if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
break; vrefresh = radeon_crtc->hw_mode.vrefresh;
break;
}
} }
} }
return vrefresh; return vrefresh;
} }
......
...@@ -528,6 +528,13 @@ static bool radeon_atpx_detect(void) ...@@ -528,6 +528,13 @@ static bool radeon_atpx_detect(void)
has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true); has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
} }
/* some newer PX laptops mark the dGPU as a non-VGA display device */
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_OTHER << 8, pdev)) != NULL) {
vga_count++;
has_atpx |= (radeon_atpx_pci_probe_handle(pdev) == true);
}
if (has_atpx && vga_count == 2) { if (has_atpx && vga_count == 2) {
acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer); acpi_get_name(radeon_atpx_priv.atpx.handle, ACPI_FULL_PATHNAME, &buffer);
printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n",
......
...@@ -839,6 +839,38 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den, ...@@ -839,6 +839,38 @@ static void avivo_reduce_ratio(unsigned *nom, unsigned *den,
} }
} }
/**
* avivo_get_fb_ref_div - feedback and ref divider calculation
*
* @nom: nominator
* @den: denominator
* @post_div: post divider
* @fb_div_max: feedback divider maximum
* @ref_div_max: reference divider maximum
* @fb_div: resulting feedback divider
* @ref_div: resulting reference divider
*
* Calculate feedback and reference divider for a given post divider. Makes
* sure we stay within the limits.
*/
static void avivo_get_fb_ref_div(unsigned nom, unsigned den, unsigned post_div,
unsigned fb_div_max, unsigned ref_div_max,
unsigned *fb_div, unsigned *ref_div)
{
/* limit reference * post divider to a maximum */
ref_div_max = min(210 / post_div, ref_div_max);
/* get matching reference and feedback divider */
*ref_div = min(max(DIV_ROUND_CLOSEST(den, post_div), 1u), ref_div_max);
*fb_div = DIV_ROUND_CLOSEST(nom * *ref_div * post_div, den);
/* limit fb divider to its maximum */
if (*fb_div > fb_div_max) {
*ref_div = DIV_ROUND_CLOSEST(*ref_div * fb_div_max, *fb_div);
*fb_div = fb_div_max;
}
}
/** /**
* radeon_compute_pll_avivo - compute PLL paramaters * radeon_compute_pll_avivo - compute PLL paramaters
* *
...@@ -860,6 +892,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -860,6 +892,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
u32 *ref_div_p, u32 *ref_div_p,
u32 *post_div_p) u32 *post_div_p)
{ {
unsigned target_clock = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ?
freq : freq / 10;
unsigned fb_div_min, fb_div_max, fb_div; unsigned fb_div_min, fb_div_max, fb_div;
unsigned post_div_min, post_div_max, post_div; unsigned post_div_min, post_div_max, post_div;
unsigned ref_div_min, ref_div_max, ref_div; unsigned ref_div_min, ref_div_max, ref_div;
...@@ -880,14 +915,18 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -880,14 +915,18 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
ref_div_min = pll->reference_div; ref_div_min = pll->reference_div;
else else
ref_div_min = pll->min_ref_div; ref_div_min = pll->min_ref_div;
ref_div_max = pll->max_ref_div;
if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV &&
pll->flags & RADEON_PLL_USE_REF_DIV)
ref_div_max = pll->reference_div;
else
ref_div_max = pll->max_ref_div;
/* determine allowed post divider range */ /* determine allowed post divider range */
if (pll->flags & RADEON_PLL_USE_POST_DIV) { if (pll->flags & RADEON_PLL_USE_POST_DIV) {
post_div_min = pll->post_div; post_div_min = pll->post_div;
post_div_max = pll->post_div; post_div_max = pll->post_div;
} else { } else {
unsigned target_clock = freq / 10;
unsigned vco_min, vco_max; unsigned vco_min, vco_max;
if (pll->flags & RADEON_PLL_IS_LCD) { if (pll->flags & RADEON_PLL_IS_LCD) {
...@@ -898,6 +937,11 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -898,6 +937,11 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
vco_max = pll->pll_out_max; vco_max = pll->pll_out_max;
} }
if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
vco_min *= 10;
vco_max *= 10;
}
post_div_min = vco_min / target_clock; post_div_min = vco_min / target_clock;
if ((target_clock * post_div_min) < vco_min) if ((target_clock * post_div_min) < vco_min)
++post_div_min; ++post_div_min;
...@@ -912,7 +956,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -912,7 +956,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
} }
/* represent the searched ratio as fractional number */ /* represent the searched ratio as fractional number */
nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; nom = target_clock;
den = pll->reference_freq; den = pll->reference_freq;
/* reduce the numbers to a simpler ratio */ /* reduce the numbers to a simpler ratio */
...@@ -926,7 +970,12 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -926,7 +970,12 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
diff_best = ~0; diff_best = ~0;
for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {
unsigned diff = abs(den - den / post_div * post_div); unsigned diff;
avivo_get_fb_ref_div(nom, den, post_div, fb_div_max,
ref_div_max, &fb_div, &ref_div);
diff = abs(target_clock - (pll->reference_freq * fb_div) /
(ref_div * post_div));
if (diff < diff_best || (diff == diff_best && if (diff < diff_best || (diff == diff_best &&
!(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) {
...@@ -936,28 +985,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -936,28 +985,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
} }
post_div = post_div_best; post_div = post_div_best;
/* limit reference * post divider to a maximum */ /* get the feedback and reference divider for the optimal value */
ref_div_max = min(210 / post_div, ref_div_max); avivo_get_fb_ref_div(nom, den, post_div, fb_div_max, ref_div_max,
&fb_div, &ref_div);
/* get matching reference and feedback divider */
ref_div = max(DIV_ROUND_CLOSEST(den, post_div), 1u);
fb_div = DIV_ROUND_CLOSEST(nom * ref_div * post_div, den);
/* we're almost done, but reference and feedback
divider might be to large now */
nom = fb_div;
den = ref_div;
if (fb_div > fb_div_max) {
ref_div = DIV_ROUND_CLOSEST(den * fb_div_max, nom);
fb_div = fb_div_max;
}
if (ref_div > ref_div_max) {
ref_div = ref_div_max;
fb_div = DIV_ROUND_CLOSEST(nom * ref_div_max, den);
}
/* reduce the numbers to a simpler ratio once more */ /* reduce the numbers to a simpler ratio once more */
/* this also makes sure that the reference divider is large enough */ /* this also makes sure that the reference divider is large enough */
...@@ -979,7 +1009,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, ...@@ -979,7 +1009,7 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
*post_div_p = post_div; *post_div_p = post_div;
DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", 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, freq, *dot_clock_p * 10, *fb_div_p, *frac_fb_div_p,
ref_div, post_div); ref_div, post_div);
} }
......
...@@ -107,11 +107,9 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags) ...@@ -107,11 +107,9 @@ int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags)
flags |= RADEON_IS_PCI; flags |= RADEON_IS_PCI;
} }
if (radeon_runtime_pm == 1) if ((radeon_runtime_pm != 0) &&
flags |= RADEON_IS_PX; radeon_has_atpx() &&
else if ((radeon_runtime_pm == -1) && ((flags & RADEON_IS_IGP) == 0))
radeon_has_atpx() &&
((flags & RADEON_IS_IGP) == 0))
flags |= RADEON_IS_PX; flags |= RADEON_IS_PX;
/* radeon_device_init should report only fatal error /* radeon_device_init should report only fatal error
......
...@@ -603,7 +603,6 @@ static const struct attribute_group *hwmon_groups[] = { ...@@ -603,7 +603,6 @@ static const struct attribute_group *hwmon_groups[] = {
static int radeon_hwmon_init(struct radeon_device *rdev) static int radeon_hwmon_init(struct radeon_device *rdev)
{ {
int err = 0; int err = 0;
struct device *hwmon_dev;
switch (rdev->pm.int_thermal_type) { switch (rdev->pm.int_thermal_type) {
case THERMAL_TYPE_RV6XX: case THERMAL_TYPE_RV6XX:
...@@ -616,11 +615,11 @@ static int radeon_hwmon_init(struct radeon_device *rdev) ...@@ -616,11 +615,11 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
case THERMAL_TYPE_KV: case THERMAL_TYPE_KV:
if (rdev->asic->pm.get_temperature == NULL) if (rdev->asic->pm.get_temperature == NULL)
return err; return err;
hwmon_dev = hwmon_device_register_with_groups(rdev->dev, rdev->pm.int_hwmon_dev = hwmon_device_register_with_groups(rdev->dev,
"radeon", rdev, "radeon", rdev,
hwmon_groups); hwmon_groups);
if (IS_ERR(hwmon_dev)) { if (IS_ERR(rdev->pm.int_hwmon_dev)) {
err = PTR_ERR(hwmon_dev); err = PTR_ERR(rdev->pm.int_hwmon_dev);
dev_err(rdev->dev, dev_err(rdev->dev,
"Unable to register hwmon device: %d\n", err); "Unable to register hwmon device: %d\n", err);
} }
...@@ -632,6 +631,12 @@ static int radeon_hwmon_init(struct radeon_device *rdev) ...@@ -632,6 +631,12 @@ static int radeon_hwmon_init(struct radeon_device *rdev)
return err; return err;
} }
static void radeon_hwmon_fini(struct radeon_device *rdev)
{
if (rdev->pm.int_hwmon_dev)
hwmon_device_unregister(rdev->pm.int_hwmon_dev);
}
static void radeon_dpm_thermal_work_handler(struct work_struct *work) static void radeon_dpm_thermal_work_handler(struct work_struct *work)
{ {
struct radeon_device *rdev = struct radeon_device *rdev =
...@@ -1257,6 +1262,7 @@ int radeon_pm_init(struct radeon_device *rdev) ...@@ -1257,6 +1262,7 @@ int radeon_pm_init(struct radeon_device *rdev)
case CHIP_RV670: case CHIP_RV670:
case CHIP_RS780: case CHIP_RS780:
case CHIP_RS880: case CHIP_RS880:
case CHIP_RV770:
case CHIP_BARTS: case CHIP_BARTS:
case CHIP_TURKS: case CHIP_TURKS:
case CHIP_CAICOS: case CHIP_CAICOS:
...@@ -1273,7 +1279,6 @@ int radeon_pm_init(struct radeon_device *rdev) ...@@ -1273,7 +1279,6 @@ int radeon_pm_init(struct radeon_device *rdev)
else else
rdev->pm.pm_method = PM_METHOD_PROFILE; rdev->pm.pm_method = PM_METHOD_PROFILE;
break; break;
case CHIP_RV770:
case CHIP_RV730: case CHIP_RV730:
case CHIP_RV710: case CHIP_RV710:
case CHIP_RV740: case CHIP_RV740:
...@@ -1353,6 +1358,8 @@ static void radeon_pm_fini_old(struct radeon_device *rdev) ...@@ -1353,6 +1358,8 @@ static void radeon_pm_fini_old(struct radeon_device *rdev)
device_remove_file(rdev->dev, &dev_attr_power_method); device_remove_file(rdev->dev, &dev_attr_power_method);
} }
radeon_hwmon_fini(rdev);
if (rdev->pm.power_state) if (rdev->pm.power_state)
kfree(rdev->pm.power_state); kfree(rdev->pm.power_state);
} }
...@@ -1372,6 +1379,8 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev) ...@@ -1372,6 +1379,8 @@ static void radeon_pm_fini_dpm(struct radeon_device *rdev)
} }
radeon_dpm_fini(rdev); radeon_dpm_fini(rdev);
radeon_hwmon_fini(rdev);
if (rdev->pm.power_state) if (rdev->pm.power_state)
kfree(rdev->pm.power_state); kfree(rdev->pm.power_state);
} }
...@@ -1397,12 +1406,14 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev) ...@@ -1397,12 +1406,14 @@ static void radeon_pm_compute_clocks_old(struct radeon_device *rdev)
rdev->pm.active_crtcs = 0; rdev->pm.active_crtcs = 0;
rdev->pm.active_crtc_count = 0; rdev->pm.active_crtc_count = 0;
list_for_each_entry(crtc, if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
&ddev->mode_config.crtc_list, head) { list_for_each_entry(crtc,
radeon_crtc = to_radeon_crtc(crtc); &ddev->mode_config.crtc_list, head) {
if (radeon_crtc->enabled) { radeon_crtc = to_radeon_crtc(crtc);
rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id); if (radeon_crtc->enabled) {
rdev->pm.active_crtc_count++; rdev->pm.active_crtcs |= (1 << radeon_crtc->crtc_id);
rdev->pm.active_crtc_count++;
}
} }
} }
...@@ -1469,12 +1480,14 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) ...@@ -1469,12 +1480,14 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
/* update active crtc counts */ /* update active crtc counts */
rdev->pm.dpm.new_active_crtcs = 0; rdev->pm.dpm.new_active_crtcs = 0;
rdev->pm.dpm.new_active_crtc_count = 0; rdev->pm.dpm.new_active_crtc_count = 0;
list_for_each_entry(crtc, if (rdev->num_crtc && rdev->mode_info.mode_config_initialized) {
&ddev->mode_config.crtc_list, head) { list_for_each_entry(crtc,
radeon_crtc = to_radeon_crtc(crtc); &ddev->mode_config.crtc_list, head) {
if (crtc->enabled) { radeon_crtc = to_radeon_crtc(crtc);
rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id); if (crtc->enabled) {
rdev->pm.dpm.new_active_crtc_count++; rdev->pm.dpm.new_active_crtcs |= (1 << radeon_crtc->crtc_id);
rdev->pm.dpm.new_active_crtc_count++;
}
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment