|
@@ -34,6 +34,25 @@
|
|
#include "i915_drm.h"
|
|
#include "i915_drm.h"
|
|
#include "i915_drv.h"
|
|
#include "i915_drv.h"
|
|
|
|
|
|
|
|
+/* Here's the desired hotplug mode */
|
|
|
|
+#define ADPA_HOTPLUG_BITS (ADPA_CRT_HOTPLUG_PERIOD_128 | \
|
|
|
|
+ ADPA_CRT_HOTPLUG_WARMUP_10MS | \
|
|
|
|
+ ADPA_CRT_HOTPLUG_SAMPLE_4S | \
|
|
|
|
+ ADPA_CRT_HOTPLUG_VOLTAGE_50 | \
|
|
|
|
+ ADPA_CRT_HOTPLUG_VOLREF_325MV | \
|
|
|
|
+ ADPA_CRT_HOTPLUG_ENABLE)
|
|
|
|
+
|
|
|
|
+struct intel_crt {
|
|
|
|
+ struct intel_encoder base;
|
|
|
|
+ bool force_hotplug_required;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct intel_crt *intel_attached_crt(struct drm_connector *connector)
|
|
|
|
+{
|
|
|
|
+ return container_of(intel_attached_encoder(connector),
|
|
|
|
+ struct intel_crt, base);
|
|
|
|
+}
|
|
|
|
+
|
|
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
|
static void intel_crt_dpms(struct drm_encoder *encoder, int mode)
|
|
{
|
|
{
|
|
struct drm_device *dev = encoder->dev;
|
|
struct drm_device *dev = encoder->dev;
|
|
@@ -129,7 +148,7 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
|
|
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
|
|
dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
|
|
}
|
|
}
|
|
|
|
|
|
- adpa = 0;
|
|
|
|
|
|
+ adpa = ADPA_HOTPLUG_BITS;
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
|
|
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
|
adpa |= ADPA_HSYNC_ACTIVE_HIGH;
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
|
@@ -157,53 +176,44 @@ static void intel_crt_mode_set(struct drm_encoder *encoder,
|
|
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
|
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector)
|
|
{
|
|
{
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_device *dev = connector->dev;
|
|
|
|
+ struct intel_crt *crt = intel_attached_crt(connector);
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
- u32 adpa, temp;
|
|
|
|
|
|
+ u32 adpa;
|
|
bool ret;
|
|
bool ret;
|
|
- bool turn_off_dac = false;
|
|
|
|
|
|
|
|
- temp = adpa = I915_READ(PCH_ADPA);
|
|
|
|
|
|
+ /* The first time through, trigger an explicit detection cycle */
|
|
|
|
+ if (crt->force_hotplug_required) {
|
|
|
|
+ bool turn_off_dac = HAS_PCH_SPLIT(dev);
|
|
|
|
+ u32 save_adpa;
|
|
|
|
|
|
- if (HAS_PCH_SPLIT(dev))
|
|
|
|
- turn_off_dac = true;
|
|
|
|
-
|
|
|
|
- adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
|
|
|
- if (turn_off_dac)
|
|
|
|
- adpa &= ~ADPA_DAC_ENABLE;
|
|
|
|
-
|
|
|
|
- /* disable HPD first */
|
|
|
|
- I915_WRITE(PCH_ADPA, adpa);
|
|
|
|
- (void)I915_READ(PCH_ADPA);
|
|
|
|
-
|
|
|
|
- adpa |= (ADPA_CRT_HOTPLUG_PERIOD_128 |
|
|
|
|
- ADPA_CRT_HOTPLUG_WARMUP_10MS |
|
|
|
|
- ADPA_CRT_HOTPLUG_SAMPLE_4S |
|
|
|
|
- ADPA_CRT_HOTPLUG_VOLTAGE_50 | /* default */
|
|
|
|
- ADPA_CRT_HOTPLUG_VOLREF_325MV |
|
|
|
|
- ADPA_CRT_HOTPLUG_ENABLE |
|
|
|
|
- ADPA_CRT_HOTPLUG_FORCE_TRIGGER);
|
|
|
|
-
|
|
|
|
- DRM_DEBUG_KMS("pch crt adpa 0x%x", adpa);
|
|
|
|
- I915_WRITE(PCH_ADPA, adpa);
|
|
|
|
-
|
|
|
|
- if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
|
|
|
- 1000))
|
|
|
|
- DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
|
|
|
-
|
|
|
|
- if (turn_off_dac) {
|
|
|
|
- /* Make sure hotplug is enabled */
|
|
|
|
- I915_WRITE(PCH_ADPA, temp | ADPA_CRT_HOTPLUG_ENABLE);
|
|
|
|
- (void)I915_READ(PCH_ADPA);
|
|
|
|
|
|
+ crt->force_hotplug_required = 0;
|
|
|
|
+
|
|
|
|
+ save_adpa = adpa = I915_READ(PCH_ADPA);
|
|
|
|
+ DRM_DEBUG_KMS("trigger hotplug detect cycle: adpa=0x%x\n", adpa);
|
|
|
|
+
|
|
|
|
+ adpa |= ADPA_CRT_HOTPLUG_FORCE_TRIGGER;
|
|
|
|
+ if (turn_off_dac)
|
|
|
|
+ adpa &= ~ADPA_DAC_ENABLE;
|
|
|
|
+
|
|
|
|
+ I915_WRITE(PCH_ADPA, adpa);
|
|
|
|
+
|
|
|
|
+ if (wait_for((I915_READ(PCH_ADPA) & ADPA_CRT_HOTPLUG_FORCE_TRIGGER) == 0,
|
|
|
|
+ 1000))
|
|
|
|
+ DRM_DEBUG_KMS("timed out waiting for FORCE_TRIGGER");
|
|
|
|
+
|
|
|
|
+ if (turn_off_dac) {
|
|
|
|
+ I915_WRITE(PCH_ADPA, save_adpa);
|
|
|
|
+ POSTING_READ(PCH_ADPA);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
/* Check the status to see if both blue and green are on now */
|
|
/* Check the status to see if both blue and green are on now */
|
|
adpa = I915_READ(PCH_ADPA);
|
|
adpa = I915_READ(PCH_ADPA);
|
|
- adpa &= ADPA_CRT_HOTPLUG_MONITOR_MASK;
|
|
|
|
- if ((adpa == ADPA_CRT_HOTPLUG_MONITOR_COLOR) ||
|
|
|
|
- (adpa == ADPA_CRT_HOTPLUG_MONITOR_MONO))
|
|
|
|
|
|
+ if ((adpa & ADPA_CRT_HOTPLUG_MONITOR_MASK) != 0)
|
|
ret = true;
|
|
ret = true;
|
|
else
|
|
else
|
|
ret = false;
|
|
ret = false;
|
|
|
|
+ DRM_DEBUG_KMS("ironlake hotplug adpa=0x%x, result %d\n", adpa, ret);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -277,13 +287,12 @@ static bool intel_crt_ddc_probe(struct drm_i915_private *dev_priv, int ddc_bus)
|
|
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
|
|
return i2c_transfer(&dev_priv->gmbus[ddc_bus].adapter, msgs, 1) == 1;
|
|
}
|
|
}
|
|
|
|
|
|
-static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
|
|
|
|
|
|
+static bool intel_crt_detect_ddc(struct intel_crt *crt)
|
|
{
|
|
{
|
|
- struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
|
|
|
|
- struct drm_i915_private *dev_priv = encoder->dev->dev_private;
|
|
|
|
|
|
+ struct drm_i915_private *dev_priv = crt->base.base.dev->dev_private;
|
|
|
|
|
|
/* CRT should always be at 0, but check anyway */
|
|
/* CRT should always be at 0, but check anyway */
|
|
- if (intel_encoder->type != INTEL_OUTPUT_ANALOG)
|
|
|
|
|
|
+ if (crt->base.type != INTEL_OUTPUT_ANALOG)
|
|
return false;
|
|
return false;
|
|
|
|
|
|
if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
|
|
if (intel_crt_ddc_probe(dev_priv, dev_priv->crt_ddc_pin)) {
|
|
@@ -291,7 +300,7 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
|
|
- if (intel_ddc_probe(intel_encoder, dev_priv->crt_ddc_pin)) {
|
|
|
|
|
|
+ if (intel_ddc_probe(&crt->base, dev_priv->crt_ddc_pin)) {
|
|
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
|
|
DRM_DEBUG_KMS("CRT detected via DDC:0x50 [EDID]\n");
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -300,9 +309,9 @@ static bool intel_crt_detect_ddc(struct drm_encoder *encoder)
|
|
}
|
|
}
|
|
|
|
|
|
static enum drm_connector_status
|
|
static enum drm_connector_status
|
|
-intel_crt_load_detect(struct drm_crtc *crtc, struct intel_encoder *intel_encoder)
|
|
|
|
|
|
+intel_crt_load_detect(struct drm_crtc *crtc, struct intel_crt *crt)
|
|
{
|
|
{
|
|
- struct drm_encoder *encoder = &intel_encoder->base;
|
|
|
|
|
|
+ struct drm_encoder *encoder = &crt->base.base;
|
|
struct drm_device *dev = encoder->dev;
|
|
struct drm_device *dev = encoder->dev;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
@@ -434,7 +443,7 @@ static enum drm_connector_status
|
|
intel_crt_detect(struct drm_connector *connector, bool force)
|
|
intel_crt_detect(struct drm_connector *connector, bool force)
|
|
{
|
|
{
|
|
struct drm_device *dev = connector->dev;
|
|
struct drm_device *dev = connector->dev;
|
|
- struct intel_encoder *encoder = intel_attached_encoder(connector);
|
|
|
|
|
|
+ struct intel_crt *crt = intel_attached_crt(connector);
|
|
struct drm_crtc *crtc;
|
|
struct drm_crtc *crtc;
|
|
int dpms_mode;
|
|
int dpms_mode;
|
|
enum drm_connector_status status;
|
|
enum drm_connector_status status;
|
|
@@ -443,28 +452,31 @@ intel_crt_detect(struct drm_connector *connector, bool force)
|
|
if (intel_crt_detect_hotplug(connector)) {
|
|
if (intel_crt_detect_hotplug(connector)) {
|
|
DRM_DEBUG_KMS("CRT detected via hotplug\n");
|
|
DRM_DEBUG_KMS("CRT detected via hotplug\n");
|
|
return connector_status_connected;
|
|
return connector_status_connected;
|
|
- } else
|
|
|
|
|
|
+ } else {
|
|
|
|
+ DRM_DEBUG_KMS("CRT not detected via hotplug\n");
|
|
return connector_status_disconnected;
|
|
return connector_status_disconnected;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- if (intel_crt_detect_ddc(&encoder->base))
|
|
|
|
|
|
+ if (intel_crt_detect_ddc(crt))
|
|
return connector_status_connected;
|
|
return connector_status_connected;
|
|
|
|
|
|
if (!force)
|
|
if (!force)
|
|
return connector->status;
|
|
return connector->status;
|
|
|
|
|
|
/* for pre-945g platforms use load detect */
|
|
/* for pre-945g platforms use load detect */
|
|
- if (encoder->base.crtc && encoder->base.crtc->enabled) {
|
|
|
|
- status = intel_crt_load_detect(encoder->base.crtc, encoder);
|
|
|
|
|
|
+ crtc = crt->base.base.crtc;
|
|
|
|
+ if (crtc && crtc->enabled) {
|
|
|
|
+ status = intel_crt_load_detect(crtc, crt);
|
|
} else {
|
|
} else {
|
|
- crtc = intel_get_load_detect_pipe(encoder, connector,
|
|
|
|
|
|
+ crtc = intel_get_load_detect_pipe(&crt->base, connector,
|
|
NULL, &dpms_mode);
|
|
NULL, &dpms_mode);
|
|
if (crtc) {
|
|
if (crtc) {
|
|
- if (intel_crt_detect_ddc(&encoder->base))
|
|
|
|
|
|
+ if (intel_crt_detect_ddc(crt))
|
|
status = connector_status_connected;
|
|
status = connector_status_connected;
|
|
else
|
|
else
|
|
- status = intel_crt_load_detect(crtc, encoder);
|
|
|
|
- intel_release_load_detect_pipe(encoder,
|
|
|
|
|
|
+ status = intel_crt_load_detect(crtc, crt);
|
|
|
|
+ intel_release_load_detect_pipe(&crt->base,
|
|
connector, dpms_mode);
|
|
connector, dpms_mode);
|
|
} else
|
|
} else
|
|
status = connector_status_unknown;
|
|
status = connector_status_unknown;
|
|
@@ -536,17 +548,17 @@ static const struct drm_encoder_funcs intel_crt_enc_funcs = {
|
|
void intel_crt_init(struct drm_device *dev)
|
|
void intel_crt_init(struct drm_device *dev)
|
|
{
|
|
{
|
|
struct drm_connector *connector;
|
|
struct drm_connector *connector;
|
|
- struct intel_encoder *intel_encoder;
|
|
|
|
|
|
+ struct intel_crt *crt;
|
|
struct intel_connector *intel_connector;
|
|
struct intel_connector *intel_connector;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
|
|
- intel_encoder = kzalloc(sizeof(struct intel_encoder), GFP_KERNEL);
|
|
|
|
- if (!intel_encoder)
|
|
|
|
|
|
+ crt = kzalloc(sizeof(struct intel_crt), GFP_KERNEL);
|
|
|
|
+ if (!crt)
|
|
return;
|
|
return;
|
|
|
|
|
|
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
|
|
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
|
|
if (!intel_connector) {
|
|
if (!intel_connector) {
|
|
- kfree(intel_encoder);
|
|
|
|
|
|
+ kfree(crt);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -554,20 +566,20 @@ void intel_crt_init(struct drm_device *dev)
|
|
drm_connector_init(dev, &intel_connector->base,
|
|
drm_connector_init(dev, &intel_connector->base,
|
|
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
|
&intel_crt_connector_funcs, DRM_MODE_CONNECTOR_VGA);
|
|
|
|
|
|
- drm_encoder_init(dev, &intel_encoder->base, &intel_crt_enc_funcs,
|
|
|
|
|
|
+ drm_encoder_init(dev, &crt->base.base, &intel_crt_enc_funcs,
|
|
DRM_MODE_ENCODER_DAC);
|
|
DRM_MODE_ENCODER_DAC);
|
|
|
|
|
|
- intel_connector_attach_encoder(intel_connector, intel_encoder);
|
|
|
|
|
|
+ intel_connector_attach_encoder(intel_connector, &crt->base);
|
|
|
|
|
|
- intel_encoder->type = INTEL_OUTPUT_ANALOG;
|
|
|
|
- intel_encoder->clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT) |
|
|
|
|
- (1 << INTEL_ANALOG_CLONE_BIT) |
|
|
|
|
- (1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
|
|
|
- intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
|
|
|
|
|
+ crt->base.type = INTEL_OUTPUT_ANALOG;
|
|
|
|
+ crt->base.clone_mask = (1 << INTEL_SDVO_NON_TV_CLONE_BIT |
|
|
|
|
+ 1 << INTEL_ANALOG_CLONE_BIT |
|
|
|
|
+ 1 << INTEL_SDVO_LVDS_CLONE_BIT);
|
|
|
|
+ crt->base.crtc_mask = (1 << 0) | (1 << 1);
|
|
connector->interlace_allowed = 1;
|
|
connector->interlace_allowed = 1;
|
|
connector->doublescan_allowed = 0;
|
|
connector->doublescan_allowed = 0;
|
|
|
|
|
|
- drm_encoder_helper_add(&intel_encoder->base, &intel_crt_helper_funcs);
|
|
|
|
|
|
+ drm_encoder_helper_add(&crt->base.base, &intel_crt_helper_funcs);
|
|
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);
|
|
@@ -577,5 +589,22 @@ void intel_crt_init(struct drm_device *dev)
|
|
else
|
|
else
|
|
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
|
connector->polled = DRM_CONNECTOR_POLL_CONNECT;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * Configure the automatic hotplug detection stuff
|
|
|
|
+ */
|
|
|
|
+ crt->force_hotplug_required = 0;
|
|
|
|
+ if (HAS_PCH_SPLIT(dev)) {
|
|
|
|
+ u32 adpa;
|
|
|
|
+
|
|
|
|
+ adpa = I915_READ(PCH_ADPA);
|
|
|
|
+ adpa &= ~ADPA_CRT_HOTPLUG_MASK;
|
|
|
|
+ adpa |= ADPA_HOTPLUG_BITS;
|
|
|
|
+ I915_WRITE(PCH_ADPA, adpa);
|
|
|
|
+ POSTING_READ(PCH_ADPA);
|
|
|
|
+
|
|
|
|
+ DRM_DEBUG_KMS("pch crt adpa set to 0x%x\n", adpa);
|
|
|
|
+ crt->force_hotplug_required = 1;
|
|
|
|
+ }
|
|
|
|
+
|
|
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
|
dev_priv->hotplug_supported_mask |= CRT_HOTPLUG_INT_STATUS;
|
|
}
|
|
}
|