67,8 → 67,13 |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crt *crt = intel_encoder_to_crt(encoder); |
enum intel_display_power_domain power_domain; |
u32 tmp; |
|
power_domain = intel_display_port_power_domain(encoder); |
if (!intel_display_power_enabled(dev_priv, power_domain)) |
return false; |
|
tmp = I915_READ(crt->adpa_reg); |
|
if (!(tmp & ADPA_DAC_ENABLE)) |
131,6 → 136,18 |
pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder); |
} |
|
static void hsw_crt_pre_enable(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
|
WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL already enabled\n"); |
I915_WRITE(SPLL_CTL, |
SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC); |
POSTING_READ(SPLL_CTL); |
udelay(20); |
} |
|
/* Note: The caller is required to filter out dpms modes not supported by the |
* platform. */ |
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode) |
138,28 → 155,49 |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crt *crt = intel_encoder_to_crt(encoder); |
u32 temp; |
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); |
struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; |
u32 adpa; |
|
temp = I915_READ(crt->adpa_reg); |
temp &= ~(ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE); |
temp &= ~ADPA_DAC_ENABLE; |
if (INTEL_INFO(dev)->gen >= 5) |
adpa = ADPA_HOTPLUG_BITS; |
else |
adpa = 0; |
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
adpa |= ADPA_HSYNC_ACTIVE_HIGH; |
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
adpa |= ADPA_VSYNC_ACTIVE_HIGH; |
|
/* For CPT allow 3 pipe config, for others just use A or B */ |
if (HAS_PCH_LPT(dev)) |
; /* Those bits don't exist here */ |
else if (HAS_PCH_CPT(dev)) |
adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); |
else if (crtc->pipe == 0) |
adpa |= ADPA_PIPE_A_SELECT; |
else |
adpa |= ADPA_PIPE_B_SELECT; |
|
if (!HAS_PCH_SPLIT(dev)) |
I915_WRITE(BCLRPAT(crtc->pipe), 0); |
|
switch (mode) { |
case DRM_MODE_DPMS_ON: |
temp |= ADPA_DAC_ENABLE; |
adpa |= ADPA_DAC_ENABLE; |
break; |
case DRM_MODE_DPMS_STANDBY: |
temp |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; |
adpa |= ADPA_DAC_ENABLE | ADPA_HSYNC_CNTL_DISABLE; |
break; |
case DRM_MODE_DPMS_SUSPEND: |
temp |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; |
adpa |= ADPA_DAC_ENABLE | ADPA_VSYNC_CNTL_DISABLE; |
break; |
case DRM_MODE_DPMS_OFF: |
temp |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; |
adpa |= ADPA_HSYNC_CNTL_DISABLE | ADPA_VSYNC_CNTL_DISABLE; |
break; |
} |
|
I915_WRITE(crt->adpa_reg, temp); |
I915_WRITE(crt->adpa_reg, adpa); |
} |
|
static void intel_disable_crt(struct intel_encoder *encoder) |
167,6 → 205,20 |
intel_crt_set_dpms(encoder, DRM_MODE_DPMS_OFF); |
} |
|
|
static void hsw_crt_post_disable(struct intel_encoder *encoder) |
{ |
struct drm_device *dev = encoder->base.dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
uint32_t val; |
|
DRM_DEBUG_KMS("Disabling SPLL\n"); |
val = I915_READ(SPLL_CTL); |
WARN_ON(!(val & SPLL_PLL_ENABLE)); |
I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE); |
POSTING_READ(SPLL_CTL); |
} |
|
static void intel_enable_crt(struct intel_encoder *encoder) |
{ |
struct intel_crt *crt = intel_encoder_to_crt(encoder); |
261,43 → 313,13 |
if (HAS_PCH_LPT(dev)) |
pipe_config->pipe_bpp = 24; |
|
return true; |
/* FDI must always be 2.7 GHz */ |
if (HAS_DDI(dev)) { |
pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL; |
pipe_config->port_clock = 135000 * 2; |
} |
|
static void intel_crt_mode_set(struct intel_encoder *encoder) |
{ |
|
struct drm_device *dev = encoder->base.dev; |
struct intel_crt *crt = intel_encoder_to_crt(encoder); |
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode; |
u32 adpa; |
|
if (INTEL_INFO(dev)->gen >= 5) |
adpa = ADPA_HOTPLUG_BITS; |
else |
adpa = 0; |
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) |
adpa |= ADPA_HSYNC_ACTIVE_HIGH; |
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) |
adpa |= ADPA_VSYNC_ACTIVE_HIGH; |
|
/* For CPT allow 3 pipe config, for others just use A or B */ |
if (HAS_PCH_LPT(dev)) |
; /* Those bits don't exist here */ |
else if (HAS_PCH_CPT(dev)) |
adpa |= PORT_TRANS_SEL_CPT(crtc->pipe); |
else if (crtc->pipe == 0) |
adpa |= ADPA_PIPE_A_SELECT; |
else |
adpa |= ADPA_PIPE_B_SELECT; |
|
if (!HAS_PCH_SPLIT(dev)) |
I915_WRITE(BCLRPAT(crtc->pipe), 0); |
|
I915_WRITE(crt->adpa_reg, adpa); |
return true; |
} |
|
static bool intel_ironlake_crt_detect_hotplug(struct drm_connector *connector) |
629,14 → 651,21 |
intel_crt_detect(struct drm_connector *connector, bool force) |
{ |
struct drm_device *dev = connector->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crt *crt = intel_attached_crt(connector); |
struct intel_encoder *intel_encoder = &crt->base; |
enum intel_display_power_domain power_domain; |
enum drm_connector_status status; |
struct intel_load_detect_pipe tmp; |
struct drm_modeset_acquire_ctx ctx; |
|
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n", |
connector->base.id, drm_get_connector_name(connector), |
connector->base.id, connector->name, |
force); |
|
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
|
if (I915_HAS_HOTPLUG(dev)) { |
/* We can not rely on the HPD pin always being correctly wired |
* up, for example many KVM do not pass it through, and so |
644,26 → 673,35 |
*/ |
if (intel_crt_detect_hotplug(connector)) { |
DRM_DEBUG_KMS("CRT detected via hotplug\n"); |
return connector_status_connected; |
status = connector_status_connected; |
goto out; |
} else |
DRM_DEBUG_KMS("CRT not detected via hotplug\n"); |
} |
|
if (intel_crt_detect_ddc(connector)) |
return connector_status_connected; |
if (intel_crt_detect_ddc(connector)) { |
status = connector_status_connected; |
goto out; |
} |
|
/* Load detection is broken on HPD capable machines. Whoever wants a |
* broken monitor (without edid) to work behind a broken kvm (that fails |
* to have the right resistors for HP detection) needs to fix this up. |
* For now just bail out. */ |
if (I915_HAS_HOTPLUG(dev)) |
return connector_status_disconnected; |
if (I915_HAS_HOTPLUG(dev)) { |
status = connector_status_disconnected; |
goto out; |
} |
|
if (!force) |
return connector->status; |
if (!force) { |
status = connector->status; |
goto out; |
} |
|
drm_modeset_acquire_init(&ctx, 0); |
|
/* for pre-945g platforms use load detect */ |
if (intel_get_load_detect_pipe(connector, NULL, &tmp)) { |
if (intel_get_load_detect_pipe(connector, NULL, &tmp, &ctx)) { |
if (intel_crt_detect_ddc(connector)) |
status = connector_status_connected; |
else |
672,6 → 710,11 |
} else |
status = connector_status_unknown; |
|
drm_modeset_drop_locks(&ctx); |
drm_modeset_acquire_fini(&ctx); |
|
out: |
intel_display_power_put(dev_priv, power_domain); |
return status; |
} |
|
685,17 → 728,28 |
{ |
struct drm_device *dev = connector->dev; |
struct drm_i915_private *dev_priv = dev->dev_private; |
struct intel_crt *crt = intel_attached_crt(connector); |
struct intel_encoder *intel_encoder = &crt->base; |
enum intel_display_power_domain power_domain; |
int ret; |
struct i2c_adapter *i2c; |
|
power_domain = intel_display_port_power_domain(intel_encoder); |
intel_display_power_get(dev_priv, power_domain); |
|
i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin); |
ret = intel_crt_ddc_get_modes(connector, i2c); |
if (ret || !IS_G4X(dev)) |
return ret; |
goto out; |
|
/* Try to probe digital port for output in DVI-I -> VGA mode. */ |
i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB); |
return intel_crt_ddc_get_modes(connector, i2c); |
ret = intel_crt_ddc_get_modes(connector, i2c); |
|
out: |
intel_display_power_put(dev_priv, power_domain); |
|
return ret; |
} |
|
static int intel_crt_set_property(struct drm_connector *connector, |
777,7 → 831,7 |
intel_connector_attach_encoder(intel_connector, &crt->base); |
|
crt->base.type = INTEL_OUTPUT_ANALOG; |
crt->base.cloneable = true; |
crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI); |
if (IS_I830(dev)) |
crt->base.crtc_mask = (1 << 0); |
else |
797,7 → 851,6 |
crt->adpa_reg = ADPA; |
|
crt->base.compute_config = intel_crt_compute_config; |
crt->base.mode_set = intel_crt_mode_set; |
crt->base.disable = intel_disable_crt; |
crt->base.enable = intel_enable_crt; |
if (I915_HAS_HOTPLUG(dev)) |
805,15 → 858,18 |
if (HAS_DDI(dev)) { |
crt->base.get_config = hsw_crt_get_config; |
crt->base.get_hw_state = intel_ddi_get_hw_state; |
crt->base.pre_enable = hsw_crt_pre_enable; |
crt->base.post_disable = hsw_crt_post_disable; |
} else { |
crt->base.get_config = intel_crt_get_config; |
crt->base.get_hw_state = intel_crt_get_hw_state; |
} |
intel_connector->get_hw_state = intel_connector_get_hw_state; |
intel_connector->unregister = intel_connector_unregister; |
|
drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs); |
|
drm_sysfs_connector_add(connector); |
drm_connector_register(connector); |
|
if (!I915_HAS_HOTPLUG(dev)) |
intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT; |
834,4 → 890,6 |
|
dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config; |
} |
|
intel_crt_reset(connector); |
} |