[Intel-gfx] [PATCH] drm/i915/bxt: Enable VBT based BL control for DP

Imre Deak imre.deak at intel.com
Tue Jun 6 12:34:22 UTC 2017


On Tue, Jun 06, 2017 at 12:24:30PM +0300, Jani Nikula wrote:
> On Tue, 06 Jun 2017, Mustamin B Mustaffa <mustamin.b.mustaffa at intel.com> wrote:
> > [...]
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index d1670b8..124f58b 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -591,13 +591,8 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
> >  	/* We should never land here with regular DP ports */
> >  	WARN_ON(!is_edp(intel_dp));
> >  
> > -	/*
> > -	 * TODO: BXT has 2 PPS instances. The correct port->PPS instance
> > -	 * mapping needs to be retrieved from VBT, for now just hard-code to
> > -	 * use instance #0 always.
> > -	 */
> >  	if (!intel_dp->pps_reset)
> > -		return 0;
> > +		return dev_priv->vbt.backlight.controller;
> 
> So the existing code around here looks a bit convoluted, not least
> because now pretty much all PPS access first does
> 
>  - intel_pps_get_registers(), which calls
>  - bxt_power_sequencer_idx(), which calls
>  - intel_dp_init_panel_power_sequencer_registers(), which calls
>  - intel_pps_get_registers()...
> 
> With your change, for controller == 1 and pps_reset == true, the first
> time the registers are needed, we'll initialize the correct controller 1
> registers, but controller 0 registers are returned. From there on, we'll
> keep returning controller 1 registers until pps_reset is set to true
> again.
> 
> Cc: Imre as author of commits 78597996370c ("drm/i915/bxt: Fix PPS lost
> state after suspend breaking eDP link training") and 8e8232d51878
> ("drm/i915: Deduplicate PPS register retrieval") which I think create
> the loop.

A loop would be prevented by the pps->reset check, but agree the code
isn't nice, I guess I overlooked this when I wrote it. To make things
clearer we could factor out a helper from
intel_dp_init_panel_power_sequencer_registers() that takes pps_registers
and call this helper from bxt_power_sequencer_idx().

So how about something like the following:

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 58dca87..e312f63 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -424,6 +424,14 @@ static void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes)
 		dst[i] = src >> ((3-i) * 8);
 }
 
+struct pps_registers {
+	i915_reg_t pp_ctrl;
+	i915_reg_t pp_stat;
+	i915_reg_t pp_on;
+	i915_reg_t pp_off;
+	i915_reg_t pp_div;
+};
+
 static void
 intel_dp_init_panel_power_sequencer(struct drm_device *dev,
 				    struct intel_dp *intel_dp);
@@ -431,6 +439,16 @@ static void
 intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 					      struct intel_dp *intel_dp,
 					      bool force_disable_vdd);
+
+static void intel_pps_get_instance_registers(struct drm_i915_private *dev_priv,
+					     int idx,
+					     struct pps_registers *regs);
+
+static void
+intel_dp_init_panel_power_sequencer_instance(struct drm_i915_private *dev_priv,
+					     struct intel_dp *intel_dp,
+					     bool force_disable_vdd,
+					     const struct pps_registers *regs);
 static void
 intel_dp_pps_init(struct drm_device *dev, struct intel_dp *intel_dp);
 
@@ -627,6 +645,8 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
 	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
 	struct drm_device *dev = intel_dig_port->base.base.dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct pps_registers regs;
+	int idx;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
@@ -638,8 +658,10 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
 	 * mapping needs to be retrieved from VBT, for now just hard-code to
 	 * use instance #0 always.
 	 */
+	idx = 0;
+
 	if (!intel_dp->pps_reset)
-		return 0;
+		return idx;
 
 	intel_dp->pps_reset = false;
 
@@ -647,9 +669,11 @@ bxt_power_sequencer_idx(struct intel_dp *intel_dp)
 	 * Only the HW needs to be reprogrammed, the SW state is fixed and
 	 * has been setup during connector init.
 	 */
-	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, false);
+	intel_pps_get_instance_registers(dev_priv, idx, &regs);
+	intel_dp_init_panel_power_sequencer_instance(dev_priv, intel_dp, false,
+						     &regs);
 
-	return 0;
+	return idx;
 }
 
 typedef bool (*vlv_pipe_check)(struct drm_i915_private *dev_priv,
@@ -773,27 +797,12 @@ void intel_power_sequencer_reset(struct drm_i915_private *dev_priv)
 	}
 }
 
-struct pps_registers {
-	i915_reg_t pp_ctrl;
-	i915_reg_t pp_stat;
-	i915_reg_t pp_on;
-	i915_reg_t pp_off;
-	i915_reg_t pp_div;
-};
-
-static void intel_pps_get_registers(struct drm_i915_private *dev_priv,
-				    struct intel_dp *intel_dp,
-				    struct pps_registers *regs)
+static void intel_pps_get_instance_registers(struct drm_i915_private *dev_priv,
+					     int pps_idx,
+					     struct pps_registers *regs)
 {
-	int pps_idx = 0;
-
 	memset(regs, 0, sizeof(*regs));
 
-	if (IS_GEN9_LP(dev_priv))
-		pps_idx = bxt_power_sequencer_idx(intel_dp);
-	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
-		pps_idx = vlv_power_sequencer_pipe(intel_dp);
-
 	regs->pp_ctrl = PP_CONTROL(pps_idx);
 	regs->pp_stat = PP_STATUS(pps_idx);
 	regs->pp_on = PP_ON_DELAYS(pps_idx);
@@ -802,6 +811,20 @@ static void intel_pps_get_registers(struct drm_i915_private *dev_priv,
 		regs->pp_div = PP_DIVISOR(pps_idx);
 }
 
+static void intel_pps_get_registers(struct drm_i915_private *dev_priv,
+				    struct intel_dp *intel_dp,
+				    struct pps_registers *regs)
+{
+	int pps_idx = 0;
+
+	if (IS_GEN9_LP(dev_priv))
+		pps_idx = bxt_power_sequencer_idx(intel_dp);
+	else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
+		pps_idx = vlv_power_sequencer_pipe(intel_dp);
+
+	intel_pps_get_instance_registers(dev_priv, pps_idx, regs);
+}
+
 static i915_reg_t
 _pp_ctrl_reg(struct intel_dp *intel_dp)
 {
@@ -5228,21 +5251,18 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev,
 }
 
 static void
-intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
-					      struct intel_dp *intel_dp,
-					      bool force_disable_vdd)
+intel_dp_init_panel_power_sequencer_instance(struct drm_i915_private *dev_priv,
+					     struct intel_dp *intel_dp,
+					     bool force_disable_vdd,
+					     const struct pps_registers *regs)
 {
-	struct drm_i915_private *dev_priv = to_i915(dev);
 	u32 pp_on, pp_off, pp_div, port_sel = 0;
 	int div = dev_priv->rawclk_freq / 1000;
-	struct pps_registers regs;
 	enum port port = dp_to_dig_port(intel_dp)->port;
 	const struct edp_power_seq *seq = &intel_dp->pps_delays;
 
 	lockdep_assert_held(&dev_priv->pps_mutex);
 
-	intel_pps_get_registers(dev_priv, intel_dp, &regs);
-
 	/*
 	 * On some VLV machines the BIOS can leave the VDD
 	 * enabled even on power seqeuencers which aren't
@@ -5265,7 +5285,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 
 		pp &= ~EDP_FORCE_VDD;
 
-		I915_WRITE(regs.pp_ctrl, pp);
+		I915_WRITE(regs->pp_ctrl, pp);
 	}
 
 	pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
@@ -5275,7 +5295,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 	/* Compute the divisor for the pp clock, simply match the Bspec
 	 * formula. */
 	if (IS_GEN9_LP(dev_priv)) {
-		pp_div = I915_READ(regs.pp_ctrl);
+		pp_div = I915_READ(regs->pp_ctrl);
 		pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK;
 		pp_div |= (DIV_ROUND_UP((seq->t11_t12 + 1), 1000)
 				<< BXT_POWER_CYCLE_DELAY_SHIFT);
@@ -5298,19 +5318,32 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 
 	pp_on |= port_sel;
 
-	I915_WRITE(regs.pp_on, pp_on);
-	I915_WRITE(regs.pp_off, pp_off);
+	I915_WRITE(regs->pp_on, pp_on);
+	I915_WRITE(regs->pp_off, pp_off);
 	if (IS_GEN9_LP(dev_priv))
-		I915_WRITE(regs.pp_ctrl, pp_div);
+		I915_WRITE(regs->pp_ctrl, pp_div);
 	else
-		I915_WRITE(regs.pp_div, pp_div);
+		I915_WRITE(regs->pp_div, pp_div);
 
 	DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n",
-		      I915_READ(regs.pp_on),
-		      I915_READ(regs.pp_off),
+		      I915_READ(regs->pp_on),
+		      I915_READ(regs->pp_off),
 		      IS_GEN9_LP(dev_priv) ?
-		      (I915_READ(regs.pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK) :
-		      I915_READ(regs.pp_div));
+		      (I915_READ(regs->pp_ctrl) & BXT_POWER_CYCLE_DELAY_MASK) :
+		      I915_READ(regs->pp_div));
+}
+
+static void
+intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
+					      struct intel_dp *intel_dp,
+					      bool force_disable_vdd)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct pps_registers regs;
+
+	intel_pps_get_registers(dev_priv, intel_dp, &regs);
+	intel_dp_init_panel_power_sequencer_instance(dev_priv, intel_dp,
+						     force_disable_vdd, &regs);
 }
 
 static void intel_dp_pps_init(struct drm_device *dev,

--Imre


More information about the Intel-gfx mailing list