Skip to content

Commit

Permalink
drm/i915: only enable hotplug for detected outputs
Browse files Browse the repository at this point in the history
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: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
  • Loading branch information
Jesse Barnes authored and Eric Anholt committed Dec 16, 2009
1 parent b295d1b commit b01f2c3
Show file tree
Hide file tree
Showing 9 changed files with 59 additions and 26 deletions.
4 changes: 2 additions & 2 deletions drivers/gpu/drm/i915/i915_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,8 @@ static int i915_load_modeset_init(struct drm_device *dev,
if (ret)
goto destroy_ringbuffer;

intel_modeset_init(dev);

ret = drm_irq_install(dev);
if (ret)
goto destroy_ringbuffer;
Expand All @@ -1263,8 +1265,6 @@ static int i915_load_modeset_init(struct drm_device *dev,

I915_WRITE(INSTPM, (1 << 5) | (1 << 21));

intel_modeset_init(dev);

drm_helper_initial_config(dev);

return 0;
Expand Down
30 changes: 19 additions & 11 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,10 @@ void i915_driver_irq_preinstall(struct drm_device * dev)
(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)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
Expand All @@ -1106,19 +1110,23 @@ int i915_driver_irq_postinstall(struct drm_device *dev)
if (I915_HAS_HOTPLUG(dev)) {
u32 hotplug_en = I915_READ(PORT_HOTPLUG_EN);

/* Leave other bits alone */
hotplug_en |= HOTPLUG_EN_MASK;
/* Note HDMI and DP share bits */
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);

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_mask |= I915_DISPLAY_PORT_INTERRUPT;
/* and unmask in IMR */
Expand Down
7 changes: 0 additions & 7 deletions drivers/gpu/drm/i915/i915_reg.h
Original file line number Diff line number Diff line change
Expand Up @@ -879,13 +879,6 @@
#define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2)
#define CRT_HOTPLUG_MASK (0x3fc) /* Bits 9-2 */
#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 HDMIB_HOTPLUG_INT_STATUS (1 << 29)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/intel_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,4 +548,6 @@ void intel_crt_init(struct drm_device *dev)
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);

drm_sysfs_connector_add(connector);

dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
}
26 changes: 20 additions & 6 deletions drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -4400,29 +4400,43 @@ static void intel_setup_outputs(struct drm_device *dev)
bool found = false;

if (I915_READ(SDVOB) & SDVO_DETECTED) {
DRM_DEBUG_KMS("probing SDVOB\n");
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);
}

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);
}
}

/* 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);
}

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);
if (SUPPORTS_INTEGRATED_DP(dev))
}
if (SUPPORTS_INTEGRATED_DP(dev)) {
DRM_DEBUG_KMS("probing DP_C\n");
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);
}
} else if (IS_I8XX(dev))
intel_dvo_init(dev);

Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1402,14 +1402,20 @@ intel_dp_init(struct drm_device *dev, int output_reg)
break;
case DP_B:
case PCH_DP_B:
dev_priv->hotplug_supported_mask |=
HDMIB_HOTPLUG_INT_STATUS;
name = "DPDDC-B";
break;
case DP_C:
case PCH_DP_C:
dev_priv->hotplug_supported_mask |=
HDMIC_HOTPLUG_INT_STATUS;
name = "DPDDC-C";
break;
case DP_D:
case PCH_DP_D:
dev_priv->hotplug_supported_mask |=
HDMID_HOTPLUG_INT_STATUS;
name = "DPDDC-D";
break;
}
Expand Down
5 changes: 5 additions & 0 deletions drivers/gpu/drm/i915/intel_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,21 +303,26 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
if (sdvox_reg == SDVOB) {
intel_output->clone_mask = (1 << INTEL_HDMIB_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == SDVOC) {
intel_output->clone_mask = (1 << INTEL_HDMIC_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, GPIOD, "HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIB) {
intel_output->clone_mask = (1 << INTEL_HDMID_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOE,
"HDMIB");
dev_priv->hotplug_supported_mask |= HDMIB_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMIC) {
intel_output->clone_mask = (1 << INTEL_HDMIE_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOD,
"HDMIC");
dev_priv->hotplug_supported_mask |= HDMIC_HOTPLUG_INT_STATUS;
} else if (sdvox_reg == HDMID) {
intel_output->clone_mask = (1 << INTEL_HDMIF_CLONE_BIT);
intel_output->ddc_bus = intel_i2c_create(dev, PCH_GPIOF,
"HDMID");
dev_priv->hotplug_supported_mask |= HDMID_HOTPLUG_INT_STATUS;
}
if (!intel_output->ddc_bus)
goto err_connector;
Expand Down
3 changes: 3 additions & 0 deletions drivers/gpu/drm/i915/intel_sdvo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_connector *connector;
struct intel_output *intel_output;
struct intel_sdvo_priv *sdvo_priv;
Expand Down Expand Up @@ -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");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOB/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOB_HOTPLUG_INT_STATUS;
} else {
intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
sdvo_priv->analog_ddc_bus = intel_i2c_create(dev, GPIOA,
"SDVOC/VGA DDC BUS");
dev_priv->hotplug_supported_mask |= SDVOC_HOTPLUG_INT_STATUS;
}

if (intel_output->ddc_bus == NULL)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/intel_tv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,8 @@ intel_tv_init(struct drm_device *dev)
drm_connector_attach_property(connector,
dev->mode_config.tv_bottom_margin_property,
tv_priv->margin[TV_MARGIN_BOTTOM]);

dev_priv->hotplug_supported_mask |= TV_HOTPLUG_INT_STATUS;
out:
drm_sysfs_connector_add(connector);
}

0 comments on commit b01f2c3

Please sign in to comment.