Commit 86a3073e authored by Keith Packard's avatar Keith Packard

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

Conflicts:
	drivers/gpu/drm/i915/intel_dp.c

Just whitespace change conflicts
parents 0ac225e5 32ce697c
...@@ -349,7 +349,6 @@ typedef struct drm_i915_private { ...@@ -349,7 +349,6 @@ typedef struct drm_i915_private {
/* LVDS info */ /* LVDS info */
int backlight_level; /* restore backlight to this value */ int backlight_level; /* restore backlight to this value */
bool backlight_enabled; bool backlight_enabled;
struct drm_display_mode *panel_fixed_mode;
struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */
struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */
...@@ -674,7 +673,6 @@ typedef struct drm_i915_private { ...@@ -674,7 +673,6 @@ typedef struct drm_i915_private {
unsigned int lvds_border_bits; unsigned int lvds_border_bits;
/* Panel fitter placement and size for Ironlake+ */ /* Panel fitter placement and size for Ironlake+ */
u32 pch_pf_pos, pch_pf_size; u32 pch_pf_pos, pch_pf_size;
int panel_t3, panel_t12;
struct drm_crtc *plane_to_crtc_mapping[2]; struct drm_crtc *plane_to_crtc_mapping[2];
struct drm_crtc *pipe_to_crtc_mapping[2]; struct drm_crtc *pipe_to_crtc_mapping[2];
......
...@@ -1777,6 +1777,26 @@ static void ironlake_irq_preinstall(struct drm_device *dev) ...@@ -1777,6 +1777,26 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
POSTING_READ(SDEIER); POSTING_READ(SDEIER);
} }
/*
* Enable digital hotplug on the PCH, and configure the DP short pulse
* duration to 2ms (which is the minimum in the Display Port spec)
*
* This register is the same on all known PCH chips.
*/
static void ironlake_enable_pch_hotplug(struct drm_device *dev)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
u32 hotplug;
hotplug = I915_READ(PCH_PORT_HOTPLUG);
hotplug &= ~(PORTD_PULSE_DURATION_MASK|PORTC_PULSE_DURATION_MASK|PORTB_PULSE_DURATION_MASK);
hotplug |= PORTD_HOTPLUG_ENABLE | PORTD_PULSE_DURATION_2ms;
hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms;
hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms;
I915_WRITE(PCH_PORT_HOTPLUG, hotplug);
}
static int ironlake_irq_postinstall(struct drm_device *dev) static int ironlake_irq_postinstall(struct drm_device *dev)
{ {
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
...@@ -1839,6 +1859,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev) ...@@ -1839,6 +1859,8 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
I915_WRITE(SDEIER, hotplug_mask); I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER); POSTING_READ(SDEIER);
ironlake_enable_pch_hotplug(dev);
if (IS_IRONLAKE_M(dev)) { if (IS_IRONLAKE_M(dev)) {
/* Clear & enable PCU event interrupts */ /* Clear & enable PCU event interrupts */
I915_WRITE(DEIIR, DE_PCU_EVENT); I915_WRITE(DEIIR, DE_PCU_EVENT);
...@@ -1896,6 +1918,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev) ...@@ -1896,6 +1918,8 @@ static int ivybridge_irq_postinstall(struct drm_device *dev)
I915_WRITE(SDEIER, hotplug_mask); I915_WRITE(SDEIER, hotplug_mask);
POSTING_READ(SDEIER); POSTING_READ(SDEIER);
ironlake_enable_pch_hotplug(dev);
return 0; return 0;
} }
...@@ -2020,6 +2044,10 @@ static void ironlake_irq_uninstall(struct drm_device *dev) ...@@ -2020,6 +2044,10 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
I915_WRITE(GTIMR, 0xffffffff); I915_WRITE(GTIMR, 0xffffffff);
I915_WRITE(GTIER, 0x0); I915_WRITE(GTIER, 0x0);
I915_WRITE(GTIIR, I915_READ(GTIIR)); I915_WRITE(GTIIR, I915_READ(GTIIR));
I915_WRITE(SDEIMR, 0xffffffff);
I915_WRITE(SDEIER, 0x0);
I915_WRITE(SDEIIR, I915_READ(SDEIIR));
} }
static void i915_driver_irq_uninstall(struct drm_device * dev) static void i915_driver_irq_uninstall(struct drm_device * dev)
......
...@@ -2916,12 +2916,13 @@ ...@@ -2916,12 +2916,13 @@
#define SDEIER 0xc400c #define SDEIER 0xc400c
/* digital port hotplug */ /* digital port hotplug */
#define PCH_PORT_HOTPLUG 0xc4030 #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */
#define PORTD_HOTPLUG_ENABLE (1 << 20) #define PORTD_HOTPLUG_ENABLE (1 << 20)
#define PORTD_PULSE_DURATION_2ms (0) #define PORTD_PULSE_DURATION_2ms (0)
#define PORTD_PULSE_DURATION_4_5ms (1 << 18) #define PORTD_PULSE_DURATION_4_5ms (1 << 18)
#define PORTD_PULSE_DURATION_6ms (2 << 18) #define PORTD_PULSE_DURATION_6ms (2 << 18)
#define PORTD_PULSE_DURATION_100ms (3 << 18) #define PORTD_PULSE_DURATION_100ms (3 << 18)
#define PORTD_PULSE_DURATION_MASK (3 << 18)
#define PORTD_HOTPLUG_NO_DETECT (0) #define PORTD_HOTPLUG_NO_DETECT (0)
#define PORTD_HOTPLUG_SHORT_DETECT (1 << 16) #define PORTD_HOTPLUG_SHORT_DETECT (1 << 16)
#define PORTD_HOTPLUG_LONG_DETECT (1 << 17) #define PORTD_HOTPLUG_LONG_DETECT (1 << 17)
...@@ -2930,6 +2931,7 @@ ...@@ -2930,6 +2931,7 @@
#define PORTC_PULSE_DURATION_4_5ms (1 << 10) #define PORTC_PULSE_DURATION_4_5ms (1 << 10)
#define PORTC_PULSE_DURATION_6ms (2 << 10) #define PORTC_PULSE_DURATION_6ms (2 << 10)
#define PORTC_PULSE_DURATION_100ms (3 << 10) #define PORTC_PULSE_DURATION_100ms (3 << 10)
#define PORTC_PULSE_DURATION_MASK (3 << 10)
#define PORTC_HOTPLUG_NO_DETECT (0) #define PORTC_HOTPLUG_NO_DETECT (0)
#define PORTC_HOTPLUG_SHORT_DETECT (1 << 8) #define PORTC_HOTPLUG_SHORT_DETECT (1 << 8)
#define PORTC_HOTPLUG_LONG_DETECT (1 << 9) #define PORTC_HOTPLUG_LONG_DETECT (1 << 9)
...@@ -2938,6 +2940,7 @@ ...@@ -2938,6 +2940,7 @@
#define PORTB_PULSE_DURATION_4_5ms (1 << 2) #define PORTB_PULSE_DURATION_4_5ms (1 << 2)
#define PORTB_PULSE_DURATION_6ms (2 << 2) #define PORTB_PULSE_DURATION_6ms (2 << 2)
#define PORTB_PULSE_DURATION_100ms (3 << 2) #define PORTB_PULSE_DURATION_100ms (3 << 2)
#define PORTB_PULSE_DURATION_MASK (3 << 2)
#define PORTB_HOTPLUG_NO_DETECT (0) #define PORTB_HOTPLUG_NO_DETECT (0)
#define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) #define PORTB_HOTPLUG_SHORT_DETECT (1 << 0)
#define PORTB_HOTPLUG_LONG_DETECT (1 << 1) #define PORTB_HOTPLUG_LONG_DETECT (1 << 1)
...@@ -3321,15 +3324,35 @@ ...@@ -3321,15 +3324,35 @@
#define PCH_PP_STATUS 0xc7200 #define PCH_PP_STATUS 0xc7200
#define PCH_PP_CONTROL 0xc7204 #define PCH_PP_CONTROL 0xc7204
#define PANEL_UNLOCK_REGS (0xabcd << 16) #define PANEL_UNLOCK_REGS (0xabcd << 16)
#define PANEL_UNLOCK_MASK (0xffff << 16)
#define EDP_FORCE_VDD (1 << 3) #define EDP_FORCE_VDD (1 << 3)
#define EDP_BLC_ENABLE (1 << 2) #define EDP_BLC_ENABLE (1 << 2)
#define PANEL_POWER_RESET (1 << 1) #define PANEL_POWER_RESET (1 << 1)
#define PANEL_POWER_OFF (0 << 0) #define PANEL_POWER_OFF (0 << 0)
#define PANEL_POWER_ON (1 << 0) #define PANEL_POWER_ON (1 << 0)
#define PCH_PP_ON_DELAYS 0xc7208 #define PCH_PP_ON_DELAYS 0xc7208
#define PANEL_PORT_SELECT_MASK (3 << 30)
#define PANEL_PORT_SELECT_LVDS (0 << 30)
#define PANEL_PORT_SELECT_DPA (1 << 30)
#define EDP_PANEL (1 << 30) #define EDP_PANEL (1 << 30)
#define PANEL_PORT_SELECT_DPC (2 << 30)
#define PANEL_PORT_SELECT_DPD (3 << 30)
#define PANEL_POWER_UP_DELAY_MASK (0x1fff0000)
#define PANEL_POWER_UP_DELAY_SHIFT 16
#define PANEL_LIGHT_ON_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_ON_DELAY_SHIFT 0
#define PCH_PP_OFF_DELAYS 0xc720c #define PCH_PP_OFF_DELAYS 0xc720c
#define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000)
#define PANEL_POWER_DOWN_DELAY_SHIFT 16
#define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff)
#define PANEL_LIGHT_OFF_DELAY_SHIFT 0
#define PCH_PP_DIVISOR 0xc7210 #define PCH_PP_DIVISOR 0xc7210
#define PP_REFERENCE_DIVIDER_MASK (0xffffff00)
#define PP_REFERENCE_DIVIDER_SHIFT 8
#define PANEL_POWER_CYCLE_DELAY_MASK (0x1f)
#define PANEL_POWER_CYCLE_DELAY_SHIFT 0
#define PCH_DP_B 0xe4100 #define PCH_DP_B 0xe4100
#define PCH_DPB_AUX_CH_CTL 0xe4110 #define PCH_DPB_AUX_CH_CTL 0xe4110
......
/* /*
* Copyright 2006 Intel Corporation * Copyright © 2006 Intel Corporation
* *
* Permission is hereby granted, free of charge, to any person obtaining a * Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"), * copy of this software and associated documentation files (the "Software"),
...@@ -446,11 +446,11 @@ struct bdb_driver_features { ...@@ -446,11 +446,11 @@ struct bdb_driver_features {
#define EDP_VSWING_1_2V 3 #define EDP_VSWING_1_2V 3
struct edp_power_seq { struct edp_power_seq {
u16 t3; u16 t1_t3;
u16 t7; u16 t8;
u16 t9; u16 t9;
u16 t10; u16 t10;
u16 t12; u16 t11_t12;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct edp_link_params { struct edp_link_params {
......
...@@ -59,6 +59,15 @@ struct intel_dp { ...@@ -59,6 +59,15 @@ struct intel_dp {
bool is_pch_edp; bool is_pch_edp;
uint8_t train_set[4]; uint8_t train_set[4];
uint8_t link_status[DP_LINK_STATUS_SIZE]; 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;
}; };
/** /**
...@@ -200,16 +209,14 @@ intel_dp_mode_valid(struct drm_connector *connector, ...@@ -200,16 +209,14 @@ intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct intel_dp *intel_dp = intel_attached_dp(connector); 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_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
int max_lanes = intel_dp_max_lane_count(intel_dp); int max_lanes = intel_dp_max_lane_count(intel_dp);
if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) { if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay) if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
return MODE_PANEL; return MODE_PANEL;
if (mode->vdisplay > dev_priv->panel_fixed_mode->vdisplay) if (mode->vdisplay > intel_dp->panel_fixed_mode->vdisplay)
return MODE_PANEL; return MODE_PANEL;
} }
...@@ -279,6 +286,38 @@ intel_hrawclk(struct drm_device *dev) ...@@ -279,6 +286,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 static int
intel_dp_aux_ch(struct intel_dp *intel_dp, intel_dp_aux_ch(struct intel_dp *intel_dp,
uint8_t *send, int send_bytes, uint8_t *send, int send_bytes,
...@@ -295,6 +334,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, ...@@ -295,6 +334,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
uint32_t aux_clock_divider; uint32_t aux_clock_divider;
int try, precharge; int try, precharge;
intel_dp_check_edp(intel_dp);
/* The clock divider is based off the hrawclk, /* The clock divider is based off the hrawclk,
* and would like to run at 2MHz. So, take the * and would like to run at 2MHz. So, take the
* hrawclk value and divide by 2 and use that * hrawclk value and divide by 2 and use that
...@@ -408,6 +448,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp, ...@@ -408,6 +448,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
int msg_bytes; int msg_bytes;
uint8_t ack; uint8_t ack;
intel_dp_check_edp(intel_dp);
if (send_bytes > 16) if (send_bytes > 16)
return -1; return -1;
msg[0] = AUX_NATIVE_WRITE << 4; msg[0] = AUX_NATIVE_WRITE << 4;
...@@ -450,6 +491,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, ...@@ -450,6 +491,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
uint8_t ack; uint8_t ack;
int ret; int ret;
intel_dp_check_edp(intel_dp);
msg[0] = AUX_NATIVE_READ << 4; msg[0] = AUX_NATIVE_READ << 4;
msg[1] = address >> 8; msg[1] = address >> 8;
msg[2] = address & 0xff; msg[2] = address & 0xff;
...@@ -493,6 +535,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, ...@@ -493,6 +535,7 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
int reply_bytes; int reply_bytes;
int ret; int ret;
intel_dp_check_edp(intel_dp);
/* Set up the command byte */ /* Set up the command byte */
if (mode & MODE_I2C_READ) if (mode & MODE_I2C_READ)
msg[0] = AUX_I2C_READ << 4; msg[0] = AUX_I2C_READ << 4;
...@@ -573,10 +616,15 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, ...@@ -573,10 +616,15 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
return -EREMOTEIO; 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 static int
intel_dp_i2c_init(struct intel_dp *intel_dp, intel_dp_i2c_init(struct intel_dp *intel_dp,
struct intel_connector *intel_connector, const char *name) struct intel_connector *intel_connector, const char *name)
{ {
int ret;
DRM_DEBUG_KMS("i2c_init %s\n", name); DRM_DEBUG_KMS("i2c_init %s\n", name);
intel_dp->algo.running = false; intel_dp->algo.running = false;
intel_dp->algo.address = 0; intel_dp->algo.address = 0;
...@@ -590,7 +638,10 @@ intel_dp_i2c_init(struct intel_dp *intel_dp, ...@@ -590,7 +638,10 @@ intel_dp_i2c_init(struct intel_dp *intel_dp,
intel_dp->adapter.algo_data = &intel_dp->algo; intel_dp->adapter.algo_data = &intel_dp->algo;
intel_dp->adapter.dev.parent = &intel_connector->base.kdev; 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 static bool
...@@ -598,22 +649,21 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -598,22 +649,21 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
{ {
struct drm_device *dev = encoder->dev; 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); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
int lane_count, clock; int lane_count, clock;
int max_lane_count = intel_dp_max_lane_count(intel_dp); 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; 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 }; static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) { if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode); intel_fixed_panel_mode(intel_dp->panel_fixed_mode, adjusted_mode);
intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN, intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
mode, adjusted_mode); mode, adjusted_mode);
/* /*
* the mode->clock is used to calculate the Data&Link M/N * the mode->clock is used to calculate the Data&Link M/N
* of the pipe. For the eDP the fixed clock should be used. * 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 (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
...@@ -740,6 +790,9 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode, ...@@ -740,6 +790,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 static void
intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode)
...@@ -749,6 +802,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -749,6 +802,14 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
struct drm_crtc *crtc = intel_dp->base.base.crtc; struct drm_crtc *crtc = intel_dp->base.base.crtc;
struct intel_crtc *intel_crtc = to_intel_crtc(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 = DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
intel_dp->DP |= intel_dp->color_range; intel_dp->DP |= intel_dp->color_range;
...@@ -808,58 +869,150 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ...@@ -808,58 +869,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) static void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
{ {
struct drm_device *dev = intel_dp->base.base.dev; struct drm_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp; u32 pp;
/* if (!is_edp(intel_dp))
* If the panel wasn't on, make sure there's not a currently return;
* active PP sequence before enabling AUX VDD. DRM_DEBUG_KMS("Turn eDP VDD on\n");
*/
if (!(I915_READ(PCH_PP_STATUS) & PP_ON))
msleep(dev_priv->panel_t3);
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 = I915_READ(PCH_PP_CONTROL);
pp &= ~PANEL_UNLOCK_MASK;
pp |= PANEL_UNLOCK_REGS;
pp |= EDP_FORCE_VDD; pp |= EDP_FORCE_VDD;
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL); 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_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp; u32 pp;
pp = I915_READ(PCH_PP_CONTROL); if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
pp &= ~EDP_FORCE_VDD; pp = I915_READ(PCH_PP_CONTROL);
I915_WRITE(PCH_PP_CONTROL, pp); pp &= ~PANEL_UNLOCK_MASK;
POSTING_READ(PCH_PP_CONTROL); 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;
}
}
/* Make sure sequencer is idle before allowing subsequent activity */ static void ironlake_panel_vdd_work(struct work_struct *__work)
msleep(dev_priv->panel_t12); {
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;
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 */ /* 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_device *dev = intel_dp->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE; u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
if (I915_READ(PCH_PP_STATUS) & PP_ON) if (!is_edp(intel_dp))
return true; return;
if (ironlake_edp_have_panel_power(intel_dp))
return;
ironlake_wait_panel_off(intel_dp);
pp = I915_READ(PCH_PP_CONTROL); 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 |= POWER_TARGET_ON;
pp &= ~PANEL_POWER_RESET;
I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL); POSTING_READ(PCH_PP_CONTROL);
...@@ -868,44 +1021,64 @@ static bool ironlake_edp_panel_on(struct intel_dp *intel_dp) ...@@ -868,44 +1021,64 @@ static bool ironlake_edp_panel_on(struct intel_dp *intel_dp)
DRM_ERROR("panel on wait timed out: 0x%08x\n", DRM_ERROR("panel on wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS)); I915_READ(PCH_PP_STATUS));
pp |= PANEL_POWER_RESET; /* restore panel reset bit */ if (IS_GEN5(dev)) {
I915_WRITE(PCH_PP_CONTROL, pp); pp |= PANEL_POWER_RESET; /* restore panel reset bit */
POSTING_READ(PCH_PP_CONTROL); I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
return false; }
} }
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; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK | u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK; PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
if (!is_edp(intel_dp))
return;
pp = I915_READ(PCH_PP_CONTROL); 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 */ intel_dp->panel_off_jiffies = jiffies;
pp &= ~PANEL_POWER_RESET;
I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL);
pp &= ~POWER_TARGET_ON; if (IS_GEN5(dev)) {
I915_WRITE(PCH_PP_CONTROL, pp); pp &= ~POWER_TARGET_ON;
POSTING_READ(PCH_PP_CONTROL); 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)) if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
DRM_ERROR("panel off wait timed out: 0x%08x\n", DRM_ERROR("panel off wait timed out: 0x%08x\n",
I915_READ(PCH_PP_STATUS)); I915_READ(PCH_PP_STATUS));
pp |= PANEL_POWER_RESET; /* restore panel reset bit */ pp |= PANEL_POWER_RESET; /* restore panel reset bit */
I915_WRITE(PCH_PP_CONTROL, pp); I915_WRITE(PCH_PP_CONTROL, pp);
POSTING_READ(PCH_PP_CONTROL); 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; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp; u32 pp;
if (!is_edp(intel_dp))
return;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
/* /*
* If we enable the backlight right away following a panel power * If we enable the backlight right away following a panel power
...@@ -913,21 +1086,32 @@ static void ironlake_edp_backlight_on(struct drm_device *dev) ...@@ -913,21 +1086,32 @@ static void ironlake_edp_backlight_on(struct drm_device *dev)
* link. So delay a bit to make sure the image is solid before * link. So delay a bit to make sure the image is solid before
* allowing it to appear. * allowing it to appear.
*/ */
msleep(300); msleep(intel_dp->backlight_on_delay);
pp = I915_READ(PCH_PP_CONTROL); pp = I915_READ(PCH_PP_CONTROL);
pp &= ~PANEL_UNLOCK_MASK;
pp |= PANEL_UNLOCK_REGS;
pp |= EDP_BLC_ENABLE; pp |= EDP_BLC_ENABLE;
I915_WRITE(PCH_PP_CONTROL, pp); 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; struct drm_i915_private *dev_priv = dev->dev_private;
u32 pp; u32 pp;
if (!is_edp(intel_dp))
return;
DRM_DEBUG_KMS("\n"); DRM_DEBUG_KMS("\n");
pp = I915_READ(PCH_PP_CONTROL); pp = I915_READ(PCH_PP_CONTROL);
pp &= ~PANEL_UNLOCK_MASK;
pp |= PANEL_UNLOCK_REGS;
pp &= ~EDP_BLC_ENABLE; pp &= ~EDP_BLC_ENABLE;
I915_WRITE(PCH_PP_CONTROL, pp); 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) static void ironlake_edp_pll_on(struct drm_encoder *encoder)
...@@ -990,41 +1174,32 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode) ...@@ -990,41 +1174,32 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
static void intel_dp_prepare(struct drm_encoder *encoder) static void intel_dp_prepare(struct drm_encoder *encoder)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
/* Wake up the sink first */ /* Wake up the sink first */
ironlake_edp_panel_vdd_on(intel_dp);
intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
ironlake_edp_panel_vdd_off(intel_dp, false);
if (is_edp(intel_dp)) { /* Make sure the panel is off before trying to
ironlake_edp_backlight_off(dev); * change the mode
ironlake_edp_panel_off(dev); */
if (!is_pch_edp(intel_dp)) ironlake_edp_backlight_off(intel_dp);
ironlake_edp_pll_on(encoder);
else
ironlake_edp_pll_off(encoder);
}
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
ironlake_edp_panel_off(encoder);
} }
static void intel_dp_commit(struct drm_encoder *encoder) static void intel_dp_commit(struct drm_encoder *encoder)
{ {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
struct drm_device *dev = encoder->dev;
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); intel_dp_start_link_train(intel_dp);
ironlake_edp_panel_on(intel_dp);
if (is_edp(intel_dp)) { ironlake_edp_panel_vdd_off(intel_dp, true);
ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_vdd_off(intel_dp);
}
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
ironlake_edp_backlight_on(intel_dp);
if (is_edp(intel_dp))
ironlake_edp_backlight_on(dev);
intel_dp->dpms_mode = DRM_MODE_DPMS_ON; intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
} }
...@@ -1038,28 +1213,27 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode) ...@@ -1038,28 +1213,27 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
uint32_t dp_reg = I915_READ(intel_dp->output_reg); uint32_t dp_reg = I915_READ(intel_dp->output_reg);
if (mode != DRM_MODE_DPMS_ON) { if (mode != DRM_MODE_DPMS_ON) {
ironlake_edp_panel_vdd_on(intel_dp);
if (is_edp(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_sink_dpms(intel_dp, mode);
intel_dp_link_down(intel_dp); intel_dp_link_down(intel_dp);
if (is_edp(intel_dp)) ironlake_edp_panel_off(encoder);
ironlake_edp_panel_off(dev);
if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
ironlake_edp_pll_off(encoder); ironlake_edp_pll_off(encoder);
ironlake_edp_panel_vdd_off(intel_dp, false);
} else { } 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); intel_dp_sink_dpms(intel_dp, mode);
if (!(dp_reg & DP_PORT_EN)) { if (!(dp_reg & DP_PORT_EN)) {
intel_dp_start_link_train(intel_dp); intel_dp_start_link_train(intel_dp);
if (is_edp(intel_dp)) { ironlake_edp_panel_on(intel_dp);
ironlake_edp_panel_on(intel_dp); ironlake_edp_panel_vdd_off(intel_dp, true);
ironlake_edp_panel_vdd_off(intel_dp);
}
intel_dp_complete_link_train(intel_dp); intel_dp_complete_link_train(intel_dp);
} ironlake_edp_backlight_on(intel_dp);
if (is_edp(intel_dp)) } else
ironlake_edp_backlight_on(dev); ironlake_edp_panel_vdd_off(intel_dp, false);
ironlake_edp_backlight_on(intel_dp);
} }
intel_dp->dpms_mode = mode; intel_dp->dpms_mode = mode;
} }
...@@ -1582,6 +1756,7 @@ intel_dp_link_down(struct intel_dp *intel_dp) ...@@ -1582,6 +1756,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN); I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
POSTING_READ(intel_dp->output_reg); POSTING_READ(intel_dp->output_reg);
msleep(intel_dp->panel_power_down_delay);
} }
static bool static bool
...@@ -1687,6 +1862,31 @@ g4x_dp_detect(struct intel_dp *intel_dp) ...@@ -1687,6 +1862,31 @@ g4x_dp_detect(struct intel_dp *intel_dp)
return intel_dp_detect_dpcd(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. * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
* *
...@@ -1719,7 +1919,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) ...@@ -1719,7 +1919,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
if (intel_dp->force_audio) { if (intel_dp->force_audio) {
intel_dp->has_audio = intel_dp->force_audio > 0; intel_dp->has_audio = intel_dp->force_audio > 0;
} else { } else {
edid = drm_get_edid(connector, &intel_dp->adapter); edid = intel_dp_get_edid(connector, &intel_dp->adapter);
if (edid) { if (edid) {
intel_dp->has_audio = drm_detect_monitor_audio(edid); intel_dp->has_audio = drm_detect_monitor_audio(edid);
connector->display_info.raw_edid = NULL; connector->display_info.raw_edid = NULL;
...@@ -1740,28 +1940,36 @@ static int intel_dp_get_modes(struct drm_connector *connector) ...@@ -1740,28 +1940,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 /* 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 (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; struct drm_display_mode *newmode;
list_for_each_entry(newmode, &connector->probed_modes, list_for_each_entry(newmode, &connector->probed_modes,
head) { head) {
if (newmode->type & DRM_MODE_TYPE_PREFERRED) { if ((newmode->type & DRM_MODE_TYPE_PREFERRED)) {
dev_priv->panel_fixed_mode = intel_dp->panel_fixed_mode =
drm_mode_duplicate(dev, newmode); drm_mode_duplicate(dev, newmode);
break; break;
} }
} }
} }
return ret; return ret;
} }
/* if eDP has no EDID, try to use fixed panel mode from VBT */ /* if eDP has no EDID, try to use fixed panel mode from VBT */
if (is_edp(intel_dp)) { 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; 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); drm_mode_probed_add(connector, mode);
return 1; return 1;
} }
...@@ -1776,7 +1984,7 @@ intel_dp_detect_audio(struct drm_connector *connector) ...@@ -1776,7 +1984,7 @@ intel_dp_detect_audio(struct drm_connector *connector)
struct edid *edid; struct edid *edid;
bool has_audio = false; bool has_audio = false;
edid = drm_get_edid(connector, &intel_dp->adapter); edid = intel_dp_get_edid(connector, &intel_dp->adapter);
if (edid) { if (edid) {
has_audio = drm_detect_monitor_audio(edid); has_audio = drm_detect_monitor_audio(edid);
...@@ -1861,6 +2069,10 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder) ...@@ -1861,6 +2069,10 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
i2c_del_adapter(&intel_dp->adapter); i2c_del_adapter(&intel_dp->adapter);
drm_encoder_cleanup(encoder); 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); kfree(intel_dp);
} }
...@@ -1997,8 +2209,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -1997,8 +2209,11 @@ intel_dp_init(struct drm_device *dev, int output_reg)
else if (output_reg == DP_D || output_reg == PCH_DP_D) else if (output_reg == DP_D || output_reg == PCH_DP_D)
intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT); 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); 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);
connector->interlace_allowed = true; connector->interlace_allowed = true;
...@@ -2036,25 +2251,60 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -2036,25 +2251,60 @@ intel_dp_init(struct drm_device *dev, int output_reg)
break; break;
} }
intel_dp_i2c_init(intel_dp, intel_connector, name);
/* 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)) {
bool ret; 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_on = I915_READ(PCH_PP_ON_DELAYS);
pp_off = I915_READ(PCH_PP_OFF_DELAYS);
pp_div = I915_READ(PCH_PP_DIVISOR); pp_div = I915_READ(PCH_PP_DIVISOR);
/* Get T3 & T12 values (note: VESA not bspec terminology) */ /* Pull timing values out of registers */
dev_priv->panel_t3 = (pp_on & 0x1fff0000) >> 16; cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >>
dev_priv->panel_t3 /= 10; /* t3 in 100us units */ PANEL_POWER_UP_DELAY_SHIFT;
dev_priv->panel_t12 = pp_div & 0xf;
dev_priv->panel_t12 *= 100; /* t12 in 100ms units */ 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); ironlake_edp_panel_vdd_on(intel_dp);
ret = intel_dp_get_dpcd(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 (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 =
...@@ -2069,18 +2319,11 @@ intel_dp_init(struct drm_device *dev, int output_reg) ...@@ -2069,18 +2319,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; intel_encoder->hot_plug = intel_dp_hot_plug;
if (is_edp(intel_dp)) { 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; dev_priv->int_edp_connector = connector;
intel_panel_setup_backlight(dev); intel_panel_setup_backlight(dev);
} }
......
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