Commit 2c1756b1 authored by Keith Packard's avatar Keith Packard

Merge branch 'drm-intel-fixes' into drm-intel-next

parents cf96e46f d74362c9
...@@ -313,10 +313,10 @@ static void i915_hotplug_work_func(struct work_struct *work) ...@@ -313,10 +313,10 @@ static void i915_hotplug_work_func(struct work_struct *work)
if (encoder->hot_plug) if (encoder->hot_plug)
encoder->hot_plug(encoder); encoder->hot_plug(encoder);
mutex_unlock(&mode_config->mutex);
/* Just fire off a uevent and let userspace tell us what to do */ /* Just fire off a uevent and let userspace tell us what to do */
drm_helper_hpd_irq_event(dev); drm_helper_hpd_irq_event(dev);
mutex_unlock(&mode_config->mutex);
} }
static void i915_handle_rps_change(struct drm_device *dev) static void i915_handle_rps_change(struct drm_device *dev)
......
...@@ -2084,9 +2084,6 @@ ...@@ -2084,9 +2084,6 @@
#define DP_PIPEB_SELECT (1 << 30) #define DP_PIPEB_SELECT (1 << 30)
#define DP_PIPE_MASK (1 << 30) #define DP_PIPE_MASK (1 << 30)
#define DP_PIPE_ENABLED(V, P) \
(((V) & (DP_PIPE_MASK | DP_PORT_EN)) == ((P) << 30 | DP_PORT_EN))
/* Link training mode - select a suitable mode for each stage */ /* Link training mode - select a suitable mode for each stage */
#define DP_LINK_TRAIN_PAT_1 (0 << 28) #define DP_LINK_TRAIN_PAT_1 (0 << 28)
#define DP_LINK_TRAIN_PAT_2 (1 << 28) #define DP_LINK_TRAIN_PAT_2 (1 << 28)
...@@ -3076,6 +3073,11 @@ ...@@ -3076,6 +3073,11 @@
#define TRANS_6BPC (2<<5) #define TRANS_6BPC (2<<5)
#define TRANS_12BPC (3<<5) #define TRANS_12BPC (3<<5)
#define _TRANSA_CHICKEN2 0xf0064
#define _TRANSB_CHICKEN2 0xf1064
#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2)
#define TRANS_AUTOTRAIN_GEN_STALL_DIS (1<<31)
#define SOUTH_CHICKEN2 0xc2004 #define SOUTH_CHICKEN2 0xc2004
#define DPLS_EDP_PPS_FIX_DIS (1<<0) #define DPLS_EDP_PPS_FIX_DIS (1<<0)
......
...@@ -980,11 +980,29 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv, ...@@ -980,11 +980,29 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,
pipe_name(pipe)); pipe_name(pipe));
} }
static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,
int reg, u32 port_sel, u32 val)
{
if ((val & DP_PORT_EN) == 0)
return false;
if (HAS_PCH_CPT(dev_priv->dev)) {
u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe);
u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg);
if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel)
return false;
} else {
if ((val & DP_PIPE_MASK) != (pipe << 30))
return false;
}
return true;
}
static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, int reg) enum pipe pipe, int reg, u32 port_sel)
{ {
u32 val = I915_READ(reg); u32 val = I915_READ(reg);
WARN(DP_PIPE_ENABLED(val, pipe), WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val),
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe)); reg, pipe_name(pipe));
} }
...@@ -1004,9 +1022,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv, ...@@ -1004,9 +1022,9 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
int reg; int reg;
u32 val; u32 val;
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D); assert_pch_dp_disabled(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
reg = PCH_ADPA; reg = PCH_ADPA;
val = I915_READ(reg); val = I915_READ(reg);
...@@ -1276,6 +1294,17 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv, ...@@ -1276,6 +1294,17 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
intel_wait_for_pipe_off(dev_priv->dev, pipe); intel_wait_for_pipe_off(dev_priv->dev, pipe);
} }
/*
* Plane regs are double buffered, going from enabled->disabled needs a
* trigger in order to latch. The display address reg provides this.
*/
static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane)
{
I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane)));
}
/** /**
* intel_enable_plane - enable a display plane on a given pipe * intel_enable_plane - enable a display plane on a given pipe
* @dev_priv: i915 private structure * @dev_priv: i915 private structure
...@@ -1299,20 +1328,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv, ...@@ -1299,20 +1328,10 @@ static void intel_enable_plane(struct drm_i915_private *dev_priv,
return; return;
I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE); I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
intel_flush_display_plane(dev_priv, plane);
intel_wait_for_vblank(dev_priv->dev, pipe); intel_wait_for_vblank(dev_priv->dev, pipe);
} }
/*
* Plane regs are double buffered, going from enabled->disabled needs a
* trigger in order to latch. The display address reg provides this.
*/
static void intel_flush_display_plane(struct drm_i915_private *dev_priv,
enum plane plane)
{
u32 reg = DSPADDR(plane);
I915_WRITE(reg, I915_READ(reg));
}
/** /**
* intel_disable_plane - disable a display plane * intel_disable_plane - disable a display plane
* @dev_priv: i915 private structure * @dev_priv: i915 private structure
...@@ -1338,19 +1357,24 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv, ...@@ -1338,19 +1357,24 @@ static void intel_disable_plane(struct drm_i915_private *dev_priv,
} }
static void disable_pch_dp(struct drm_i915_private *dev_priv, static void disable_pch_dp(struct drm_i915_private *dev_priv,
enum pipe pipe, int reg) enum pipe pipe, int reg, u32 port_sel)
{ {
u32 val = I915_READ(reg); u32 val = I915_READ(reg);
if (DP_PIPE_ENABLED(val, pipe)) if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) {
DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);
I915_WRITE(reg, val & ~DP_PORT_EN); I915_WRITE(reg, val & ~DP_PORT_EN);
}
} }
static void disable_pch_hdmi(struct drm_i915_private *dev_priv, static void disable_pch_hdmi(struct drm_i915_private *dev_priv,
enum pipe pipe, int reg) enum pipe pipe, int reg)
{ {
u32 val = I915_READ(reg); u32 val = I915_READ(reg);
if (HDMI_PIPE_ENABLED(val, pipe)) if (HDMI_PIPE_ENABLED(val, pipe)) {
DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",
reg, pipe);
I915_WRITE(reg, val & ~PORT_ENABLE); I915_WRITE(reg, val & ~PORT_ENABLE);
}
} }
/* Disable any ports connected to this transcoder */ /* Disable any ports connected to this transcoder */
...@@ -1362,9 +1386,9 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv, ...@@ -1362,9 +1386,9 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,
val = I915_READ(PCH_PP_CONTROL); val = I915_READ(PCH_PP_CONTROL);
I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS); I915_WRITE(PCH_PP_CONTROL, val | PANEL_UNLOCK_REGS);
disable_pch_dp(dev_priv, pipe, PCH_DP_B); disable_pch_dp(dev_priv, pipe, PCH_DP_B, TRANS_DP_PORT_SEL_B);
disable_pch_dp(dev_priv, pipe, PCH_DP_C); disable_pch_dp(dev_priv, pipe, PCH_DP_C, TRANS_DP_PORT_SEL_C);
disable_pch_dp(dev_priv, pipe, PCH_DP_D); disable_pch_dp(dev_priv, pipe, PCH_DP_D, TRANS_DP_PORT_SEL_D);
reg = PCH_ADPA; reg = PCH_ADPA;
val = I915_READ(reg); val = I915_READ(reg);
...@@ -5523,6 +5547,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc, ...@@ -5523,6 +5547,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
drm_vblank_post_modeset(dev, pipe); drm_vblank_post_modeset(dev, pipe);
intel_crtc->dpms_mode = DRM_MODE_DPMS_ON;
return ret; return ret;
} }
...@@ -7721,10 +7747,12 @@ static void gen6_init_clock_gating(struct drm_device *dev) ...@@ -7721,10 +7747,12 @@ static void gen6_init_clock_gating(struct drm_device *dev)
ILK_DPARB_CLK_GATE | ILK_DPARB_CLK_GATE |
ILK_DPFD_CLK_GATE); ILK_DPFD_CLK_GATE);
for_each_pipe(pipe) for_each_pipe(pipe) {
I915_WRITE(DSPCNTR(pipe), I915_WRITE(DSPCNTR(pipe),
I915_READ(DSPCNTR(pipe)) | I915_READ(DSPCNTR(pipe)) |
DISPPLANE_TRICKLE_FEED_DISABLE); DISPPLANE_TRICKLE_FEED_DISABLE);
intel_flush_display_plane(dev_priv, pipe);
}
} }
static void ivybridge_init_clock_gating(struct drm_device *dev) static void ivybridge_init_clock_gating(struct drm_device *dev)
...@@ -7741,10 +7769,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev) ...@@ -7741,10 +7769,12 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE); I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);
for_each_pipe(pipe) for_each_pipe(pipe) {
I915_WRITE(DSPCNTR(pipe), I915_WRITE(DSPCNTR(pipe),
I915_READ(DSPCNTR(pipe)) | I915_READ(DSPCNTR(pipe)) |
DISPPLANE_TRICKLE_FEED_DISABLE); DISPPLANE_TRICKLE_FEED_DISABLE);
intel_flush_display_plane(dev_priv, pipe);
}
} }
static void g4x_init_clock_gating(struct drm_device *dev) static void g4x_init_clock_gating(struct drm_device *dev)
...@@ -7827,6 +7857,7 @@ static void ibx_init_clock_gating(struct drm_device *dev) ...@@ -7827,6 +7857,7 @@ static void ibx_init_clock_gating(struct drm_device *dev)
static void cpt_init_clock_gating(struct drm_device *dev) static void cpt_init_clock_gating(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int pipe;
/* /*
* On Ibex Peak and Cougar Point, we need to disable clock * On Ibex Peak and Cougar Point, we need to disable clock
...@@ -7836,6 +7867,9 @@ static void cpt_init_clock_gating(struct drm_device *dev) ...@@ -7836,6 +7867,9 @@ static void cpt_init_clock_gating(struct drm_device *dev)
I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE); I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) | I915_WRITE(SOUTH_CHICKEN2, I915_READ(SOUTH_CHICKEN2) |
DPLS_EDP_PPS_FIX_DIS); DPLS_EDP_PPS_FIX_DIS);
/* Without this, mode sets may fail silently on FDI */
for_each_pipe(pipe)
I915_WRITE(TRANS_CHICKEN2(pipe), TRANS_AUTOTRAIN_GEN_STALL_DIS);
} }
static void ironlake_teardown_rc6(struct drm_device *dev) static void ironlake_teardown_rc6(struct drm_device *dev)
......
...@@ -50,6 +50,7 @@ struct intel_dp { ...@@ -50,6 +50,7 @@ struct intel_dp {
bool has_audio; bool has_audio;
int force_audio; int force_audio;
uint32_t color_range; uint32_t color_range;
int dpms_mode;
uint8_t link_bw; uint8_t link_bw;
uint8_t lane_count; uint8_t lane_count;
uint8_t dpcd[8]; uint8_t dpcd[8];
...@@ -1012,6 +1013,8 @@ static void intel_dp_commit(struct drm_encoder *encoder) ...@@ -1012,6 +1013,8 @@ static void intel_dp_commit(struct drm_encoder *encoder)
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev); ironlake_edp_backlight_on(dev);
intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
} }
static void static void
...@@ -1046,6 +1049,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -1046,6 +1049,7 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
if (is_edp(intel_dp)) if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev); ironlake_edp_backlight_on(dev);
} }
intel_dp->dpms_mode = mode;
} }
/* /*
...@@ -1568,6 +1572,18 @@ intel_dp_link_down(struct intel_dp *intel_dp) ...@@ -1568,6 +1572,18 @@ intel_dp_link_down(struct intel_dp *intel_dp)
POSTING_READ(intel_dp->output_reg); POSTING_READ(intel_dp->output_reg);
} }
static bool
intel_dp_get_dpcd(struct intel_dp *intel_dp)
{
if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd)) &&
(intel_dp->dpcd[DP_DPCD_REV] != 0)) {
return true;
}
return false;
}
/* /*
* According to DP spec * According to DP spec
* 5.1.2: * 5.1.2:
...@@ -1580,42 +1596,38 @@ intel_dp_link_down(struct intel_dp *intel_dp) ...@@ -1580,42 +1596,38 @@ intel_dp_link_down(struct intel_dp *intel_dp)
static void static void
intel_dp_check_link_status(struct intel_dp *intel_dp) intel_dp_check_link_status(struct intel_dp *intel_dp)
{ {
int ret; if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
if (!intel_dp->base.base.crtc) if (!intel_dp->base.base.crtc)
return; return;
/* Try to read receiver status if the link appears to be up */
if (!intel_dp_get_link_status(intel_dp)) { if (!intel_dp_get_link_status(intel_dp)) {
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
return; return;
} }
/* Try to read receiver status if the link appears to be up */ /* Now read the DPCD to see if it's actually running */
ret = intel_dp_aux_native_read(intel_dp, if (!intel_dp_get_dpcd(intel_dp)) {
0x000, intel_dp->dpcd,
sizeof (intel_dp->dpcd));
if (ret != sizeof(intel_dp->dpcd)) {
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
return; return;
} }
if (!intel_channel_eq_ok(intel_dp)) { if (!intel_channel_eq_ok(intel_dp)) {
DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
drm_get_encoder_name(&intel_dp->base.base));
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
} }
} }
static enum drm_connector_status static enum drm_connector_status
i915_dp_detect_common(struct intel_dp *intel_dp) intel_dp_detect_dpcd(struct intel_dp *intel_dp)
{ {
enum drm_connector_status status = connector_status_disconnected; if (intel_dp_get_dpcd(intel_dp))
return connector_status_connected;
if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd, return connector_status_disconnected;
sizeof (intel_dp->dpcd)) &&
(intel_dp->dpcd[DP_DPCD_REV] != 0))
status = connector_status_connected;
return status;
} }
static enum drm_connector_status static enum drm_connector_status
...@@ -1631,7 +1643,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp) ...@@ -1631,7 +1643,7 @@ ironlake_dp_detect(struct intel_dp *intel_dp)
return status; return status;
} }
return i915_dp_detect_common(intel_dp); return intel_dp_detect_dpcd(intel_dp);
} }
static enum drm_connector_status static enum drm_connector_status
...@@ -1660,7 +1672,7 @@ g4x_dp_detect(struct intel_dp *intel_dp) ...@@ -1660,7 +1672,7 @@ g4x_dp_detect(struct intel_dp *intel_dp)
if ((temp & bit) == 0) if ((temp & bit) == 0)
return connector_status_disconnected; return connector_status_disconnected;
return i915_dp_detect_common(intel_dp); return intel_dp_detect_dpcd(intel_dp);
} }
/** /**
...@@ -1935,6 +1947,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1935,6 +1947,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
return; return;
intel_dp->output_reg = output_reg; intel_dp->output_reg = output_reg;
intel_dp->dpms_mode = -1;
intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL); intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
if (!intel_connector) { if (!intel_connector) {
...@@ -2011,7 +2024,7 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -2011,7 +2024,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
/* Cache some DPCD data in the eDP case */ /* Cache some DPCD data in the eDP case */
if (is_edp(intel_dp)) { if (is_edp(intel_dp)) {
int ret; bool ret;
u32 pp_on, pp_div; u32 pp_on, pp_div;
pp_on = I915_READ(PCH_PP_ON_DELAYS); pp_on = I915_READ(PCH_PP_ON_DELAYS);
...@@ -2024,11 +2037,9 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -2024,11 +2037,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ dev_priv->panel_t12 *= 100; /* t12 in 100ms units */
ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_panel_vdd_on(intel_dp);
ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV, ret = intel_dp_get_dpcd(intel_dp);
intel_dp->dpcd,
sizeof(intel_dp->dpcd));
ironlake_edp_panel_vdd_off(intel_dp); ironlake_edp_panel_vdd_off(intel_dp);
if (ret == sizeof(intel_dp->dpcd)) { if (ret) {
if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
dev_priv->no_aux_handshake = dev_priv->no_aux_handshake =
intel_dp->dpcd[DP_MAX_DOWNSPREAD] & intel_dp->dpcd[DP_MAX_DOWNSPREAD] &
......
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