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 <imre.deak@xxxxxxxxx> > --- > 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ä <ville.syrjala@xxxxxxxxxxxxxxx> > + 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 Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx