diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_debugfs.c | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_reg.h | 17 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/i915_suspend.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_display.c | 187 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_drv.h | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_lvds.c | 82 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_opregion.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_panel.c | 72 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 4 | 
12 files changed, 272 insertions, 116 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a8ab6263e0d..3c395a59da3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -499,7 +499,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)  	seq_printf(m, "Interrupts received: %d\n",  		   atomic_read(&dev_priv->irq_received));  	for (i = 0; i < I915_NUM_RINGS; i++) { -		if (IS_GEN6(dev)) { +		if (IS_GEN6(dev) || IS_GEN7(dev)) {  			seq_printf(m, "Graphics Interrupt mask (%s):	%08x\n",  				   dev_priv->ring[i].name,  				   I915_READ_IMR(&dev_priv->ring[i])); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index feb4f164fd1..7916bd97d5c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -36,6 +36,7 @@  #include <linux/io-mapping.h>  #include <linux/i2c.h>  #include <drm/intel-gtt.h> +#include <linux/backlight.h>  /* General customization:   */ @@ -690,6 +691,7 @@ typedef struct drm_i915_private {  	int child_dev_num;  	struct child_device_config *child_dev;  	struct drm_connector *int_lvds_connector; +	struct drm_connector *int_edp_connector;  	bool mchbar_need_disable; @@ -723,6 +725,8 @@ typedef struct drm_i915_private {  	/* list of fbdev register on this device */  	struct intel_fbdev *fbdev; +	struct backlight_device *backlight; +  	struct drm_property *broadcast_rgb_property;  	struct drm_property *force_audio_property; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 02f96fd0d52..9cbb0cd8f46 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2058,8 +2058,10 @@ void intel_irq_init(struct drm_device *dev)  		dev->driver->get_vblank_counter = gm45_get_vblank_counter;  	} - -	dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		dev->driver->get_vblank_timestamp = i915_get_vblank_timestamp; +	else +		dev->driver->get_vblank_timestamp = NULL;  	dev->driver->get_scanout_position = i915_get_crtc_scanoutpos;  	if (IS_IVYBRIDGE(dev)) { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index d1331f771e2..542453f7498 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -375,6 +375,7 @@  # define MI_FLUSH_ENABLE				(1 << 11)  #define GFX_MODE	0x02520 +#define GFX_MODE_GEN7	0x0229c  #define   GFX_RUN_LIST_ENABLE		(1<<15)  #define   GFX_TLB_INVALIDATE_ALWAYS	(1<<13)  #define   GFX_SURFACE_FAULT_ENABLE	(1<<12) @@ -382,6 +383,9 @@  #define   GFX_PSMI_GRANULARITY		(1<<10)  #define   GFX_PPGTT_ENABLE		(1<<9) +#define GFX_MODE_ENABLE(bit) (((bit) << 16) | (bit)) +#define GFX_MODE_DISABLE(bit) (((bit) << 16) | (0)) +  #define SCPD0		0x0209c /* 915+ only */  #define IER		0x020a0  #define IIR		0x020a4 @@ -1318,6 +1322,7 @@  #define   ADPA_PIPE_SELECT_MASK	(1<<30)  #define   ADPA_PIPE_A_SELECT	0  #define   ADPA_PIPE_B_SELECT	(1<<30) +#define   ADPA_PIPE_SELECT(pipe) ((pipe) << 30)  #define   ADPA_USE_VGA_HVPOLARITY (1<<15)  #define   ADPA_SETS_HVPOLARITY	0  #define   ADPA_VSYNC_CNTL_DISABLE (1<<11) @@ -1460,6 +1465,7 @@  /* Selects pipe B for LVDS data.  Must be set on pre-965. */  #define   LVDS_PIPEB_SELECT		(1 << 30)  #define   LVDS_PIPE_MASK		(1 << 30) +#define   LVDS_PIPE(pipe)		((pipe) << 30)  /* LVDS dithering flag on 965/g4x platform */  #define   LVDS_ENABLE_DITHER		(1 << 25)  /* LVDS sync polarity flags. Set to invert (i.e. negative) */ @@ -1499,9 +1505,6 @@  #define   LVDS_B0B3_POWER_DOWN		(0 << 2)  #define   LVDS_B0B3_POWER_UP		(3 << 2) -#define LVDS_PIPE_ENABLED(V, P) \ -	(((V) & (LVDS_PIPE_MASK | LVDS_PORT_EN)) == ((P) << 30 | LVDS_PORT_EN)) -  /* Video Data Island Packet control */  #define VIDEO_DIP_DATA		0x61178  #define VIDEO_DIP_CTL		0x61170 @@ -3256,14 +3259,12 @@  #define  ADPA_CRT_HOTPLUG_VOLREF_475MV  (1<<17)  #define  ADPA_CRT_HOTPLUG_FORCE_TRIGGER (1<<16) -#define ADPA_PIPE_ENABLED(V, P) \ -	(((V) & (ADPA_TRANS_SELECT_MASK | ADPA_DAC_ENABLE)) == ((P) << 30 | ADPA_DAC_ENABLE)) -  /* or SDVOB */  #define HDMIB   0xe1140  #define  PORT_ENABLE    (1 << 31)  #define  TRANSCODER_A   (0)  #define  TRANSCODER_B   (1 << 30) +#define  TRANSCODER(pipe)	((pipe) << 30)  #define  TRANSCODER_MASK   (1 << 30)  #define  COLOR_FORMAT_8bpc      (0)  #define  COLOR_FORMAT_12bpc     (3 << 26) @@ -3280,9 +3281,6 @@  #define  HSYNC_ACTIVE_HIGH      (1 << 3)  #define  PORT_DETECTED          (1 << 2) -#define HDMI_PIPE_ENABLED(V, P) \ -	(((V) & (TRANSCODER_MASK | PORT_ENABLE)) == ((P) << 30 | PORT_ENABLE)) -  /* PCH SDVOB multiplex with HDMIB */  #define PCH_SDVOB	HDMIB @@ -3349,6 +3347,7 @@  #define  PORT_TRANS_B_SEL_CPT	(1<<29)  #define  PORT_TRANS_C_SEL_CPT	(2<<29)  #define  PORT_TRANS_SEL_MASK	(3<<29) +#define  PORT_TRANS_SEL_CPT(pipe)	((pipe) << 29)  #define TRANS_DP_CTL_A		0xe0300  #define TRANS_DP_CTL_B		0xe1300 diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index 87677d60d0d..f10742359ec 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -871,7 +871,8 @@ int i915_restore_state(struct drm_device *dev)  	}  	mutex_unlock(&dev->struct_mutex); -	intel_init_clock_gating(dev); +	if (drm_core_check_feature(dev, DRIVER_MODESET)) +		intel_init_clock_gating(dev);  	if (IS_IRONLAKE_M(dev)) {  		ironlake_enable_drps(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 35364e68a09..ee1d701317f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -980,8 +980,8 @@ static void assert_transcoder_disabled(struct drm_i915_private *dev_priv,  	     pipe_name(pipe));  } -static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe, -			    int reg, u32 port_sel, u32 val) +static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, +			    enum pipe pipe, u32 port_sel, u32 val)  {  	if ((val & DP_PORT_EN) == 0)  		return false; @@ -998,11 +998,58 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, enum pipe pipe,  	return true;  } +static bool hdmi_pipe_enabled(struct drm_i915_private *dev_priv, +			      enum pipe pipe, u32 val) +{ +	if ((val & PORT_ENABLE) == 0) +		return false; + +	if (HAS_PCH_CPT(dev_priv->dev)) { +		if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) +			return false; +	} else { +		if ((val & TRANSCODER_MASK) != TRANSCODER(pipe)) +			return false; +	} +	return true; +} + +static bool lvds_pipe_enabled(struct drm_i915_private *dev_priv, +			      enum pipe pipe, u32 val) +{ +	if ((val & LVDS_PORT_EN) == 0) +		return false; + +	if (HAS_PCH_CPT(dev_priv->dev)) { +		if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) +			return false; +	} else { +		if ((val & LVDS_PIPE_MASK) != LVDS_PIPE(pipe)) +			return false; +	} +	return true; +} + +static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv, +			      enum pipe pipe, u32 val) +{ +	if ((val & ADPA_DAC_ENABLE) == 0) +		return false; +	if (HAS_PCH_CPT(dev_priv->dev)) { +		if ((val & PORT_TRANS_SEL_MASK) != PORT_TRANS_SEL_CPT(pipe)) +			return false; +	} else { +		if ((val & ADPA_PIPE_SELECT_MASK) != ADPA_PIPE_SELECT(pipe)) +			return false; +	} +	return true; +} +  static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,  				   enum pipe pipe, int reg, u32 port_sel)  {  	u32 val = I915_READ(reg); -	WARN(dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val), +	WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),  	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",  	     reg, pipe_name(pipe));  } @@ -1011,7 +1058,7 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,  				     enum pipe pipe, int reg)  {  	u32 val = I915_READ(reg); -	WARN(HDMI_PIPE_ENABLED(val, pipe), +	WARN(hdmi_pipe_enabled(dev_priv, val, pipe),  	     "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",  	     reg, pipe_name(pipe));  } @@ -1028,13 +1075,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,  	reg = PCH_ADPA;  	val = I915_READ(reg); -	WARN(ADPA_PIPE_ENABLED(val, pipe), +	WARN(adpa_pipe_enabled(dev_priv, val, pipe),  	     "PCH VGA enabled on transcoder %c, should be disabled\n",  	     pipe_name(pipe));  	reg = PCH_LVDS;  	val = I915_READ(reg); -	WARN(LVDS_PIPE_ENABLED(val, pipe), +	WARN(lvds_pipe_enabled(dev_priv, val, pipe),  	     "PCH LVDS enabled on transcoder %c, should be disabled\n",  	     pipe_name(pipe)); @@ -1360,7 +1407,7 @@ static void disable_pch_dp(struct drm_i915_private *dev_priv,  			   enum pipe pipe, int reg, u32 port_sel)  {  	u32 val = I915_READ(reg); -	if (dp_pipe_enabled(dev_priv, pipe, reg, port_sel, val)) { +	if (dp_pipe_enabled(dev_priv, pipe, port_sel, val)) {  		DRM_DEBUG_KMS("Disabling pch dp %x on pipe %d\n", reg, pipe);  		I915_WRITE(reg, val & ~DP_PORT_EN);  	} @@ -1370,7 +1417,7 @@ static void disable_pch_hdmi(struct drm_i915_private *dev_priv,  			     enum pipe pipe, int reg)  {  	u32 val = I915_READ(reg); -	if (HDMI_PIPE_ENABLED(val, pipe)) { +	if (hdmi_pipe_enabled(dev_priv, val, pipe)) {  		DRM_DEBUG_KMS("Disabling pch HDMI %x on pipe %d\n",  			      reg, pipe);  		I915_WRITE(reg, val & ~PORT_ENABLE); @@ -1392,12 +1439,13 @@ static void intel_disable_pch_ports(struct drm_i915_private *dev_priv,  	reg = PCH_ADPA;  	val = I915_READ(reg); -	if (ADPA_PIPE_ENABLED(val, pipe)) +	if (adpa_pipe_enabled(dev_priv, val, pipe))  		I915_WRITE(reg, val & ~ADPA_DAC_ENABLE);  	reg = PCH_LVDS;  	val = I915_READ(reg); -	if (LVDS_PIPE_ENABLED(val, pipe)) { +	if (lvds_pipe_enabled(dev_priv, val, pipe)) { +		DRM_DEBUG_KMS("disable lvds on pipe %d val 0x%08x\n", pipe, val);  		I915_WRITE(reg, val & ~LVDS_PORT_EN);  		POSTING_READ(reg);  		udelay(100); @@ -5049,6 +5097,81 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,  	return ret;  } +static void ironlake_update_pch_refclk(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct drm_mode_config *mode_config = &dev->mode_config; +	struct drm_crtc *crtc; +	struct intel_encoder *encoder; +	struct intel_encoder *has_edp_encoder = NULL; +	u32 temp; +	bool has_lvds = false; + +	/* We need to take the global config into account */ +	list_for_each_entry(crtc, &mode_config->crtc_list, head) { +		if (!crtc->enabled) +			continue; + +		list_for_each_entry(encoder, &mode_config->encoder_list, +				    base.head) { +			if (encoder->base.crtc != crtc) +				continue; + +			switch (encoder->type) { +			case INTEL_OUTPUT_LVDS: +				has_lvds = true; +			case INTEL_OUTPUT_EDP: +				has_edp_encoder = encoder; +				break; +			} +		} +	} + +	/* Ironlake: try to setup display ref clock before DPLL +	 * enabling. This is only under driver's control after +	 * PCH B stepping, previous chipset stepping should be +	 * ignoring this setting. +	 */ +	temp = I915_READ(PCH_DREF_CONTROL); +	/* Always enable nonspread source */ +	temp &= ~DREF_NONSPREAD_SOURCE_MASK; +	temp |= DREF_NONSPREAD_SOURCE_ENABLE; +	temp &= ~DREF_SSC_SOURCE_MASK; +	temp |= DREF_SSC_SOURCE_ENABLE; +	I915_WRITE(PCH_DREF_CONTROL, temp); + +	POSTING_READ(PCH_DREF_CONTROL); +	udelay(200); + +	if (has_edp_encoder) { +		if (intel_panel_use_ssc(dev_priv)) { +			temp |= DREF_SSC1_ENABLE; +			I915_WRITE(PCH_DREF_CONTROL, temp); + +			POSTING_READ(PCH_DREF_CONTROL); +			udelay(200); +		} +		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; + +		/* Enable CPU source on CPU attached eDP */ +		if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { +			if (intel_panel_use_ssc(dev_priv)) +				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; +			else +				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; +		} else { +			/* Enable SSC on PCH eDP if needed */ +			if (intel_panel_use_ssc(dev_priv)) { +				DRM_ERROR("enabling SSC on PCH\n"); +				temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; +			} +		} +		I915_WRITE(PCH_DREF_CONTROL, temp); +		POSTING_READ(PCH_DREF_CONTROL); +		udelay(200); +	} +} +  static int ironlake_crtc_mode_set(struct drm_crtc *crtc,  				  struct drm_display_mode *mode,  				  struct drm_display_mode *adjusted_mode, @@ -5244,49 +5367,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,  	ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,  			     &m_n); -	/* Ironlake: try to setup display ref clock before DPLL -	 * enabling. This is only under driver's control after -	 * PCH B stepping, previous chipset stepping should be -	 * ignoring this setting. -	 */ -	temp = I915_READ(PCH_DREF_CONTROL); -	/* Always enable nonspread source */ -	temp &= ~DREF_NONSPREAD_SOURCE_MASK; -	temp |= DREF_NONSPREAD_SOURCE_ENABLE; -	temp &= ~DREF_SSC_SOURCE_MASK; -	temp |= DREF_SSC_SOURCE_ENABLE; -	I915_WRITE(PCH_DREF_CONTROL, temp); - -	POSTING_READ(PCH_DREF_CONTROL); -	udelay(200); - -	if (has_edp_encoder) { -		if (intel_panel_use_ssc(dev_priv)) { -			temp |= DREF_SSC1_ENABLE; -			I915_WRITE(PCH_DREF_CONTROL, temp); - -			POSTING_READ(PCH_DREF_CONTROL); -			udelay(200); -		} -		temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK; - -		/* Enable CPU source on CPU attached eDP */ -		if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) { -			if (intel_panel_use_ssc(dev_priv)) -				temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD; -			else -				temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD; -		} else { -			/* Enable SSC on PCH eDP if needed */ -			if (intel_panel_use_ssc(dev_priv)) { -				DRM_ERROR("enabling SSC on PCH\n"); -				temp |= DREF_SUPERSPREAD_SOURCE_ENABLE; -			} -		} -		I915_WRITE(PCH_DREF_CONTROL, temp); -		POSTING_READ(PCH_DREF_CONTROL); -		udelay(200); -	} +	ironlake_update_pch_refclk(dev);  	fp = clock.n << 16 | clock.m1 << 8 | clock.m2;  	if (has_reduced_clock) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 0feae908bb3..44fef5e1c49 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1841,6 +1841,11 @@ done:  static void  intel_dp_destroy (struct drm_connector *connector)  { +	struct drm_device *dev = connector->dev; + +	if (intel_dpd_is_edp(dev)) +		intel_panel_destroy_backlight(dev); +  	drm_sysfs_connector_remove(connector);  	drm_connector_cleanup(connector);  	kfree(connector); @@ -2072,6 +2077,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)  					DRM_MODE_TYPE_PREFERRED;  			}  		} +		dev_priv->int_edp_connector = connector; +		intel_panel_setup_backlight(dev);  	}  	intel_dp_add_properties(intel_dp, connector); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7b330e76a43..0b2ee9d3998 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -297,9 +297,10 @@ extern void intel_pch_panel_fitting(struct drm_device *dev,  extern u32 intel_panel_get_max_backlight(struct drm_device *dev);  extern u32 intel_panel_get_backlight(struct drm_device *dev);  extern void intel_panel_set_backlight(struct drm_device *dev, u32 level); -extern void intel_panel_setup_backlight(struct drm_device *dev); +extern int intel_panel_setup_backlight(struct drm_device *dev);  extern void intel_panel_enable_backlight(struct drm_device *dev);  extern void intel_panel_disable_backlight(struct drm_device *dev); +extern void intel_panel_destroy_backlight(struct drm_device *dev);  extern enum drm_connector_status intel_panel_detect(struct drm_device *dev);  extern void intel_crtc_load_lut(struct drm_crtc *crtc); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 2e8ddfcba40..31da77f5c05 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -72,14 +72,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)  {  	struct drm_device *dev = intel_lvds->base.base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private; -	u32 ctl_reg, lvds_reg; +	u32 ctl_reg, lvds_reg, stat_reg;  	if (HAS_PCH_SPLIT(dev)) {  		ctl_reg = PCH_PP_CONTROL;  		lvds_reg = PCH_LVDS; +		stat_reg = PCH_PP_STATUS;  	} else {  		ctl_reg = PP_CONTROL;  		lvds_reg = LVDS; +		stat_reg = PP_STATUS;  	}  	I915_WRITE(lvds_reg, I915_READ(lvds_reg) | LVDS_PORT_EN); @@ -94,17 +96,16 @@ static void intel_lvds_enable(struct intel_lvds *intel_lvds)  		DRM_DEBUG_KMS("applying panel-fitter: %x, %x\n",  			      intel_lvds->pfit_control,  			      intel_lvds->pfit_pgm_ratios); -		if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) { -			DRM_ERROR("timed out waiting for panel to power off\n"); -		} else { -			I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); -			I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); -			intel_lvds->pfit_dirty = false; -		} + +		I915_WRITE(PFIT_PGM_RATIOS, intel_lvds->pfit_pgm_ratios); +		I915_WRITE(PFIT_CONTROL, intel_lvds->pfit_control); +		intel_lvds->pfit_dirty = false;  	}  	I915_WRITE(ctl_reg, I915_READ(ctl_reg) | POWER_TARGET_ON);  	POSTING_READ(lvds_reg); +	if (wait_for((I915_READ(stat_reg) & PP_ON) != 0, 1000)) +		DRM_ERROR("timed out waiting for panel to power on\n");  	intel_panel_enable_backlight(dev);  } @@ -113,24 +114,25 @@ static void intel_lvds_disable(struct intel_lvds *intel_lvds)  {  	struct drm_device *dev = intel_lvds->base.base.dev;  	struct drm_i915_private *dev_priv = dev->dev_private; -	u32 ctl_reg, lvds_reg; +	u32 ctl_reg, lvds_reg, stat_reg;  	if (HAS_PCH_SPLIT(dev)) {  		ctl_reg = PCH_PP_CONTROL;  		lvds_reg = PCH_LVDS; +		stat_reg = PCH_PP_STATUS;  	} else {  		ctl_reg = PP_CONTROL;  		lvds_reg = LVDS; +		stat_reg = PP_STATUS;  	}  	intel_panel_disable_backlight(dev);  	I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); +	if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) +		DRM_ERROR("timed out waiting for panel to power off\n");  	if (intel_lvds->pfit_control) { -		if (wait_for((I915_READ(PP_STATUS) & PP_ON) == 0, 1000)) -			DRM_ERROR("timed out waiting for panel to power off\n"); -  		I915_WRITE(PFIT_CONTROL, 0);  		intel_lvds->pfit_dirty = true;  	} @@ -398,53 +400,21 @@ out:  static void intel_lvds_prepare(struct drm_encoder *encoder)  { -	struct drm_device *dev = encoder->dev; -	struct drm_i915_private *dev_priv = dev->dev_private;  	struct intel_lvds *intel_lvds = to_intel_lvds(encoder); -	/* We try to do the minimum that is necessary in order to unlock -	 * the registers for mode setting. -	 * -	 * On Ironlake, this is quite simple as we just set the unlock key -	 * and ignore all subtleties. (This may cause some issues...) -	 * +	/*  	 * Prior to Ironlake, we must disable the pipe if we want to adjust  	 * the panel fitter. However at all other times we can just reset  	 * the registers regardless.  	 */ - -	if (HAS_PCH_SPLIT(dev)) { -		I915_WRITE(PCH_PP_CONTROL, -			   I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); -	} else if (intel_lvds->pfit_dirty) { -		I915_WRITE(PP_CONTROL, -			   (I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS) -			   & ~POWER_TARGET_ON); -	} else { -		I915_WRITE(PP_CONTROL, -			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); -	} +	if (!HAS_PCH_SPLIT(encoder->dev) && intel_lvds->pfit_dirty) +		intel_lvds_disable(intel_lvds);  }  static void intel_lvds_commit(struct drm_encoder *encoder)  { -	struct drm_device *dev = encoder->dev; -	struct drm_i915_private *dev_priv = dev->dev_private;  	struct intel_lvds *intel_lvds = to_intel_lvds(encoder); -	/* Undo any unlocking done in prepare to prevent accidental -	 * adjustment of the registers. -	 */ -	if (HAS_PCH_SPLIT(dev)) { -		u32 val = I915_READ(PCH_PP_CONTROL); -		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) -			I915_WRITE(PCH_PP_CONTROL, val & 0x3); -	} else { -		u32 val = I915_READ(PP_CONTROL); -		if ((val & PANEL_UNLOCK_REGS) == PANEL_UNLOCK_REGS) -			I915_WRITE(PP_CONTROL, val & 0x3); -	} -  	/* Always do a full power on as we do not know what state  	 * we were left in.  	 */ @@ -582,6 +552,8 @@ static void intel_lvds_destroy(struct drm_connector *connector)  	struct drm_device *dev = connector->dev;  	struct drm_i915_private *dev_priv = dev->dev_private; +	intel_panel_destroy_backlight(dev); +  	if (dev_priv->lid_notifier.notifier_call)  		acpi_lid_notifier_unregister(&dev_priv->lid_notifier);  	drm_sysfs_connector_remove(connector); @@ -1040,6 +1012,19 @@ out:  		pwm = I915_READ(BLC_PWM_PCH_CTL1);  		pwm |= PWM_PCH_ENABLE;  		I915_WRITE(BLC_PWM_PCH_CTL1, pwm); +		/* +		 * Unlock registers and just +		 * leave them unlocked +		 */ +		I915_WRITE(PCH_PP_CONTROL, +			   I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); +	} else { +		/* +		 * Unlock registers and just +		 * leave them unlocked +		 */ +		I915_WRITE(PP_CONTROL, +			   I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);  	}  	dev_priv->lid_notifier.notifier_call = intel_lid_notify;  	if (acpi_lid_notifier_register(&dev_priv->lid_notifier)) { @@ -1049,6 +1034,9 @@ out:  	/* keep the LVDS connector */  	dev_priv->int_lvds_connector = connector;  	drm_sysfs_connector_add(connector); + +	intel_panel_setup_backlight(dev); +  	return true;  failed: diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index b7c5ddb564d..b8e8158bb16 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -227,7 +227,6 @@ void intel_opregion_asle_intr(struct drm_device *dev)  	asle->aslc = asle_stat;  } -/* Only present on Ironlake+ */  void intel_opregion_gse_intr(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 05f500cd9c2..a9e0c7bcd31 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -277,7 +277,7 @@ void intel_panel_enable_backlight(struct drm_device *dev)  	dev_priv->backlight_enabled = true;  } -void intel_panel_setup_backlight(struct drm_device *dev) +static void intel_panel_init_backlight(struct drm_device *dev)  {  	struct drm_i915_private *dev_priv = dev->dev_private; @@ -309,3 +309,73 @@ intel_panel_detect(struct drm_device *dev)  	return connector_status_unknown;  } + +#ifdef CONFIG_BACKLIGHT_CLASS_DEVICE +static int intel_panel_update_status(struct backlight_device *bd) +{ +	struct drm_device *dev = bl_get_data(bd); +	intel_panel_set_backlight(dev, bd->props.brightness); +	return 0; +} + +static int intel_panel_get_brightness(struct backlight_device *bd) +{ +	struct drm_device *dev = bl_get_data(bd); +	return intel_panel_get_backlight(dev); +} + +static const struct backlight_ops intel_panel_bl_ops = { +	.update_status = intel_panel_update_status, +	.get_brightness = intel_panel_get_brightness, +}; + +int intel_panel_setup_backlight(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	struct backlight_properties props; +	struct drm_connector *connector; + +	intel_panel_init_backlight(dev); + +	if (dev_priv->int_lvds_connector) +		connector = dev_priv->int_lvds_connector; +	else if (dev_priv->int_edp_connector) +		connector = dev_priv->int_edp_connector; +	else +		return -ENODEV; + +	props.type = BACKLIGHT_RAW; +	props.max_brightness = intel_panel_get_max_backlight(dev); +	dev_priv->backlight = +		backlight_device_register("intel_backlight", +					  &connector->kdev, dev, +					  &intel_panel_bl_ops, &props); + +	if (IS_ERR(dev_priv->backlight)) { +		DRM_ERROR("Failed to register backlight: %ld\n", +			  PTR_ERR(dev_priv->backlight)); +		dev_priv->backlight = NULL; +		return -ENODEV; +	} +	dev_priv->backlight->props.brightness = intel_panel_get_backlight(dev); +	return 0; +} + +void intel_panel_destroy_backlight(struct drm_device *dev) +{ +	struct drm_i915_private *dev_priv = dev->dev_private; +	if (dev_priv->backlight) +		backlight_device_unregister(dev_priv->backlight); +} +#else +int intel_panel_setup_backlight(struct drm_device *dev) +{ +	intel_panel_init_backlight(dev); +	return 0; +} + +void intel_panel_destroy_backlight(struct drm_device *dev) +{ +	return; +} +#endif diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 47b9b277703..c30626ea9f9 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -290,6 +290,10 @@ static int init_render_ring(struct intel_ring_buffer *ring)  		if (IS_GEN6(dev) || IS_GEN7(dev))  			mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE;  		I915_WRITE(MI_MODE, mode); +		if (IS_GEN7(dev)) +			I915_WRITE(GFX_MODE_GEN7, +				   GFX_MODE_DISABLE(GFX_TLB_INVALIDATE_ALWAYS) | +				   GFX_MODE_ENABLE(GFX_REPLAY_MODE));  	}  	if (INTEL_INFO(dev)->gen >= 6) {  |