[PATCH] drm/i915: dynamic haswell display power well support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 29 Nov 2012 16:19:54 +0100
Daniel Vetter <daniel.vetter at ffwll.ch> wrote:

> We can disable (almost) all the display hw if we only use pipe A, with
> the integrated edp transcoder on port A. Because we don't set the cpu
> transcoder that earyl (yet), we need to help us with a trick to simply
> check for any edp encoders.
> 
> And wrt the old code: Can anyone explain what that struct mutex
> grabbing was supposed to protect?
> 
> v2: Paulo Zanoni pointed out that we also need to configure the eDP
> cpu transcoder correctly.
> 
> Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>

/me waits for tested-by on this one... you may want to ping Joe, since
he's one of the few I know with a working edp panel + HSW atm. (Also,
maybe run this by Art)

Power numbers and how it was tested would also be cool.

> ---
>  drivers/gpu/drm/i915/intel_ddi.c     |  8 ++++-
>  drivers/gpu/drm/i915/intel_display.c | 66
> +++++++++++++++++++++++++++++++++---
> drivers/gpu/drm/i915/intel_drv.h     |  1 -
> drivers/gpu/drm/i915/intel_pm.c      | 31 ----------------- 4 files
> changed, 68 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c index ad936c6..1a73a70 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -960,7 +960,13 @@ void intel_ddi_enable_pipe_func(struct drm_crtc
> *crtc) if (cpu_transcoder == TRANSCODER_EDP) {
>  		switch (pipe) {
>  		case PIPE_A:
> -			temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
> +			/* Can only use the always-on power well for
> eDP when
> +			 * not using the panel fitter, and when not
> using motion
> +			 * blur mitigation (which we don't support).
> */
> +			if (dev_priv->pch_pf_size)
> +				temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
> +			else
> +				temp |= TRANS_DDI_EDP_INPUT_A_ON;
>  			break;
>  		case PIPE_B:
>  			temp |= TRANS_DDI_EDP_INPUT_B_ONOFF;
> diff --git a/drivers/gpu/drm/i915/intel_display.c
> b/drivers/gpu/drm/i915/intel_display.c index 52b6b0e..ea8e57c 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -5448,6 +5448,65 @@ static int ironlake_crtc_mode_set(struct
> drm_crtc *crtc, return fdi_config_ok ? ret : -EINVAL;
>  }
>  
> +/* Starting with Haswell, we have different power wells for
> + * different parts of the GPU. This attempts to enable them all.
> + */
> +static void haswell_set_power_well(struct drm_device *dev,
> +				   bool enable)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	unsigned long power_wells[] = {
> +		HSW_PWR_WELL_CTL1,
> +		HSW_PWR_WELL_CTL2,
> +		HSW_PWR_WELL_CTL4
> +	};
> +	int i;
> +
> +	if (!IS_HASWELL(dev))
> +		return;
> +
> +	for (i = 0; i < ARRAY_SIZE(power_wells); i++) {
> +		int well = I915_READ(power_wells[i]);
> +
> +		if (enable) {
> +			I915_WRITE(power_wells[i], well &
> HSW_PWR_WELL_ENABLE);
> +			if (wait_for(I915_READ(power_wells[i]) &
> HSW_PWR_WELL_STATE, 20))
> +				DRM_ERROR("Error enabling power well
> %lx\n", power_wells[i]);
> +		} else {
> +			I915_WRITE(power_wells[i], well &
> ~HSW_PWR_WELL_ENABLE);
> +			if (wait_for((I915_READ(power_wells[i]) &
> HSW_PWR_WELL_STATE) == 0, 20))
> +				DRM_ERROR("Error disabling power
> well %lx\n", power_wells[i]);
> +		}
> +	}
> +}
> +
> +static void haswell_modeset_global_resources(struct drm_device *dev)
> +{
> +	struct drm_i915_private *dev_priv = dev->dev_private;
> +	bool enable = false;
> +	struct intel_crtc *crtc;
> +	struct intel_encoder *encoder;
> +
> +	list_for_each_entry(crtc, &dev->mode_config.crtc_list,
> base.head) {
> +		if (crtc->pipe != PIPE_A && crtc->base.enabled)
> +			enable = true;
> +		/* XXX: Should check for edp transcoder here, but
> thanks to init
> +		 * sequence that's not yet availble. Just in case
> desktop eDP on
> +		 * PORT D is possible on haswell, too. */
> +	}
> +
> +	list_for_each_entry(encoder, &dev->mode_config.encoder_list,
> base.head) {
> +		if (encoder->type != INTEL_OUTPUT_EDP)
> +			enable = true;
> +	}
> +
> +	/* Even the eDP panel fitter is outside the always-on well.
> */
> +	if (dev_priv->pch_pf_size)
> +		enable = true;
> +
> +	haswell_set_power_well(dev, enable);
> +}
> +
>  static int haswell_crtc_mode_set(struct drm_crtc *crtc,
>  				 struct drm_display_mode *mode,
>  				 struct drm_display_mode
> *adjusted_mode, @@ -8421,6 +8480,8 @@ static void
> intel_init_display(struct drm_device *dev) } else if
> (IS_HASWELL(dev)) { dev_priv->display.fdi_link_train =
> hsw_fdi_link_train; dev_priv->display.write_eld = haswell_write_eld;
> +			dev_priv->display.modeset_global_resources =
> +				haswell_modeset_global_resources;
>  		} else
>  			dev_priv->display.update_wm = NULL;
>  	} else if (IS_G4X(dev)) {
> @@ -8592,11 +8653,6 @@ static void i915_disable_vga(struct drm_device
> *dev) 
>  void intel_modeset_init_hw(struct drm_device *dev)
>  {
> -	/* We attempt to init the necessary power wells early in the
> initialization
> -	 * time, so the subsystems that expect power to be enabled
> can work.
> -	 */
> -	intel_init_power_wells(dev);
> -
>  	intel_prepare_ddi(dev);
>  
>  	intel_init_clock_gating(dev);
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h index 7ca7772..d20c603 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -646,7 +646,6 @@ extern void intel_update_fbc(struct drm_device
> *dev); extern void intel_gpu_ips_init(struct drm_i915_private
> *dev_priv); extern void intel_gpu_ips_teardown(void);
>  
> -extern void intel_init_power_wells(struct drm_device *dev);
>  extern void intel_enable_gt_powersave(struct drm_device *dev);
>  extern void intel_disable_gt_powersave(struct drm_device *dev);
>  extern void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv);
> diff --git a/drivers/gpu/drm/i915/intel_pm.c
> b/drivers/gpu/drm/i915/intel_pm.c index f595b8d..8886130 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -3916,37 +3916,6 @@ void intel_init_clock_gating(struct drm_device
> *dev) dev_priv->display.init_clock_gating(dev);
>  }
>  
> -/* Starting with Haswell, we have different power wells for
> - * different parts of the GPU. This attempts to enable them all.
> - */
> -void intel_init_power_wells(struct drm_device *dev)
> -{
> -	struct drm_i915_private *dev_priv = dev->dev_private;
> -	unsigned long power_wells[] = {
> -		HSW_PWR_WELL_CTL1,
> -		HSW_PWR_WELL_CTL2,
> -		HSW_PWR_WELL_CTL4
> -	};
> -	int i;
> -
> -	if (!IS_HASWELL(dev))
> -		return;
> -
> -	mutex_lock(&dev->struct_mutex);
> -
> -	for (i = 0; i < ARRAY_SIZE(power_wells); i++) {
> -		int well = I915_READ(power_wells[i]);
> -
> -		if ((well & HSW_PWR_WELL_STATE) == 0) {
> -			I915_WRITE(power_wells[i], well &
> HSW_PWR_WELL_ENABLE);
> -			if (wait_for((I915_READ(power_wells[i]) &
> HSW_PWR_WELL_STATE), 20))
> -				DRM_ERROR("Error enabling power well
> %lx\n", power_wells[i]);
> -		}
> -	}
> -
> -	mutex_unlock(&dev->struct_mutex);
> -}
> -
>  /* Set up chip specific power management-related functions */
>  void intel_init_pm(struct drm_device *dev)
>  {



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux