Commit b01f2c3a authored by Jesse Barnes's avatar Jesse Barnes Committed by Eric Anholt

drm/i915: only enable hotplug for detected outputs

This patch changes around our hotplug enable code a bit to only enable
it for ports we actually detect and initialize.  This prevents problems
with stuck or spurious interrupts on outputs that aren't actually wired
up, and is generally more correct.

Fixes FDO bug #23183.
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent b295d1b6
...@@ -1249,6 +1249,8 @@ static int i915_load_modeset_init(struct drm_device *dev, ...@@ -1249,6 +1249,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret) if (ret)
goto destroy_ringbuffer; goto destroy_ringbuffer;
intel_modeset_init(dev);
ret = drm_irq_install(dev); ret = drm_irq_install(dev);
if (ret) if (ret)
goto destroy_ringbuffer; goto destroy_ringbuffer;
...@@ -1263,8 +1265,6 @@ static int i915_load_modeset_init(struct drm_device *dev, ...@@ -1263,8 +1265,6 @@ static int i915_load_modeset_init(struct drm_device *dev,
I915_WRITE(INSTPM, (1 << 5) | (1 << 21)); I915_WRITE(INSTPM, (1 << 5) | (1 << 21));
intel_modeset_init(dev);
drm_helper_initial_config(dev); drm_helper_initial_config(dev);
return 0; return 0;
......
...@@ -1084,6 +1084,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev) ...@@ -1084,6 +1084,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
(void) I915_READ(IER); (void) I915_READ(IER);
} }
/*
* Must be called after intel_modeset_init or hotplug interrupts won't be
* enabled correctly.
*/
int i915_driver_irq_postinstall(struct drm_device *dev) int i915_driver_irq_postinstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
...@@ -1106,19 +1110,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev) ...@@ -1106,19 +1110,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
if (I915_HAS_HOTPLUG(dev)) { if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN); u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);
/* Leave other bits alone */ /* Note HDMI and DP share bits */
hotplug_en |= HOTPLUG_EN_MASK; if (dev_priv->hotplug_supported_mask & HDMIB_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMIC_HOTPLUG_INT_STATUS)
hotplug_en |= HDMIC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & HDMID_HOTPLUG_INT_STATUS)
hotplug_en |= HDMID_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOC_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOC_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & SDVOB_HOTPLUG_INT_STATUS)
hotplug_en |= SDVOB_HOTPLUG_INT_EN;
if (dev_priv->hotplug_supported_mask & CRT_HOTPLUG_INT_STATUS)
hotplug_en |= CRT_HOTPLUG_INT_EN;
/* Ignore TV since it's buggy */
I915_WRITE(PORT_HOTPLUG_EN, hotplug_en); I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
dev_priv->hotplug_supported_mask = CRT_HOTPLUG_INT_STATUS |
TV_HOTPLUG_INT_STATUS | SDVOC_HOTPLUG_INT_STATUS |
SDVOB_HOTPLUG_INT_STATUS;
if (IS_G4X(dev)) {
dev_priv->hotplug_supported_mask |=
HDMIB_HOTPLUG_INT_STATUS |
HDMIC_HOTPLUG_INT_STATUS |
HDMID_HOTPLUG_INT_STATUS;
}
/* Enable in IER... */ /* Enable in IER... */
enable_mask |= I915_DISPLAY_PORT_INTERRUPT; enable_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */ /* and unmask in IMR */
......
...@@ -879,13 +879,6 @@ ...@@ -879,13 +879,6 @@
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */ #define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
#define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f #define CRT_FORCE_HOTPLUG_MASK 0xfffffe1f
#define HOTPLUG_EN_MASK (HDMIB_HOTPLUG_INT_EN | \
HDMIC_HOTPLUG_INT_EN | \
HDMID_HOTPLUG_INT_EN | \
SDVOB_HOTPLUG_INT_EN | \
SDVOC_HOTPLUG_INT_EN | \
CRT_HOTPLUG_INT_EN)
#define PORT_HOTPLUG_STAT 0x61114 #define PORT_HOTPLUG_STAT 0x61114
#define HDMIB_HOTPLUG_INT_STATUS (1 << 29) #define HDMIB_HOTPLUG_INT_STATUS (1 << 29)
......
...@@ -548,4 +548,6 @@ void intel_crt_init(struct drm_device *dev) ...@@ -548,4 +548,6 @@ void intel_crt_init(struct drm_device *dev)
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
} }
...@@ -4400,29 +4400,43 @@ static void intel_setup_outputs(struct drm_device *dev) ...@@ -4400,29 +4400,43 @@ static void intel_setup_outputs(struct drm_device *dev)
bool found = false; bool found = false;
if (I915_READ(SDVOB) & SDVO_DETECTED) { if (I915_READ(SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOB\n");
found = intel_sdvo_init(dev, SDVOB); found = intel_sdvo_init(dev, SDVOB);
if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOB\n");
intel_hdmi_init(dev, SDVOB); intel_hdmi_init(dev, SDVOB);
}
if (!found && SUPPORTS_INTEGRATED_DP(dev)) if (!found && SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_B\n");
intel_dp_init(dev, DP_B); intel_dp_init(dev, DP_B);
}
} }
/* Before G4X SDVOC doesn't have its own detect register */ /* Before G4X SDVOC doesn't have its own detect register */
if (I915_READ(SDVOB) & SDVO_DETECTED) if (I915_READ(SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOC\n");
found = intel_sdvo_init(dev, SDVOC); found = intel_sdvo_init(dev, SDVOC);
}
if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) { if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
if (SUPPORTS_INTEGRATED_HDMI(dev)) if (SUPPORTS_INTEGRATED_HDMI(dev)) {
DRM_DEBUG_KMS("probing HDMI on SDVOC\n");
intel_hdmi_init(dev, SDVOC); intel_hdmi_init(dev, SDVOC);
if (SUPPORTS_INTEGRATED_DP(dev)) }
if (SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_C\n");
intel_dp_init(dev, DP_C); intel_dp_init(dev, DP_C);
}
} }
if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED)) if (SUPPORTS_INTEGRATED_DP(dev) &&
(I915_READ(DP_D) & DP_DETECTED)) {
DRM_DEBUG_KMS("probing DP_D\n");
intel_dp_init(dev, DP_D); intel_dp_init(dev, DP_D);
}
} else if (IS_I8XX(dev)) } else if (IS_I8XX(dev))
intel_dvo_init(dev); intel_dvo_init(dev);
......
...@@ -1402,14 +1402,20 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1402,14 +1402,20 @@ intel_dp_init(struct drm_device *dev, int output_reg)
break; break;
case DP_B: case DP_B:
case PCH_DP_B: case PCH_DP_B:
dev_priv->hotplug_supported_mask |=
HDMIB_HOTPLUG_INT_STATUS;
name = "DPDDC-B"; name = "DPDDC-B";
break; break;
case DP_C: case DP_C:
case PCH_DP_C: case PCH_DP_C:
dev_priv->hotplug_supported_mask |=
HDMIC_HOTPLUG_INT_STATUS;
name = "DPDDC-C"; name = "DPDDC-C";
break; break;
case DP_D: case DP_D:
case PCH_DP_D: case PCH_DP_D:
dev_priv->hotplug_supported_mask |=
HDMID_HOTPLUG_INT_STATUS;
name = "DPDDC-D"; name = "DPDDC-D";
break; break;
} }
......
...@@ -303,21 +303,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg) ...@@ -303,21 +303,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
if (sdvox_reg == SDVOB) { if (sdvox_reg == SDVOB) {
intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT); intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB"); intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == SDVOC) { } else if (sdvox_reg == SDVOC) {
intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT); intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC"); intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIB) { } else if (sdvox_reg == HDMIB) {
intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT); intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
"HDMIB"); "HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIC) { } else if (sdvox_reg == HDMIC) {
intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT); intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
"HDMIC"); "HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMID) { } else if (sdvox_reg == HDMID) {
intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT); intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF, intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
"HDMID"); "HDMID");
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
} }
if (!intel_output->ddc_bus) if (!intel_output->ddc_bus)
goto err_connector; goto err_connector;
......
...@@ -2662,6 +2662,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector) ...@@ -2662,6 +2662,7 @@ static void intel_sdvo_create_enhance_property(struct drm_connector *connector)
bool intel_sdvo_init(struct drm_device *dev, int output_device) bool intel_sdvo_init(struct drm_device *dev, int output_device)
{ {
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector; struct drm_connector *connector;
struct intel_output *intel_output; struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv; struct intel_sdvo_priv *sdvo_priv;
...@@ -2708,10 +2709,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) ...@@ -2708,10 +2709,12 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOB/VGA DDC BUS"); "SDVOB/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
} else { } else {
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA, sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOC/VGA DDC BUS"); "SDVOC/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
} }
if (intel_output->ddc_bus == NULL) if (intel_output->ddc_bus == NULL)
......
...@@ -1840,6 +1840,8 @@ intel_tv_init(struct drm_device *dev) ...@@ -1840,6 +1840,8 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector, drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property, dev->mode_config.tv_bottom_margin_property,
tv_priv->margin[TV_MARGIN_BOTTOM]); tv_priv->margin[TV_MARGIN_BOTTOM]);
dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
out: out:
drm_sysfs_connector_add(connector); drm_sysfs_connector_add(connector);
} }
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