diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 614 |
1 files changed, 457 insertions, 157 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 44fef5e1c490..fc1a0832af4f 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -36,7 +36,7 @@ #include "i915_drv.h" #include "drm_dp_helper.h" - +#define DP_RECEIVER_CAP_SIZE 0xf #define DP_LINK_STATUS_SIZE 6 #define DP_LINK_CHECK_TIMEOUT (10 * 1000) @@ -53,12 +53,21 @@ struct intel_dp { int dpms_mode; uint8_t link_bw; uint8_t lane_count; - uint8_t dpcd[8]; + uint8_t dpcd[DP_RECEIVER_CAP_SIZE]; struct i2c_adapter adapter; struct i2c_algo_dp_aux_data algo; bool is_pch_edp; uint8_t train_set[4]; uint8_t link_status[DP_LINK_STATUS_SIZE]; + int panel_power_up_delay; + int panel_power_down_delay; + int panel_power_cycle_delay; + int backlight_on_delay; + int backlight_off_delay; + struct drm_display_mode *panel_fixed_mode; /* for eDP */ + struct delayed_work panel_vdd_work; + bool want_panel_vdd; + unsigned long panel_off_jiffies; }; /** @@ -86,6 +95,17 @@ static bool is_pch_edp(struct intel_dp *intel_dp) return intel_dp->is_pch_edp; } +/** + * is_cpu_edp - is the port on the CPU and attached to an eDP panel? + * @intel_dp: DP struct + * + * Returns true if the given DP struct corresponds to a CPU eDP port. + */ +static bool is_cpu_edp(struct intel_dp *intel_dp) +{ + return is_edp(intel_dp) && !is_pch_edp(intel_dp); +} + static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder) { return container_of(encoder, struct intel_dp, base.base); @@ -121,7 +141,7 @@ static void intel_dp_complete_link_train(struct intel_dp *intel_dp); static void intel_dp_link_down(struct intel_dp *intel_dp); void -intel_edp_link_config (struct intel_encoder *intel_encoder, +intel_edp_link_config(struct intel_encoder *intel_encoder, int *lane_num, int *link_bw) { struct intel_dp *intel_dp = container_of(intel_encoder, struct intel_dp, base); @@ -175,9 +195,25 @@ intel_dp_link_clock(uint8_t link_bw) return 162000; } -/* I think this is a fiction */ +/* + * The units on the numbers in the next two are... bizarre. Examples will + * make it clearer; this one parallels an example in the eDP spec. + * + * intel_dp_max_data_rate for one lane of 2.7GHz evaluates as: + * + * 270000 * 1 * 8 / 10 == 216000 + * + * The actual data capacity of that configuration is 2.16Gbit/s, so the + * units are decakilobits. ->clock in a drm_display_mode is in kilohertz - + * or equivalently, kilopixels per second - so for 1680x1050R it'd be + * 119000. At 18bpp that's 2142000 kilobits per second. + * + * Thus the strange-looking division by 10 in intel_dp_link_required, to + * get the result in decakilobits instead of kilobits. + */ + static int -intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pixel_clock) +intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock) { struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -186,7 +222,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi if (intel_crtc) bpp = intel_crtc->bpp; - return (pixel_clock * bpp + 7) / 8; + return (pixel_clock * bpp + 9) / 10; } static int @@ -200,24 +236,19 @@ intel_dp_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct intel_dp *intel_dp = intel_attached_dp(connector); - struct drm_device *dev = connector->dev; - struct drm_i915_private *dev_priv = dev->dev_private; int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp)); int max_lanes = intel_dp_max_lane_count(intel_dp); - if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) { - if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay) + if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { + if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay) return MODE_PANEL; - if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay) + if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay) return MODE_PANEL; } - /* only refuse the mode on non eDP since we have seen some weird eDP panels - which are outside spec tolerances but somehow work by magic */ - if (!is_edp(intel_dp) && - (intel_dp_link_required(connector->dev, intel_dp, mode->clock) - > intel_dp_max_data_rate(max_link_clock, max_lanes))) + if (intel_dp_link_required(intel_dp, mode->clock) + > intel_dp_max_data_rate(max_link_clock, max_lanes)) return MODE_CLOCK_HIGH; if (mode->clock < 10000) @@ -279,6 +310,38 @@ intel_hrawclk(struct drm_device *dev) } } +static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return (I915_READ(PCH_PP_STATUS) & PP_ON) != 0; +} + +static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + return (I915_READ(PCH_PP_CONTROL) & EDP_FORCE_VDD) != 0; +} + +static void +intel_dp_check_edp(struct intel_dp *intel_dp) +{ + struct drm_device *dev = intel_dp->base.base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!is_edp(intel_dp)) + return; + if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) { + WARN(1, "eDP powered off while attempting aux channel communication.\n"); + DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n", + I915_READ(PCH_PP_STATUS), + I915_READ(PCH_PP_CONTROL)); + } +} + static int intel_dp_aux_ch(struct intel_dp *intel_dp, uint8_t *send, int send_bytes, @@ -295,6 +358,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, uint32_t aux_clock_divider; int try, precharge; + intel_dp_check_edp(intel_dp); /* The clock divider is based off the hrawclk, * and would like to run at 2MHz. So, take the * hrawclk value and divide by 2 and use that @@ -302,7 +366,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, * Note that PCH attached eDP panels should use a 125MHz input * clock divider. */ - if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) { + if (is_cpu_edp(intel_dp)) { if (IS_GEN6(dev)) aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */ else @@ -337,7 +401,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, for (i = 0; i < send_bytes; i += 4) I915_WRITE(ch_data + i, pack_aux(send + i, send_bytes - i)); - + /* Send the command and wait for it to complete */ I915_WRITE(ch_ctl, DP_AUX_CH_CTL_SEND_BUSY | @@ -354,7 +418,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, break; udelay(100); } - + /* Clear done status and any errors */ I915_WRITE(ch_ctl, status | @@ -390,7 +454,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT); if (recv_bytes > recv_size) recv_bytes = recv_size; - + for (i = 0; i < recv_bytes; i += 4) unpack_aux(I915_READ(ch_data + i), recv + i, recv_bytes - i); @@ -408,6 +472,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp, int msg_bytes; uint8_t ack; + intel_dp_check_edp(intel_dp); if (send_bytes > 16) return -1; msg[0] = AUX_NATIVE_WRITE << 4; @@ -450,6 +515,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, uint8_t ack; int ret; + intel_dp_check_edp(intel_dp); msg[0] = AUX_NATIVE_READ << 4; msg[1] = address >> 8; msg[2] = address & 0xff; @@ -493,6 +559,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, int reply_bytes; int ret; + intel_dp_check_edp(intel_dp); /* Set up the command byte */ if (mode & MODE_I2C_READ) msg[0] = AUX_I2C_READ << 4; @@ -573,24 +640,32 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, return -EREMOTEIO; } +static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp); +static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync); + static int intel_dp_i2c_init(struct intel_dp *intel_dp, struct intel_connector *intel_connector, const char *name) { + int ret; + DRM_DEBUG_KMS("i2c_init %s\n", name); intel_dp->algo.running = false; intel_dp->algo.address = 0; intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch; - memset(&intel_dp->adapter, '\0', sizeof (intel_dp->adapter)); + memset(&intel_dp->adapter, '\0', sizeof(intel_dp->adapter)); intel_dp->adapter.owner = THIS_MODULE; intel_dp->adapter.class = I2C_CLASS_DDC; - strncpy (intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); + strncpy(intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1); intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0'; intel_dp->adapter.algo_data = &intel_dp->algo; intel_dp->adapter.dev.parent = &intel_connector->base.kdev; - return i2c_dp_aux_add_bus(&intel_dp->adapter); + ironlake_edp_panel_vdd_on(intel_dp); + ret = i2c_dp_aux_add_bus(&intel_dp->adapter); + ironlake_edp_panel_vdd_off(intel_dp, false); + return ret; } static bool @@ -598,29 +673,28 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dp *intel_dp = enc_to_intel_dp(encoder); int lane_count, clock; int max_lane_count = intel_dp_max_lane_count(intel_dp); int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 }; - if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) { - intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); + if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) { + intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode); intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, mode, adjusted_mode); /* * the mode->clock is used to calculate the Data&Link M/N * of the pipe. For the eDP the fixed clock should be used. */ - mode->clock = dev_priv->panel_fixed_mode->clock; + mode->clock = intel_dp->panel_fixed_mode->clock; } for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) { for (clock = 0; clock <= max_clock; clock++) { int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count); - if (intel_dp_link_required(encoder->dev, intel_dp, mode->clock) + if (intel_dp_link_required(intel_dp, mode->clock) <= link_avail) { intel_dp->link_bw = bws[clock]; intel_dp->lane_count = lane_count; @@ -634,19 +708,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, } } - if (is_edp(intel_dp)) { - /* okay we failed just pick the highest */ - intel_dp->lane_count = max_lane_count; - intel_dp->link_bw = bws[max_clock]; - adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw); - DRM_DEBUG_KMS("Force picking display port link bw %02x lane " - "count %d clock %d\n", - intel_dp->link_bw, intel_dp->lane_count, - adjusted_mode->clock); - - return true; - } - return false; } @@ -740,6 +801,9 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, } } +static void ironlake_edp_pll_on(struct drm_encoder *encoder); +static void ironlake_edp_pll_off(struct drm_encoder *encoder); + static void intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -749,6 +813,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_crtc *crtc = intel_dp->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + /* Turn on the eDP PLL if needed */ + if (is_edp(intel_dp)) { + if (!is_pch_edp(intel_dp)) + ironlake_edp_pll_on(encoder); + else + ironlake_edp_pll_off(encoder); + } + intel_dp->DP = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; intel_dp->DP |= intel_dp->color_range; @@ -757,7 +829,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) intel_dp->DP |= DP_SYNC_VS_HIGH; - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; else intel_dp->DP |= DP_LINK_TRAIN_OFF; @@ -773,8 +845,12 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp->DP |= DP_PORT_WIDTH_4; break; } - if (intel_dp->has_audio) + if (intel_dp->has_audio) { + DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", + pipe_name(intel_crtc->pipe)); intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; + intel_write_eld(encoder, adjusted_mode); + } memset(intel_dp->link_configuration, 0, DP_LINK_CONFIGURATION_SIZE); intel_dp->link_configuration[0] = intel_dp->link_bw; @@ -794,7 +870,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev)) intel_dp->DP |= DP_PIPEB_SELECT; - if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) { + if (is_cpu_edp(intel_dp)) { /* don't miss out required setting for eDP */ intel_dp->DP |= DP_PLL_ENABLE; if (adjusted_mode->clock < 200000) @@ -804,58 +880,150 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, } } +static void ironlake_wait_panel_off(struct intel_dp *intel_dp) +{ + unsigned long off_time; + unsigned long delay; + + DRM_DEBUG_KMS("Wait for panel power off time\n"); + + if (ironlake_edp_have_panel_power(intel_dp) || + ironlake_edp_have_panel_vdd(intel_dp)) + { + DRM_DEBUG_KMS("Panel still on, no delay needed\n"); + return; + } + + off_time = intel_dp->panel_off_jiffies + msecs_to_jiffies(intel_dp->panel_power_down_delay); + if (time_after(jiffies, off_time)) { + DRM_DEBUG_KMS("Time already passed"); + return; + } + delay = jiffies_to_msecs(off_time - jiffies); + if (delay > intel_dp->panel_power_down_delay) + delay = intel_dp->panel_power_down_delay; + DRM_DEBUG_KMS("Waiting an additional %ld ms\n", delay); + msleep(delay); +} + static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; - /* - * If the panel wasn't on, make sure there's not a currently - * active PP sequence before enabling AUX VDD. - */ - if (!(I915_READ(PCH_PP_STATUS) & PP_ON)) - msleep(dev_priv->panel_t3); + if (!is_edp(intel_dp)) + return; + DRM_DEBUG_KMS("Turn eDP VDD on\n"); + + WARN(intel_dp->want_panel_vdd, + "eDP VDD already requested on\n"); + + intel_dp->want_panel_vdd = true; + if (ironlake_edp_have_panel_vdd(intel_dp)) { + DRM_DEBUG_KMS("eDP VDD already on\n"); + return; + } + ironlake_wait_panel_off(intel_dp); pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; pp |= EDP_FORCE_VDD; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); + DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", + I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); + + /* + * If the panel wasn't on, delay before accessing aux channel + */ + if (!ironlake_edp_have_panel_power(intel_dp)) { + DRM_DEBUG_KMS("eDP was not running\n"); + msleep(intel_dp->panel_power_up_delay); + } } -static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp) +static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; - pp = I915_READ(PCH_PP_CONTROL); - pp &= ~EDP_FORCE_VDD; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) { + pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; + pp &= ~EDP_FORCE_VDD; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + + /* Make sure sequencer is idle before allowing subsequent activity */ + DRM_DEBUG_KMS("PCH_PP_STATUS: 0x%08x PCH_PP_CONTROL: 0x%08x\n", + I915_READ(PCH_PP_STATUS), I915_READ(PCH_PP_CONTROL)); + intel_dp->panel_off_jiffies = jiffies; + } +} + +static void ironlake_panel_vdd_work(struct work_struct *__work) +{ + struct intel_dp *intel_dp = container_of(to_delayed_work(__work), + struct intel_dp, panel_vdd_work); + struct drm_device *dev = intel_dp->base.base.dev; - /* Make sure sequencer is idle before allowing subsequent activity */ - msleep(dev_priv->panel_t12); + mutex_lock(&dev->struct_mutex); + ironlake_panel_vdd_off_sync(intel_dp); + mutex_unlock(&dev->struct_mutex); +} + +static void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync) +{ + if (!is_edp(intel_dp)) + return; + + DRM_DEBUG_KMS("Turn eDP VDD off %d\n", intel_dp->want_panel_vdd); + WARN(!intel_dp->want_panel_vdd, "eDP VDD not forced on"); + + intel_dp->want_panel_vdd = false; + + if (sync) { + ironlake_panel_vdd_off_sync(intel_dp); + } else { + /* + * Queue the timer to fire a long + * time from now (relative to the power down delay) + * to keep the panel power up across a sequence of operations + */ + schedule_delayed_work(&intel_dp->panel_vdd_work, + msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5)); + } } /* Returns true if the panel was already on when called */ -static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) +static void ironlake_edp_panel_on(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE; - if (I915_READ(PCH_PP_STATUS) & PP_ON) - return true; + if (!is_edp(intel_dp)) + return; + if (ironlake_edp_have_panel_power(intel_dp)) + return; + ironlake_wait_panel_off(intel_dp); pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; + + if (IS_GEN5(dev)) { + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + } - /* ILK workaround: disable reset around power sequence */ - pp &= ~PANEL_POWER_RESET; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - - pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON; + pp |= POWER_TARGET_ON; I915_WRITE(PCH_PP_CONTROL, pp); POSTING_READ(PCH_PP_CONTROL); @@ -864,44 +1032,64 @@ static bool ironlake_edp_panel_on (struct intel_dp *intel_dp) DRM_ERROR("panel on wait timed out: 0x%08x\n", I915_READ(PCH_PP_STATUS)); - pp |= PANEL_POWER_RESET; /* restore panel reset bit */ - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); - - return false; + if (IS_GEN5(dev)) { + pp |= PANEL_POWER_RESET; /* restore panel reset bit */ + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + } } -static void ironlake_edp_panel_off (struct drm_device *dev) +static void ironlake_edp_panel_off(struct drm_encoder *encoder) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK; + if (!is_edp(intel_dp)) + return; pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; + + if (IS_GEN5(dev)) { + /* ILK workaround: disable reset around power sequence */ + pp &= ~PANEL_POWER_RESET; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + } - /* ILK workaround: disable reset around power sequence */ - pp &= ~PANEL_POWER_RESET; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + intel_dp->panel_off_jiffies = jiffies; - pp &= ~POWER_TARGET_ON; - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + if (IS_GEN5(dev)) { + pp &= ~POWER_TARGET_ON; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + pp &= ~POWER_TARGET_ON; + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + msleep(intel_dp->panel_power_cycle_delay); - if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000)) - DRM_ERROR("panel off wait timed out: 0x%08x\n", - I915_READ(PCH_PP_STATUS)); + if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000)) + DRM_ERROR("panel off wait timed out: 0x%08x\n", + I915_READ(PCH_PP_STATUS)); - pp |= PANEL_POWER_RESET; /* restore panel reset bit */ - I915_WRITE(PCH_PP_CONTROL, pp); - POSTING_READ(PCH_PP_CONTROL); + pp |= PANEL_POWER_RESET; /* restore panel reset bit */ + I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + } } -static void ironlake_edp_backlight_on (struct drm_device *dev) +static void ironlake_edp_backlight_on(struct intel_dp *intel_dp) { + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + if (!is_edp(intel_dp)) + return; + DRM_DEBUG_KMS("\n"); /* * If we enable the backlight right away following a panel power @@ -909,21 +1097,32 @@ static void ironlake_edp_backlight_on (struct drm_device *dev) * link. So delay a bit to make sure the image is solid before * allowing it to appear. */ - msleep(300); + msleep(intel_dp->backlight_on_delay); pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; pp |= EDP_BLC_ENABLE; I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); } -static void ironlake_edp_backlight_off (struct drm_device *dev) +static void ironlake_edp_backlight_off(struct intel_dp *intel_dp) { + struct drm_device *dev = intel_dp->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; + if (!is_edp(intel_dp)) + return; + DRM_DEBUG_KMS("\n"); pp = I915_READ(PCH_PP_CONTROL); + pp &= ~PANEL_UNLOCK_MASK; + pp |= PANEL_UNLOCK_REGS; pp &= ~EDP_BLC_ENABLE; I915_WRITE(PCH_PP_CONTROL, pp); + POSTING_READ(PCH_PP_CONTROL); + msleep(intel_dp->backlight_off_delay); } static void ironlake_edp_pll_on(struct drm_encoder *encoder) @@ -986,43 +1185,39 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) static void intel_dp_prepare(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - struct drm_device *dev = encoder->dev; /* Wake up the sink first */ + ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); + ironlake_edp_panel_vdd_off(intel_dp, false); - if (is_edp(intel_dp)) { - ironlake_edp_backlight_off(dev); - ironlake_edp_panel_off(dev); - if (!is_pch_edp(intel_dp)) - ironlake_edp_pll_on(encoder); - else - ironlake_edp_pll_off(encoder); - } + /* Make sure the panel is off before trying to + * change the mode + */ + ironlake_edp_backlight_off(intel_dp); intel_dp_link_down(intel_dp); + ironlake_edp_panel_off(encoder); } static void intel_dp_commit(struct drm_encoder *encoder) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct drm_device *dev = encoder->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc); - if (is_edp(intel_dp)) - ironlake_edp_panel_vdd_on(intel_dp); - + ironlake_edp_panel_vdd_on(intel_dp); + intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_start_link_train(intel_dp); - - if (is_edp(intel_dp)) { - ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp); - } + ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); - - if (is_edp(intel_dp)) - ironlake_edp_backlight_on(dev); + ironlake_edp_backlight_on(intel_dp); intel_dp->dpms_mode = DRM_MODE_DPMS_ON; + + if (HAS_PCH_CPT(dev)) + intel_cpt_verify_modeset(dev, intel_crtc->pipe); } static void @@ -1034,28 +1229,27 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) uint32_t dp_reg = I915_READ(intel_dp->output_reg); if (mode != DRM_MODE_DPMS_ON) { + ironlake_edp_panel_vdd_on(intel_dp); if (is_edp(intel_dp)) - ironlake_edp_backlight_off(dev); + ironlake_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, mode); intel_dp_link_down(intel_dp); - if (is_edp(intel_dp)) - ironlake_edp_panel_off(dev); + ironlake_edp_panel_off(encoder); if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) ironlake_edp_pll_off(encoder); + ironlake_edp_panel_vdd_off(intel_dp, false); } else { - if (is_edp(intel_dp)) - ironlake_edp_panel_vdd_on(intel_dp); + ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, mode); if (!(dp_reg & DP_PORT_EN)) { intel_dp_start_link_train(intel_dp); - if (is_edp(intel_dp)) { - ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp); - } + ironlake_edp_panel_on(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, true); intel_dp_complete_link_train(intel_dp); - } - if (is_edp(intel_dp)) - ironlake_edp_backlight_on(dev); + ironlake_edp_backlight_on(intel_dp); + } else + ironlake_edp_panel_vdd_off(intel_dp, false); + ironlake_edp_backlight_on(intel_dp); } intel_dp->dpms_mode = mode; } @@ -1364,7 +1558,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP_LINK_CONFIGURATION_SIZE); DP |= DP_PORT_EN; - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) DP &= ~DP_LINK_TRAIN_MASK_CPT; else DP &= ~DP_LINK_TRAIN_MASK; @@ -1383,7 +1577,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp) DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_1_CPT; else reg = DP | DP_LINK_TRAIN_PAT_1; @@ -1458,7 +1652,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels; } - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) reg = DP | DP_LINK_TRAIN_PAT_2_CPT; else reg = DP | DP_LINK_TRAIN_PAT_2; @@ -1499,7 +1693,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp) ++tries; } - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) reg = DP | DP_LINK_TRAIN_OFF_CPT; else reg = DP | DP_LINK_TRAIN_OFF; @@ -1529,7 +1723,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) udelay(100); } - if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) { + if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) { DP &= ~DP_LINK_TRAIN_MASK_CPT; I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT); } else { @@ -1578,13 +1772,14 @@ intel_dp_link_down(struct intel_dp *intel_dp) I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); POSTING_READ(intel_dp->output_reg); + msleep(intel_dp->panel_power_down_delay); } 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)) && + sizeof(intel_dp->dpcd)) && (intel_dp->dpcd[DP_DPCD_REV] != 0)) { return true; } @@ -1592,6 +1787,27 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) return false; } +static bool +intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector) +{ + int ret; + + ret = intel_dp_aux_native_read_retry(intel_dp, + DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector, 1); + if (!ret) + return false; + + return true; +} + +static void +intel_dp_handle_test_request(struct intel_dp *intel_dp) +{ + /* NAK by default */ + intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_ACK); +} + /* * According to DP spec * 5.1.2: @@ -1604,6 +1820,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) static void intel_dp_check_link_status(struct intel_dp *intel_dp) { + u8 sink_irq_vector; + if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON) return; @@ -1622,6 +1840,20 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) return; } + /* Try to read the source of the interrupt */ + if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 && + intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) { + /* Clear interrupt source */ + intel_dp_aux_native_write_1(intel_dp, + DP_DEVICE_SERVICE_IRQ_VECTOR, + sink_irq_vector); + + if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) + intel_dp_handle_test_request(intel_dp); + if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ)) + DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); + } + 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)); @@ -1683,6 +1915,31 @@ g4x_dp_detect(struct intel_dp *intel_dp) return intel_dp_detect_dpcd(intel_dp); } +static struct edid * +intel_dp_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + struct edid *edid; + + ironlake_edp_panel_vdd_on(intel_dp); + edid = drm_get_edid(connector, adapter); + ironlake_edp_panel_vdd_off(intel_dp, false); + return edid; +} + +static int +intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *adapter) +{ + struct intel_dp *intel_dp = intel_attached_dp(connector); + int ret; + + ironlake_edp_panel_vdd_on(intel_dp); + ret = intel_ddc_get_modes(connector, adapter); + ironlake_edp_panel_vdd_off(intel_dp, false); + return ret; +} + + /** * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection. * @@ -1715,7 +1972,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_dp->force_audio) { intel_dp->has_audio = intel_dp->force_audio > 0; } else { - edid = drm_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->adapter); if (edid) { intel_dp->has_audio = drm_detect_monitor_audio(edid); connector->display_info.raw_edid = NULL; @@ -1736,28 +1993,36 @@ static int intel_dp_get_modes(struct drm_connector *connector) /* We should parse the EDID data and find out if it has an audio sink */ - ret = intel_ddc_get_modes(connector, &intel_dp->adapter); + ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter); if (ret) { - if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) { + if (is_edp(intel_dp) && !intel_dp->panel_fixed_mode) { struct drm_display_mode *newmode; list_for_each_entry(newmode, &connector->probed_modes, head) { - if (newmode->type & DRM_MODE_TYPE_PREFERRED) { - dev_priv->panel_fixed_mode = + if ((newmode->type & DRM_MODE_TYPE_PREFERRED)) { + intel_dp->panel_fixed_mode = drm_mode_duplicate(dev, newmode); break; } } } - return ret; } /* if eDP has no EDID, try to use fixed panel mode from VBT */ if (is_edp(intel_dp)) { - if (dev_priv->panel_fixed_mode != NULL) { + /* initialize panel mode from VBT if available for eDP */ + if (intel_dp->panel_fixed_mode == NULL && dev_priv->lfp_lvds_vbt_mode != NULL) { + intel_dp->panel_fixed_mode = + drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); + if (intel_dp->panel_fixed_mode) { + intel_dp->panel_fixed_mode->type |= + DRM_MODE_TYPE_PREFERRED; + } + } + if (intel_dp->panel_fixed_mode) { struct drm_display_mode *mode; - mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode); + mode = drm_mode_duplicate(dev, intel_dp->panel_fixed_mode); drm_mode_probed_add(connector, mode); return 1; } @@ -1772,7 +2037,7 @@ intel_dp_detect_audio(struct drm_connector *connector) struct edid *edid; bool has_audio = false; - edid = drm_get_edid(connector, &intel_dp->adapter); + edid = intel_dp_get_edid(connector, &intel_dp->adapter); if (edid) { has_audio = drm_detect_monitor_audio(edid); @@ -1839,7 +2104,7 @@ done: } static void -intel_dp_destroy (struct drm_connector *connector) +intel_dp_destroy(struct drm_connector *connector) { struct drm_device *dev = connector->dev; @@ -1857,6 +2122,10 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) i2c_del_adapter(&intel_dp->adapter); drm_encoder_cleanup(encoder); + if (is_edp(intel_dp)) { + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + ironlake_panel_vdd_off_sync(intel_dp); + } kfree(intel_dp); } @@ -1896,7 +2165,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder) /* Return which DP Port should be selected for Transcoder DP control */ int -intel_trans_dp_port_sel (struct drm_crtc *crtc) +intel_trans_dp_port_sel(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_mode_config *mode_config = &dev->mode_config; @@ -1993,10 +2262,13 @@ intel_dp_init(struct drm_device *dev, int output_reg) else if (output_reg == DP_D || output_reg == PCH_DP_D) intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); - if (is_edp(intel_dp)) + if (is_edp(intel_dp)) { intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT); + INIT_DELAYED_WORK(&intel_dp->panel_vdd_work, + ironlake_panel_vdd_work); + } - intel_encoder->crtc_mask = (1 << 0) | (1 << 1); + intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); connector->interlace_allowed = true; connector->doublescan_allowed = 0; @@ -2032,25 +2304,60 @@ intel_dp_init(struct drm_device *dev, int output_reg) break; } - intel_dp_i2c_init(intel_dp, intel_connector, name); - /* Cache some DPCD data in the eDP case */ if (is_edp(intel_dp)) { bool ret; - u32 pp_on, pp_div; + struct edp_power_seq cur, vbt; + u32 pp_on, pp_off, pp_div; pp_on = I915_READ(PCH_PP_ON_DELAYS); + pp_off = I915_READ(PCH_PP_OFF_DELAYS); pp_div = I915_READ(PCH_PP_DIVISOR); - /* Get T3 & T12 values (note: VESA not bspec terminology) */ - dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16; - dev_priv->panel_t3 /= 10; /* t3 in 100us units */ - dev_priv->panel_t12 = pp_div & 0xf; - dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ + /* Pull timing values out of registers */ + cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> + PANEL_POWER_UP_DELAY_SHIFT; + + cur.t8 = (pp_on & PANEL_LIGHT_ON_DELAY_MASK) >> + PANEL_LIGHT_ON_DELAY_SHIFT; + + cur.t9 = (pp_off & PANEL_LIGHT_OFF_DELAY_MASK) >> + PANEL_LIGHT_OFF_DELAY_SHIFT; + + cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> + PANEL_POWER_DOWN_DELAY_SHIFT; + + cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> + PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; + + DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); + + vbt = dev_priv->edp.pps; + + DRM_DEBUG_KMS("vbt t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", + vbt.t1_t3, vbt.t8, vbt.t9, vbt.t10, vbt.t11_t12); + +#define get_delay(field) ((max(cur.field, vbt.field) + 9) / 10) + + intel_dp->panel_power_up_delay = get_delay(t1_t3); + intel_dp->backlight_on_delay = get_delay(t8); + intel_dp->backlight_off_delay = get_delay(t9); + intel_dp->panel_power_down_delay = get_delay(t10); + intel_dp->panel_power_cycle_delay = get_delay(t11_t12); + + DRM_DEBUG_KMS("panel power up delay %d, power down delay %d, power cycle delay %d\n", + intel_dp->panel_power_up_delay, intel_dp->panel_power_down_delay, + intel_dp->panel_power_cycle_delay); + + DRM_DEBUG_KMS("backlight on delay %d, off delay %d\n", + intel_dp->backlight_on_delay, intel_dp->backlight_off_delay); + + intel_dp->panel_off_jiffies = jiffies - intel_dp->panel_power_down_delay; ironlake_edp_panel_vdd_on(intel_dp); ret = intel_dp_get_dpcd(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp); + ironlake_edp_panel_vdd_off(intel_dp, false); if (ret) { if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11) dev_priv->no_aux_handshake = @@ -2065,18 +2372,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) } } + intel_dp_i2c_init(intel_dp, intel_connector, name); + intel_encoder->hot_plug = intel_dp_hot_plug; if (is_edp(intel_dp)) { - /* initialize panel mode from VBT if available for eDP */ - if (dev_priv->lfp_lvds_vbt_mode) { - dev_priv->panel_fixed_mode = - drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); - if (dev_priv->panel_fixed_mode) { - dev_priv->panel_fixed_mode->type |= - DRM_MODE_TYPE_PREFERRED; - } - } dev_priv->int_edp_connector = connector; intel_panel_setup_backlight(dev); } |