Commit abaafc0a authored by Dave Airlie's avatar Dave Airlie

Merge branch 'drm-fixes-3.15' of git://people.freedesktop.org/~deathsimple/linux into drm-next

1. Further PLL parameter fixes.
2. Fixes for HPD on DP
3. Could of different PM fixes
4. Disabling DPM on RV770

* 'drm-fixes-3.15' of git://people.freedesktop.org/~deathsimple/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 4d0fa8a0 73acacc7
...@@ -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