drm/i915: Enable LVDS downclock feature through EDID.
If more than one mode with the same resolution defined in EDID has different refresh rate, it is thought that the downclock is found for LVDS. We will program the different FPx0/1 register so that we can select dynamically between the low and high frequency. On the g4x platform we will use the CxSR feature to switch the different refresh rate if the LVDS downclock feature is supported. Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
c8e0f93a38
commit
18f9ed12f8
|
@ -539,6 +539,8 @@ typedef struct drm_i915_private {
|
|||
/* Reclocking support */
|
||||
bool render_reclock_avail;
|
||||
bool lvds_downclock_avail;
|
||||
/* indicates the reduced downclock for LVDS*/
|
||||
int lvds_downclock;
|
||||
struct work_struct idle_work;
|
||||
struct timer_list idle_timer;
|
||||
bool busy;
|
||||
|
|
|
@ -2869,14 +2869,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (limit->find_reduced_pll && dev_priv->lvds_downclock_avail) {
|
||||
if (is_lvds && limit->find_reduced_pll &&
|
||||
dev_priv->lvds_downclock_avail) {
|
||||
memcpy(&reduced_clock, &clock, sizeof(intel_clock_t));
|
||||
has_reduced_clock = limit->find_reduced_pll(limit, crtc,
|
||||
(adjusted_mode->clock*3/4),
|
||||
dev_priv->lvds_downclock,
|
||||
refclk,
|
||||
&reduced_clock);
|
||||
if (has_reduced_clock && (clock.p != reduced_clock.p)) {
|
||||
/*
|
||||
* If the different P is found, it means that we can't
|
||||
* switch the display clock by using the FP0/FP1.
|
||||
* In such case we will disable the LVDS downclock
|
||||
* feature.
|
||||
*/
|
||||
DRM_DEBUG_KMS("Different P is found for "
|
||||
"LVDS clock/downclock\n");
|
||||
has_reduced_clock = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* SDVO TV has fixed PLL values depend on its clock range,
|
||||
this mirrors vbios setting. */
|
||||
if (is_sdvo && is_tv) {
|
||||
|
|
|
@ -913,6 +913,61 @@ static int intel_lid_present(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID
|
||||
* @dev: drm device
|
||||
* @connector: LVDS connector
|
||||
*
|
||||
* Find the reduced downclock for LVDS in EDID.
|
||||
*/
|
||||
static void intel_find_lvds_downclock(struct drm_device *dev,
|
||||
struct drm_connector *connector)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_display_mode *scan, *panel_fixed_mode;
|
||||
int temp_downclock;
|
||||
|
||||
panel_fixed_mode = dev_priv->panel_fixed_mode;
|
||||
temp_downclock = panel_fixed_mode->clock;
|
||||
|
||||
mutex_lock(&dev->mode_config.mutex);
|
||||
list_for_each_entry(scan, &connector->probed_modes, head) {
|
||||
/*
|
||||
* If one mode has the same resolution with the fixed_panel
|
||||
* mode while they have the different refresh rate, it means
|
||||
* that the reduced downclock is found for the LVDS. In such
|
||||
* case we can set the different FPx0/1 to dynamically select
|
||||
* between low and high frequency.
|
||||
*/
|
||||
if (scan->hdisplay == panel_fixed_mode->hdisplay &&
|
||||
scan->hsync_start == panel_fixed_mode->hsync_start &&
|
||||
scan->hsync_end == panel_fixed_mode->hsync_end &&
|
||||
scan->htotal == panel_fixed_mode->htotal &&
|
||||
scan->vdisplay == panel_fixed_mode->vdisplay &&
|
||||
scan->vsync_start == panel_fixed_mode->vsync_start &&
|
||||
scan->vsync_end == panel_fixed_mode->vsync_end &&
|
||||
scan->vtotal == panel_fixed_mode->vtotal) {
|
||||
if (scan->clock < temp_downclock) {
|
||||
/*
|
||||
* The downclock is already found. But we
|
||||
* expect to find the lower downclock.
|
||||
*/
|
||||
temp_downclock = scan->clock;
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
if (temp_downclock < panel_fixed_mode->clock) {
|
||||
/* We found the downclock for LVDS. */
|
||||
dev_priv->lvds_downclock_avail = 1;
|
||||
dev_priv->lvds_downclock = temp_downclock;
|
||||
DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
|
||||
"Normal clock %dKhz, downclock %dKhz\n",
|
||||
panel_fixed_mode->clock, temp_downclock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* intel_lvds_init - setup LVDS connectors on this device
|
||||
* @dev: drm device
|
||||
|
@ -1023,6 +1078,7 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
dev_priv->panel_fixed_mode =
|
||||
drm_mode_duplicate(dev, scan);
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
intel_find_lvds_downclock(dev, connector);
|
||||
goto out;
|
||||
}
|
||||
mutex_unlock(&dev->mode_config.mutex);
|
||||
|
|
Loading…
Reference in New Issue