On Tue, Aug 09, 2016 at 08:21:32PM +0300, Imre Deak wrote:
> Atm the LVDS encoder depends on the PPS HW context being saved/restored
> from generic suspend/resume code. Since the PPS is specific to the LVDS
> and eDP encoders a cleaner way is to reinitialize it during encoder
> enabling, so do this here for LVDS. Follow-up patches will init the PPS
> for the eDP encoder similarly and remove the suspend/resume time save /
> restore.
> 
> v2:
> - Apply BSpec +1 offset and use DIV_ROUND_UP() when programming the
> power cycle delay. (Ville)
> 
> Signed-off-by: Imre Deak <[email protected]>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |   1 +
>  drivers/gpu/drm/i915/intel_lvds.c | 113 
> +++++++++++++++++++++++++++++++++-----
>  2 files changed, 101 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
> index 889508f..da82744 100644
> --- a/drivers/gpu/drm/i915/i915_reg.h
> +++ b/drivers/gpu/drm/i915/i915_reg.h
> @@ -3710,6 +3710,7 @@ enum {
>  
>  #define _PP_ON_DELAYS                        0x61208
>  #define PP_ON_DELAYS(pps_idx)                _MMIO_PPS(pps_idx, 
> _PP_ON_DELAYS)
> +#define  PANEL_PORT_SELECT_SHIFT     30
>  #define  PANEL_PORT_SELECT_MASK              (3 << 30)
>  #define  PANEL_PORT_SELECT_LVDS              (0 << 30)
>  #define  PANEL_PORT_SELECT_DPA               (1 << 30)
> diff --git a/drivers/gpu/drm/i915/intel_lvds.c 
> b/drivers/gpu/drm/i915/intel_lvds.c
> index c5739fc..939f51f 100644
> --- a/drivers/gpu/drm/i915/intel_lvds.c
> +++ b/drivers/gpu/drm/i915/intel_lvds.c
> @@ -48,6 +48,20 @@ struct intel_lvds_connector {
>       struct notifier_block lid_notifier;
>  };
>  
> +struct intel_lvds_pps {
> +     /* 100us units */
> +     int t1_t2;
> +     int t3;
> +     int t4;
> +     int t5;
> +     int tx;
> +
> +     int divider;
> +
> +     int port;
> +     bool reset_on_powerdown;

powerdown_on_reset?

> +};
> +
>  struct intel_lvds_encoder {
>       struct intel_encoder base;
>  
> @@ -55,6 +69,9 @@ struct intel_lvds_encoder {
>       i915_reg_t reg;
>       u32 a3_power;
>  
> +     struct intel_lvds_pps init_pps;
> +     u32 init_lvds_val;
> +
>       struct intel_lvds_connector *attached_connector;
>  };
>  
> @@ -136,6 +153,82 @@ static void intel_lvds_get_config(struct intel_encoder 
> *encoder,
>       pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
>  }
>  
> +static void intel_lvds_pps_get_hw_state(struct drm_i915_private *dev_priv,
> +                                     struct intel_lvds_pps *pps)
> +{
> +     u32 val;
> +
> +     pps->reset_on_powerdown = I915_READ(PP_CONTROL(0)) & PANEL_POWER_RESET;
> +
> +     val = I915_READ(PP_ON_DELAYS(0));
> +     pps->port = (val & PANEL_PORT_SELECT_MASK) >>
> +                 PANEL_PORT_SELECT_SHIFT;
> +     pps->t1_t2 = (val & PANEL_POWER_UP_DELAY_MASK) >>
> +                  PANEL_POWER_UP_DELAY_SHIFT;
> +     pps->t5 = (val & PANEL_LIGHT_ON_DELAY_MASK) >>
> +               PANEL_LIGHT_ON_DELAY_SHIFT;
> +
> +     val = I915_READ(PP_OFF_DELAYS(0));
> +     pps->t3 = (val & PANEL_POWER_DOWN_DELAY_MASK) >>
> +               PANEL_POWER_DOWN_DELAY_SHIFT;
> +     pps->tx = (val & PANEL_LIGHT_OFF_DELAY_MASK) >>
> +               PANEL_LIGHT_OFF_DELAY_SHIFT;
> +
> +     val = I915_READ(PP_DIVISOR(0));
> +     pps->divider = (val & PP_REFERENCE_DIVIDER_MASK) >>
> +                    PP_REFERENCE_DIVIDER_SHIFT;
> +     val = (val & PANEL_POWER_CYCLE_DELAY_MASK) >>
> +           PANEL_POWER_CYCLE_DELAY_SHIFT;
> +     /*
> +      * Remove the BSpec specified +1 (100ms) offset that accounts for a
> +      * too short power-cycle delay due to the asynchronous programming of
> +      * the register.
> +      */
> +     if (val)
> +             val--;
> +     /* Convert from 100ms to 100us units */
> +     pps->t4 = val * 1000;
> +
> +     if (INTEL_INFO(dev_priv)->gen <= 4 &&
> +         pps->t1_t2 == 0 && pps->t5 == 0 && pps->t3 == 0 && pps->tx == 0) {
> +             DRM_DEBUG_KMS("Panel power timings uninitialized, "
> +                           "setting defaults\n");
> +             /* Set T2 to 40ms and T5 to 200ms in 100 usec units */
> +             pps->t1_t2 = 40 * 10;
> +             pps->t5 = 200 * 10;
> +             /* Set T3 to 35ms and Tx to 200ms in 100 usec units */
> +             pps->t3 = 35 * 10;
> +             pps->tx = 200 * 10;
> +     }
> +
> +     DRM_DEBUG_DRIVER("LVDS PPS:t1+t2 %d t3 %d t4 %d t5 %d tx %d "
> +                      "divider %d port %d reset_on_powerdown %d\n",
> +                      pps->t1_t2, pps->t3, pps->t4, pps->t5, pps->tx,
> +                      pps->divider, pps->port, pps->reset_on_powerdown);
> +}
> +
> +static void intel_lvds_pps_init_hw(struct drm_i915_private *dev_priv,
> +                                struct intel_lvds_pps *pps)
> +{
> +     u32 val;
> +
> +     val = I915_READ(PP_CONTROL(0));
> +     WARN_ON((val & PANEL_UNLOCK_MASK) != PANEL_UNLOCK_REGS);
> +     if (pps->reset_on_powerdown)
> +             val |= PANEL_POWER_RESET;
> +     I915_WRITE(PP_CONTROL(0), val);
> +
> +     I915_WRITE(PP_ON_DELAYS(0), (pps->port << PANEL_PORT_SELECT_SHIFT) |
> +                                 (pps->t1_t2 << PANEL_POWER_UP_DELAY_SHIFT) |
> +                                 (pps->t5 << PANEL_LIGHT_ON_DELAY_SHIFT));
> +     I915_WRITE(PP_OFF_DELAYS(0), (pps->t3 << PANEL_POWER_DOWN_DELAY_SHIFT) |
> +                                  (pps->tx << PANEL_LIGHT_OFF_DELAY_SHIFT));
> +
> +     val = pps->divider << PP_REFERENCE_DIVIDER_SHIFT;
> +     val |= DIV_ROUND_UP(pps->t4 + 1, 1000) << PANEL_POWER_CYCLE_DELAY_SHIFT;

+1 vs. div in the wrong order

With that fixed
Reviewed-by: Ville Syrjälä <[email protected]>

> +     I915_WRITE(PP_DIVISOR(0), val);
> +}
> +
>  static void intel_pre_enable_lvds(struct intel_encoder *encoder)
>  {
>       struct intel_lvds_encoder *lvds_encoder = 
> to_lvds_encoder(&encoder->base);
> @@ -154,7 +247,9 @@ static void intel_pre_enable_lvds(struct intel_encoder 
> *encoder)
>               assert_pll_disabled(dev_priv, pipe);
>       }
>  
> -     temp = I915_READ(lvds_encoder->reg);
> +     intel_lvds_pps_init_hw(dev_priv, &lvds_encoder->init_pps);
> +
> +     temp = lvds_encoder->init_lvds_val;
>       temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
>  
>       if (HAS_PCH_CPT(dev)) {
> @@ -922,18 +1017,6 @@ void intel_lvds_init(struct drm_device *dev)
>               DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled 
> anyway\n");
>       }
>  
> -      /* Set the Panel Power On/Off timings if uninitialized. */
> -     if (INTEL_INFO(dev_priv)->gen < 5 &&
> -         I915_READ(PP_ON_DELAYS(0)) == 0 && I915_READ(PP_OFF_DELAYS(0)) == 
> 0) {
> -             /* Set T2 to 40ms and T5 to 200ms */
> -             I915_WRITE(PP_ON_DELAYS(0), 0x019007d0);
> -
> -             /* Set T3 to 35ms and Tx to 200ms */
> -             I915_WRITE(PP_OFF_DELAYS(0), 0x015e07d0);
> -
> -             DRM_DEBUG_KMS("Panel power timings uninitialized, setting 
> defaults\n");
> -     }
> -
>       lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL);
>       if (!lvds_encoder)
>               return;
> @@ -999,6 +1082,10 @@ void intel_lvds_init(struct drm_device *dev)
>                                     dev->mode_config.scaling_mode_property,
>                                     DRM_MODE_SCALE_ASPECT);
>       intel_connector->panel.fitting_mode = DRM_MODE_SCALE_ASPECT;
> +
> +     intel_lvds_pps_get_hw_state(dev_priv, &lvds_encoder->init_pps);
> +     lvds_encoder->init_lvds_val = lvds;
> +
>       /*
>        * LVDS discovery:
>        * 1) check for EDID on DDC
> -- 
> 2.5.0

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to