summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_lvds.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-12-10 21:56:47 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2009-12-10 21:56:47 -0800
commit3ef884b4c04e857c283cc77ca70ad8f638d94b0e (patch)
treec8c5b872e836e6ffe8bd08ab3477f9e8260575ed /drivers/gpu/drm/i915/intel_lvds.c
parent4e5df8069b0e4e36c6b528b3be7da298e6f454cd (diff)
parent4361e52ad0372e6fd2240a2207b49a4de1f45ca9 (diff)
downloadblackbird-op-linux-3ef884b4c04e857c283cc77ca70ad8f638d94b0e.tar.gz
blackbird-op-linux-3ef884b4c04e857c283cc77ca70ad8f638d94b0e.zip
Merge branch 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6
* 'drm-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6: (189 commits) drm/radeon/kms: fix warning about cur_placement being uninitialised. drm/ttm: Print debug information on memory manager when eviction fails drm: Add memory manager debug function drm/radeon/kms: restore surface registers on resume. drm/radeon/kms/r600/r700: fallback gracefully on ucode failure drm/ttm: Initialize eviction placement in case the driver callback doesn't drm/radeon/kms: cleanup structure and module if initialization fails drm/radeon/kms: actualy set the eviction placements we choose drm/radeon/kms: Fix NULL ptr dereference drm/radeon/kms/avivo: add support for new pll selection algo drm/radeon/kms/avivo: fix some bugs in the display bandwidth setup drm/radeon/kms: fix return value from fence function. drm/radeon: Remove tests for -ERESTART from the TTM code. drm/ttm: Have the TTM code return -ERESTARTSYS instead of -ERESTART. drm/radeon/kms: Convert radeon to new TTM validation API (V2) drm/ttm: Rework validation & memory space allocation (V3) drm: Add search/get functions to get a block in a specific range drm/radeon/kms: fix avivo tiling regression since radeon object rework drm/i915: Remove a debugging printk from hangcheck drm/radeon/kms: make sure i2c id matches ...
Diffstat (limited to 'drivers/gpu/drm/i915/intel_lvds.c')
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c140
1 files changed, 118 insertions, 22 deletions
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index eb365021bb5a..3118ce274e67 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -56,7 +56,7 @@ static void intel_lvds_set_backlight(struct drm_device *dev, int level)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 blc_pwm_ctl, reg;
- if (IS_IGDNG(dev))
+ if (IS_IRONLAKE(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
@@ -74,7 +74,7 @@ static u32 intel_lvds_get_max_backlight(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
- if (IS_IGDNG(dev))
+ if (IS_IRONLAKE(dev))
reg = BLC_PWM_PCH_CTL2;
else
reg = BLC_PWM_CTL;
@@ -91,7 +91,7 @@ static void intel_lvds_set_power(struct drm_device *dev, bool on)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp_status, ctl_reg, status_reg;
- if (IS_IGDNG(dev)) {
+ if (IS_IRONLAKE(dev)) {
ctl_reg = PCH_PP_CONTROL;
status_reg = PCH_PP_STATUS;
} else {
@@ -137,7 +137,7 @@ static void intel_lvds_save(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
- if (IS_IGDNG(dev)) {
+ if (IS_IRONLAKE(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
@@ -174,7 +174,7 @@ static void intel_lvds_restore(struct drm_connector *connector)
u32 pp_on_reg, pp_off_reg, pp_ctl_reg, pp_div_reg;
u32 pwm_ctl_reg;
- if (IS_IGDNG(dev)) {
+ if (IS_IRONLAKE(dev)) {
pp_on_reg = PCH_PP_ON_DELAYS;
pp_off_reg = PCH_PP_OFF_DELAYS;
pp_ctl_reg = PCH_PP_CONTROL;
@@ -297,7 +297,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
}
/* full screen scale for now */
- if (IS_IGDNG(dev))
+ if (IS_IRONLAKE(dev))
goto out;
/* 965+ wants fuzzy fitting */
@@ -327,7 +327,7 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
* to register description and PRM.
* Change the value here to see the borders for debugging
*/
- if (!IS_IGDNG(dev)) {
+ if (!IS_IRONLAKE(dev)) {
I915_WRITE(BCLRPAT_A, 0);
I915_WRITE(BCLRPAT_B, 0);
}
@@ -548,7 +548,7 @@ static void intel_lvds_prepare(struct drm_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 reg;
- if (IS_IGDNG(dev))
+ if (IS_IRONLAKE(dev))
reg = BLC_PWM_CPU_CTL;
else
reg = BLC_PWM_CTL;
@@ -587,7 +587,7 @@ static void intel_lvds_mode_set(struct drm_encoder *encoder,
* settings.
*/
- if (IS_IGDNG(dev))
+ if (IS_IRONLAKE(dev))
return;
/*
@@ -914,6 +914,101 @@ 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;
+}
+
+/*
+ * Enumerate the child dev array parsed from VBT to check whether
+ * the LVDS is present.
+ * If it is present, return 1.
+ * If it is not present, return false.
+ * If no child dev is parsed from VBT, it assumes that the LVDS is present.
+ * Note: The addin_offset should also be checked for LVDS panel.
+ * Only when it is non-zero, it is assumed that it is present.
+ */
+static int lvds_is_present_in_vbt(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct child_device_config *p_child;
+ int i, ret;
+
+ if (!dev_priv->child_dev_num)
+ return 1;
+
+ ret = 0;
+ for (i = 0; i < dev_priv->child_dev_num; i++) {
+ p_child = dev_priv->child_dev + i;
+ /*
+ * If the device type is not LFP, continue.
+ * If the device type is 0x22, it is also regarded as LFP.
+ */
+ if (p_child->device_type != DEVICE_TYPE_INT_LFP &&
+ p_child->device_type != DEVICE_TYPE_LFP)
+ continue;
+
+ /* The addin_offset should be checked. Only when it is
+ * non-zero, it is regarded as present.
+ */
+ if (p_child->addin_offset) {
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**
* intel_lvds_init - setup LVDS connectors on this device
* @dev: drm device
*
@@ -936,21 +1031,20 @@ void intel_lvds_init(struct drm_device *dev)
if (dmi_check_system(intel_no_lvds))
return;
- /* Assume that any device without an ACPI LID device also doesn't
- * have an integrated LVDS. We would be better off parsing the BIOS
- * to get a reliable indicator, but that code isn't written yet.
- *
- * In the case of all-in-one desktops using LVDS that we've seen,
- * they're using SDVO LVDS.
+ /*
+ * Assume LVDS is present if there's an ACPI lid device or if the
+ * device is present in the VBT.
*/
- if (!intel_lid_present())
+ if (!lvds_is_present_in_vbt(dev) && !intel_lid_present()) {
+ DRM_DEBUG_KMS("LVDS is not present in VBT and no lid detected\n");
return;
+ }
- if (IS_IGDNG(dev)) {
+ if (IS_IRONLAKE(dev)) {
if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0)
return;
if (dev_priv->edp_support) {
- DRM_DEBUG("disable LVDS for eDP support\n");
+ DRM_DEBUG_KMS("disable LVDS for eDP support\n");
return;
}
gpio = PCH_GPIOC;
@@ -1023,6 +1117,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);
@@ -1047,8 +1142,8 @@ void intel_lvds_init(struct drm_device *dev)
* correct mode.
*/
- /* IGDNG: FIXME if still fail, not try pipe mode now */
- if (IS_IGDNG(dev))
+ /* Ironlake: FIXME if still fail, not try pipe mode now */
+ if (IS_IRONLAKE(dev))
goto failed;
lvds = I915_READ(LVDS);
@@ -1069,7 +1164,7 @@ void intel_lvds_init(struct drm_device *dev)
goto failed;
out:
- if (IS_IGDNG(dev)) {
+ if (IS_IRONLAKE(dev)) {
u32 pwm;
/* make sure PWM is enabled */
pwm = I915_READ(BLC_PWM_CPU_CTL2);
@@ -1082,7 +1177,7 @@ out:
}
dev_priv->lid_notifier.notifier_call = intel_lid_notify;
if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) {
- DRM_DEBUG("lid notifier registration failed\n");
+ DRM_DEBUG_KMS("lid notifier registration failed\n");
dev_priv->lid_notifier.notifier_call = NULL;
}
drm_sysfs_connector_add(connector);
@@ -1093,5 +1188,6 @@ failed:
if (intel_output->ddc_bus)
intel_i2c_destroy(intel_output->ddc_bus);
drm_connector_cleanup(connector);
+ drm_encoder_cleanup(encoder);
kfree(intel_output);
}
OpenPOWER on IntegriCloud