|
@@ -980,8 +980,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
|
|
|
pipe_name(pipe));
|
|
|
}
|
|
|
|
|
|
-static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
- int reg, u32 port_sel, u32 val)
|
|
|
+static bool dp_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 port_sel, u32 val)
|
|
|
{
|
|
|
if ((val & DP_PORT_EN) == 0)
|
|
|
return false;
|
|
@@ -998,11 +998,58 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 val)
|
|
|
+{
|
|
|
+ if ((val & PORT_ENABLE) == 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (HAS_PCH_CPT(dev_priv->dev)) {
|
|
|
+ if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if ((val & TRANSCODER_MASK) != TRANSCODER(pipe))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 val)
|
|
|
+{
|
|
|
+ if ((val & LVDS_PORT_EN) == 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (HAS_PCH_CPT(dev_priv->dev)) {
|
|
|
+ if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv,
|
|
|
+ enum pipe pipe, u32 val)
|
|
|
+{
|
|
|
+ if ((val & ADPA_DAC_ENABLE) == 0)
|
|
|
+ return false;
|
|
|
+ if (HAS_PCH_CPT(dev_priv->dev)) {
|
|
|
+ if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe))
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
|
|
|
enum pipe pipe, int reg, u32 port_sel)
|
|
|
{
|
|
|
u32 val = I915_READ(reg);
|
|
|
- WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val),
|
|
|
+ WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
|
|
|
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
|
|
|
reg, pipe_name(pipe));
|
|
|
}
|
|
@@ -1011,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
|
|
|
enum pipe pipe, int reg)
|
|
|
{
|
|
|
u32 val = I915_READ(reg);
|
|
|
- WARN(HDMI_PIPE_ENABLED(val, pipe),
|
|
|
+ WARN(hdmi_pipe_enabled(dev_priv, val, pipe),
|
|
|
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
|
|
|
reg, pipe_name(pipe));
|
|
|
}
|
|
@@ -1028,13 +1075,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
|
|
|
|
|
|
reg = PCH_ADPA;
|
|
|
val = I915_READ(reg);
|
|
|
- WARN(ADPA_PIPE_ENABLED(val, pipe),
|
|
|
+ WARN(adpa_pipe_enabled(dev_priv, val, pipe),
|
|
|
"PCH VGA enabled on transcoder %c, should be disabled\n",
|
|
|
pipe_name(pipe));
|
|
|
|
|
|
reg = PCH_LVDS;
|
|
|
val = I915_READ(reg);
|
|
|
- WARN(LVDS_PIPE_ENABLED(val, pipe),
|
|
|
+ WARN(lvds_pipe_enabled(dev_priv, val, pipe),
|
|
|
"PCH LVDS enabled on transcoder %c, should be disabled\n",
|
|
|
pipe_name(pipe));
|
|
|
|
|
@@ -1360,7 +1407,7 @@ static void disable_pch_dp(struct drm_i915_private *dev_priv,
|
|
|
enum pipe pipe, int reg, u32 port_sel)
|
|
|
{
|
|
|
u32 val = I915_READ(reg);
|
|
|
- if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) {
|
|
|
+ if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {
|
|
|
DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
|
|
|
I915_WRITE(reg, val & ~DP_PORT_EN);
|
|
|
}
|
|
@@ -1370,7 +1417,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
|
|
|
enum pipe pipe, int reg)
|
|
|
{
|
|
|
u32 val = I915_READ(reg);
|
|
|
- if (HDMI_PIPE_ENABLED(val, pipe)) {
|
|
|
+ if (hdmi_pipe_enabled(dev_priv, val, pipe)) {
|
|
|
DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
|
|
|
reg, pipe);
|
|
|
I915_WRITE(reg, val & ~PORT_ENABLE);
|
|
@@ -1392,12 +1439,13 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
|
|
|
|
|
|
reg = PCH_ADPA;
|
|
|
val = I915_READ(reg);
|
|
|
- if (ADPA_PIPE_ENABLED(val, pipe))
|
|
|
+ if (adpa_pipe_enabled(dev_priv, val, pipe))
|
|
|
I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);
|
|
|
|
|
|
reg = PCH_LVDS;
|
|
|
val = I915_READ(reg);
|
|
|
- if (LVDS_PIPE_ENABLED(val, pipe)) {
|
|
|
+ if (lvds_pipe_enabled(dev_priv, val, pipe)) {
|
|
|
+ DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);
|
|
|
I915_WRITE(reg, val & ~LVDS_PORT_EN);
|
|
|
POSTING_READ(reg);
|
|
|
udelay(100);
|
|
@@ -5049,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static void ironlake_update_pch_refclk(struct drm_device *dev)
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ struct drm_mode_config *mode_config = &dev->mode_config;
|
|
|
+ struct drm_crtc *crtc;
|
|
|
+ struct intel_encoder *encoder;
|
|
|
+ struct intel_encoder *has_edp_encoder = NULL;
|
|
|
+ u32 temp;
|
|
|
+ bool has_lvds = false;
|
|
|
+
|
|
|
+ /* We need to take the global config into account */
|
|
|
+ list_for_each_entry(crtc, &mode_config->crtc_list, head) {
|
|
|
+ if (!crtc->enabled)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ list_for_each_entry(encoder, &mode_config->encoder_list,
|
|
|
+ base.head) {
|
|
|
+ if (encoder->base.crtc != crtc)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ switch (encoder->type) {
|
|
|
+ case INTEL_OUTPUT_LVDS:
|
|
|
+ has_lvds = true;
|
|
|
+ case INTEL_OUTPUT_EDP:
|
|
|
+ has_edp_encoder = encoder;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Ironlake: try to setup display ref clock before DPLL
|
|
|
+ * enabling. This is only under driver's control after
|
|
|
+ * PCH B stepping, previous chipset stepping should be
|
|
|
+ * ignoring this setting.
|
|
|
+ */
|
|
|
+ temp = I915_READ(PCH_DREF_CONTROL);
|
|
|
+ /* Always enable nonspread source */
|
|
|
+ temp &= ~DREF_NONSPREAD_SOURCE_MASK;
|
|
|
+ temp |= DREF_NONSPREAD_SOURCE_ENABLE;
|
|
|
+ temp &= ~DREF_SSC_SOURCE_MASK;
|
|
|
+ temp |= DREF_SSC_SOURCE_ENABLE;
|
|
|
+ I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
+
|
|
|
+ POSTING_READ(PCH_DREF_CONTROL);
|
|
|
+ udelay(200);
|
|
|
+
|
|
|
+ if (has_edp_encoder) {
|
|
|
+ if (intel_panel_use_ssc(dev_priv)) {
|
|
|
+ temp |= DREF_SSC1_ENABLE;
|
|
|
+ I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
+
|
|
|
+ POSTING_READ(PCH_DREF_CONTROL);
|
|
|
+ udelay(200);
|
|
|
+ }
|
|
|
+ temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
|
|
+
|
|
|
+ /* Enable CPU source on CPU attached eDP */
|
|
|
+ if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
|
|
|
+ if (intel_panel_use_ssc(dev_priv))
|
|
|
+ temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
|
|
+ else
|
|
|
+ temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
|
|
+ } else {
|
|
|
+ /* Enable SSC on PCH eDP if needed */
|
|
|
+ if (intel_panel_use_ssc(dev_priv)) {
|
|
|
+ DRM_ERROR("enabling SSC on PCH\n");
|
|
|
+ temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
+ POSTING_READ(PCH_DREF_CONTROL);
|
|
|
+ udelay(200);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
struct drm_display_mode *mode,
|
|
|
struct drm_display_mode *adjusted_mode,
|
|
@@ -5244,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
|
|
|
ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
|
|
|
&m_n);
|
|
|
|
|
|
- /* Ironlake: try to setup display ref clock before DPLL
|
|
|
- * enabling. This is only under driver's control after
|
|
|
- * PCH B stepping, previous chipset stepping should be
|
|
|
- * ignoring this setting.
|
|
|
- */
|
|
|
- temp = I915_READ(PCH_DREF_CONTROL);
|
|
|
- /* Always enable nonspread source */
|
|
|
- temp &= ~DREF_NONSPREAD_SOURCE_MASK;
|
|
|
- temp |= DREF_NONSPREAD_SOURCE_ENABLE;
|
|
|
- temp &= ~DREF_SSC_SOURCE_MASK;
|
|
|
- temp |= DREF_SSC_SOURCE_ENABLE;
|
|
|
- I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
-
|
|
|
- POSTING_READ(PCH_DREF_CONTROL);
|
|
|
- udelay(200);
|
|
|
-
|
|
|
- if (has_edp_encoder) {
|
|
|
- if (intel_panel_use_ssc(dev_priv)) {
|
|
|
- temp |= DREF_SSC1_ENABLE;
|
|
|
- I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
-
|
|
|
- POSTING_READ(PCH_DREF_CONTROL);
|
|
|
- udelay(200);
|
|
|
- }
|
|
|
- temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
|
|
|
-
|
|
|
- /* Enable CPU source on CPU attached eDP */
|
|
|
- if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
|
|
|
- if (intel_panel_use_ssc(dev_priv))
|
|
|
- temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
|
|
|
- else
|
|
|
- temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
|
|
|
- } else {
|
|
|
- /* Enable SSC on PCH eDP if needed */
|
|
|
- if (intel_panel_use_ssc(dev_priv)) {
|
|
|
- DRM_ERROR("enabling SSC on PCH\n");
|
|
|
- temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
|
|
|
- }
|
|
|
- }
|
|
|
- I915_WRITE(PCH_DREF_CONTROL, temp);
|
|
|
- POSTING_READ(PCH_DREF_CONTROL);
|
|
|
- udelay(200);
|
|
|
- }
|
|
|
+ ironlake_update_pch_refclk(dev);
|
|
|
|
|
|
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
|
|
|
if (has_reduced_clock)
|