Message ID | 1395981902-21606-4-git-send-email-vandana.kannan@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, 28 Mar 2014, Vandana Kannan <vandana.kannan@intel.com> wrote: > From: Pradeep Bhat <pradeep.bhat@intel.com> > > This patch computes and stored 2nd M/N/TU for switching to different > refresh rate dynamically. PIPECONF_EDP_RR_MODE_SWITCH bit helps toggle > between alternate refresh rates programmed in 2nd M/N/TU registers. > > v2: Daniel's review comments > Computing M2/N2 in compute_config and storing it in crtc_config > > v3: Modified reference to edp_downclock and edp_downclock_avail based on the > changes made to move them from dev_private to intel_panel. > > v4: Modified references to is_drrs_supported based on the changes made to > rename it to drrs_support. > > v5: Jani's review comments > Removed superfluous return statements. Changed support for Gen 7 and above. > Corrected indentation. Re-structured the code which finds crtc and connector > from encoder. Changed some logs to be less verbose. > > v6: Modifying i915_drrs to include only intel connector as intel_dp can be > derived from intel connector when required. > > v7: As per internal review comments, acquiring mutex just before accessing > drrs RR. As per Chris's review comments, added documentation about the use > of locking in the function. > > v8: Incorporated Jani's review comments. > Removed reference to edp_downclock. > > Signed-off-by: Pradeep Bhat <pradeep.bhat@intel.com> > Signed-off-by: Vandana Kannan <vandana.kannan@intel.com> > Cc: Jani Nikula <jani.nikula@linux.intel.com> > --- > drivers/gpu/drm/i915/i915_drv.h | 5 ++ > drivers/gpu/drm/i915/i915_reg.h | 1 + > drivers/gpu/drm/i915/intel_dp.c | 108 ++++++++++++++++++++++++++++++++++++++ > drivers/gpu/drm/i915/intel_drv.h | 6 ++- > 4 files changed, 119 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index cd73a33..1c9d5cf 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -794,6 +794,10 @@ struct i915_fbc { > } no_fbc_reason; > }; > > +struct i915_drrs { > + struct intel_connector *connector; > +}; > + > struct i915_psr { > bool sink_support; > bool source_ok; > @@ -1497,6 +1501,7 @@ typedef struct drm_i915_private { > struct timer_list hotplug_reenable_timer; > > struct i915_fbc fbc; > + struct i915_drrs drrs; > struct intel_opregion opregion; > struct intel_vbt_data vbt; > > diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h > index 74f7d85..04fc64a 100644 > --- a/drivers/gpu/drm/i915/i915_reg.h > +++ b/drivers/gpu/drm/i915/i915_reg.h > @@ -3255,6 +3255,7 @@ enum punit_power_well { > #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ > #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ > #define PIPECONF_INTERLACE_MODE_MASK (7 << 21) > +#define PIPECONF_EDP_RR_MODE_SWITCH (1 << 20) > #define PIPECONF_CXSR_DOWNCLOCK (1<<16) > #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) > #define PIPECONF_BPC_MASK (0x7 << 5) > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c > index f2735de..9640df1 100644 > --- a/drivers/gpu/drm/i915/intel_dp.c > +++ b/drivers/gpu/drm/i915/intel_dp.c > @@ -736,6 +736,20 @@ intel_dp_set_clock(struct intel_encoder *encoder, > } > } > > +static void > +intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n) > +{ > + struct drm_device *dev = crtc->base.dev; > + struct drm_i915_private *dev_priv = dev->dev_private; > + enum transcoder transcoder = crtc->config.cpu_transcoder; > + > + I915_WRITE(PIPE_DATA_M2(transcoder), > + TU_SIZE(m_n->tu) | m_n->gmch_m); > + I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n); > + I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m); > + I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n); > +} > + > bool > intel_dp_compute_config(struct intel_encoder *encoder, > struct intel_crtc_config *pipe_config) > @@ -840,6 +854,15 @@ found: > pipe_config->port_clock, > &pipe_config->dp_m_n); > > + if (intel_connector->panel.downclock_mode != NULL && > + intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) { > + intel_link_compute_m_n(bpp, lane_count, > + intel_connector->panel.downclock_mode->clock, > + pipe_config->port_clock, > + &pipe_config->dp_m2_n2); > + } > + > + > intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); > > return true; > @@ -3611,6 +3634,87 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, > I915_READ(pp_div_reg)); > } > > +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) > +{ > + struct drm_i915_private *dev_priv = dev->dev_private; > + struct intel_encoder *encoder; > + struct intel_dp *intel_dp = NULL; > + struct intel_crtc_config *config = NULL; > + struct intel_crtc *intel_crtc = NULL; > + struct intel_connector *intel_connector = dev_priv->drrs.connector; > + u32 reg, val; > + int index = 0; enum edp_drrs_refresh_rate. > + > + if (refresh_rate <= 0) { > + DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n"); > + return; > + } > + > + if (intel_connector == NULL) { > + DRM_DEBUG_KMS("DRRS supported for eDP only.\n"); > + return; > + } > + > + encoder = intel_attached_encoder(&intel_connector->base); > + intel_dp = enc_to_intel_dp(&encoder->base); > + intel_crtc = encoder->new_crtc; > + > + if (!intel_crtc) { > + DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n"); > + return; > + } > + > + config = &intel_crtc->config; > + > + if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) { > + DRM_DEBUG_KMS("Seamless DRRS not supported.\n"); Isn't seamless the only thing that *is* supported? > + return; > + } > + > + if (intel_connector->panel.fixed_mode->vrefresh == refresh_rate) > + index = DRRS_HIGH_RR; > + else > + index = DRRS_LOW_RR; > + > + if (index == intel_dp->drrs_state.refresh_rate_type) { > + DRM_DEBUG_KMS( > + "DRRS requested for previously set RR...ignoring\n"); > + return; > + } > + > + if (!intel_crtc->active) { > + DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n"); > + return; > + } > + > + if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) { Can we end up here when drrs is not supported by the platform? > + reg = PIPECONF(intel_crtc->config.cpu_transcoder); > + val = I915_READ(reg); > + if (index > DRRS_HIGH_RR) { > + val |= PIPECONF_EDP_RR_MODE_SWITCH; > + intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2); > + } else { > + val &= ~PIPECONF_EDP_RR_MODE_SWITCH; > + } > + I915_WRITE(reg, val); > + } > + > + /* > + * mutex taken to ensure that there is no race between differnt > + * drrs calls trying to update refresh rate. This scenario may occur > + * in future when idleness detection based DRRS in kernel and > + * possible calls from user space to set differnt RR are made. > + */ > + > + mutex_lock(&intel_dp->drrs_state.mutex); > + > + intel_dp->drrs_state.refresh_rate_type = index; > + > + mutex_unlock(&intel_dp->drrs_state.mutex); > + > + DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate); > +} > + > static struct drm_display_mode * > intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, > struct intel_connector *intel_connector, > @@ -3647,6 +3751,10 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, > > if (downclock_mode != NULL && > dev_priv->vbt.drrs_type == SEAMLESS_DRRS_SUPPORT) { > + dev_priv->drrs.connector = intel_connector; > + > + mutex_init(&intel_dp->drrs_state.mutex); > + > intel_dp->drrs_state.type = dev_priv->vbt.drrs_type; > > intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR; > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h > index d781165..46fc8b3 100644 > --- a/drivers/gpu/drm/i915/intel_drv.h > +++ b/drivers/gpu/drm/i915/intel_drv.h > @@ -305,6 +305,9 @@ struct intel_crtc_config { > int pipe_bpp; > struct intel_link_m_n dp_m_n; > > + /* m2_n2 for eDP downclock */ > + struct intel_link_m_n dp_m2_n2; > + > /* > * Frequence the dpll for the port should run at. Differs from the > * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also > @@ -535,6 +538,7 @@ struct intel_dp { > struct { > enum drrs_support_type type; > enum edp_drrs_refresh_rate_type refresh_rate_type; > + struct mutex mutex; > } drrs_state; > > }; > @@ -789,7 +793,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); > void intel_edp_psr_enable(struct intel_dp *intel_dp); > void intel_edp_psr_disable(struct intel_dp *intel_dp); > void intel_edp_psr_update(struct drm_device *dev); > - > +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate); > > /* intel_dsi.c */ > bool intel_dsi_init(struct drm_device *dev); > -- > 1.7.9.5 >
On Apr-01-2014 6:55 PM, Jani Nikula wrote: > On Fri, 28 Mar 2014, Vandana Kannan <vandana.kannan@intel.com> wrote: >> From: Pradeep Bhat <pradeep.bhat@intel.com> >> >> This patch computes and stored 2nd M/N/TU for switching to different >> refresh rate dynamically. PIPECONF_EDP_RR_MODE_SWITCH bit helps toggle >> between alternate refresh rates programmed in 2nd M/N/TU registers. >> >> v2: Daniel's review comments >> Computing M2/N2 in compute_config and storing it in crtc_config >> >> v3: Modified reference to edp_downclock and edp_downclock_avail based on the >> changes made to move them from dev_private to intel_panel. >> >> v4: Modified references to is_drrs_supported based on the changes made to >> rename it to drrs_support. >> >> v5: Jani's review comments >> Removed superfluous return statements. Changed support for Gen 7 and above. >> Corrected indentation. Re-structured the code which finds crtc and connector >> from encoder. Changed some logs to be less verbose. >> >> v6: Modifying i915_drrs to include only intel connector as intel_dp can be >> derived from intel connector when required. >> >> v7: As per internal review comments, acquiring mutex just before accessing >> drrs RR. As per Chris's review comments, added documentation about the use >> of locking in the function. >> >> v8: Incorporated Jani's review comments. >> Removed reference to edp_downclock. >> >> Signed-off-by: Pradeep Bhat <pradeep.bhat@intel.com> >> Signed-off-by: Vandana Kannan <vandana.kannan@intel.com> >> Cc: Jani Nikula <jani.nikula@linux.intel.com> >> --- >> drivers/gpu/drm/i915/i915_drv.h | 5 ++ >> drivers/gpu/drm/i915/i915_reg.h | 1 + >> drivers/gpu/drm/i915/intel_dp.c | 108 ++++++++++++++++++++++++++++++++++++++ >> drivers/gpu/drm/i915/intel_drv.h | 6 ++- >> 4 files changed, 119 insertions(+), 1 deletion(-) >> >> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h >> index cd73a33..1c9d5cf 100644 >> --- a/drivers/gpu/drm/i915/i915_drv.h >> +++ b/drivers/gpu/drm/i915/i915_drv.h >> @@ -794,6 +794,10 @@ struct i915_fbc { >> } no_fbc_reason; >> }; >> >> +struct i915_drrs { >> + struct intel_connector *connector; >> +}; >> + >> struct i915_psr { >> bool sink_support; >> bool source_ok; >> @@ -1497,6 +1501,7 @@ typedef struct drm_i915_private { >> struct timer_list hotplug_reenable_timer; >> >> struct i915_fbc fbc; >> + struct i915_drrs drrs; >> struct intel_opregion opregion; >> struct intel_vbt_data vbt; >> >> diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h >> index 74f7d85..04fc64a 100644 >> --- a/drivers/gpu/drm/i915/i915_reg.h >> +++ b/drivers/gpu/drm/i915/i915_reg.h >> @@ -3255,6 +3255,7 @@ enum punit_power_well { >> #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ >> #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ >> #define PIPECONF_INTERLACE_MODE_MASK (7 << 21) >> +#define PIPECONF_EDP_RR_MODE_SWITCH (1 << 20) >> #define PIPECONF_CXSR_DOWNCLOCK (1<<16) >> #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) >> #define PIPECONF_BPC_MASK (0x7 << 5) >> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c >> index f2735de..9640df1 100644 >> --- a/drivers/gpu/drm/i915/intel_dp.c >> +++ b/drivers/gpu/drm/i915/intel_dp.c >> @@ -736,6 +736,20 @@ intel_dp_set_clock(struct intel_encoder *encoder, >> } >> } >> >> +static void >> +intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n) >> +{ >> + struct drm_device *dev = crtc->base.dev; >> + struct drm_i915_private *dev_priv = dev->dev_private; >> + enum transcoder transcoder = crtc->config.cpu_transcoder; >> + >> + I915_WRITE(PIPE_DATA_M2(transcoder), >> + TU_SIZE(m_n->tu) | m_n->gmch_m); >> + I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n); >> + I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m); >> + I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n); >> +} >> + >> bool >> intel_dp_compute_config(struct intel_encoder *encoder, >> struct intel_crtc_config *pipe_config) >> @@ -840,6 +854,15 @@ found: >> pipe_config->port_clock, >> &pipe_config->dp_m_n); >> >> + if (intel_connector->panel.downclock_mode != NULL && >> + intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) { >> + intel_link_compute_m_n(bpp, lane_count, >> + intel_connector->panel.downclock_mode->clock, >> + pipe_config->port_clock, >> + &pipe_config->dp_m2_n2); >> + } >> + >> + >> intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); >> >> return true; >> @@ -3611,6 +3634,87 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, >> I915_READ(pp_div_reg)); >> } >> >> +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) >> +{ >> + struct drm_i915_private *dev_priv = dev->dev_private; >> + struct intel_encoder *encoder; >> + struct intel_dp *intel_dp = NULL; >> + struct intel_crtc_config *config = NULL; >> + struct intel_crtc *intel_crtc = NULL; >> + struct intel_connector *intel_connector = dev_priv->drrs.connector; >> + u32 reg, val; >> + int index = 0; > > enum edp_drrs_refresh_rate. > Will change this accordingly.. >> + >> + if (refresh_rate <= 0) { >> + DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n"); >> + return; >> + } >> + >> + if (intel_connector == NULL) { >> + DRM_DEBUG_KMS("DRRS supported for eDP only.\n"); >> + return; >> + } >> + >> + encoder = intel_attached_encoder(&intel_connector->base); >> + intel_dp = enc_to_intel_dp(&encoder->base); >> + intel_crtc = encoder->new_crtc; >> + >> + if (!intel_crtc) { >> + DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n"); >> + return; >> + } >> + >> + config = &intel_crtc->config; >> + >> + if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) { >> + DRM_DEBUG_KMS("Seamless DRRS not supported.\n"); > > Isn't seamless the only thing that *is* supported? > Yes, will correct this.. >> + return; >> + } >> + >> + if (intel_connector->panel.fixed_mode->vrefresh == refresh_rate) >> + index = DRRS_HIGH_RR; >> + else >> + index = DRRS_LOW_RR; >> + >> + if (index == intel_dp->drrs_state.refresh_rate_type) { >> + DRM_DEBUG_KMS( >> + "DRRS requested for previously set RR...ignoring\n"); >> + return; >> + } >> + >> + if (!intel_crtc->active) { >> + DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n"); >> + return; >> + } >> + >> + if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) { > > Can we end up here when drrs is not supported by the platform? > When DRRS is not supported by the platform, drrs.connector would remain NULL. So, the check for connector above should handle the case and avoid coming up to this point. For the PSR related changes (enable/disable DRRS according to status of PSR) that would be made as part of Patch2, I think a check would be required here to make sure any call to this function not coming through update_drrs/disable_drrs returns without setting the registers. >> + reg = PIPECONF(intel_crtc->config.cpu_transcoder); >> + val = I915_READ(reg); >> + if (index > DRRS_HIGH_RR) { >> + val |= PIPECONF_EDP_RR_MODE_SWITCH; >> + intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2); >> + } else { >> + val &= ~PIPECONF_EDP_RR_MODE_SWITCH; >> + } >> + I915_WRITE(reg, val); >> + } >> + >> + /* >> + * mutex taken to ensure that there is no race between differnt >> + * drrs calls trying to update refresh rate. This scenario may occur >> + * in future when idleness detection based DRRS in kernel and >> + * possible calls from user space to set differnt RR are made. >> + */ >> + >> + mutex_lock(&intel_dp->drrs_state.mutex); >> + >> + intel_dp->drrs_state.refresh_rate_type = index; >> + >> + mutex_unlock(&intel_dp->drrs_state.mutex); >> + >> + DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate); >> +} >> + >> static struct drm_display_mode * >> intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, >> struct intel_connector *intel_connector, >> @@ -3647,6 +3751,10 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, >> >> if (downclock_mode != NULL && >> dev_priv->vbt.drrs_type == SEAMLESS_DRRS_SUPPORT) { >> + dev_priv->drrs.connector = intel_connector; >> + >> + mutex_init(&intel_dp->drrs_state.mutex); >> + >> intel_dp->drrs_state.type = dev_priv->vbt.drrs_type; >> >> intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR; >> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h >> index d781165..46fc8b3 100644 >> --- a/drivers/gpu/drm/i915/intel_drv.h >> +++ b/drivers/gpu/drm/i915/intel_drv.h >> @@ -305,6 +305,9 @@ struct intel_crtc_config { >> int pipe_bpp; >> struct intel_link_m_n dp_m_n; >> >> + /* m2_n2 for eDP downclock */ >> + struct intel_link_m_n dp_m2_n2; >> + >> /* >> * Frequence the dpll for the port should run at. Differs from the >> * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also >> @@ -535,6 +538,7 @@ struct intel_dp { >> struct { >> enum drrs_support_type type; >> enum edp_drrs_refresh_rate_type refresh_rate_type; >> + struct mutex mutex; >> } drrs_state; >> >> }; >> @@ -789,7 +793,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); >> void intel_edp_psr_enable(struct intel_dp *intel_dp); >> void intel_edp_psr_disable(struct intel_dp *intel_dp); >> void intel_edp_psr_update(struct drm_device *dev); >> - >> +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate); >> >> /* intel_dsi.c */ >> bool intel_dsi_init(struct drm_device *dev); >> -- >> 1.7.9.5 >> >
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index cd73a33..1c9d5cf 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -794,6 +794,10 @@ struct i915_fbc { } no_fbc_reason; }; +struct i915_drrs { + struct intel_connector *connector; +}; + struct i915_psr { bool sink_support; bool source_ok; @@ -1497,6 +1501,7 @@ typedef struct drm_i915_private { struct timer_list hotplug_reenable_timer; struct i915_fbc fbc; + struct i915_drrs drrs; struct intel_opregion opregion; struct intel_vbt_data vbt; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 74f7d85..04fc64a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3255,6 +3255,7 @@ enum punit_power_well { #define PIPECONF_INTERLACED_DBL_ILK (4 << 21) /* ilk/snb only */ #define PIPECONF_PFIT_PF_INTERLACED_DBL_ILK (5 << 21) /* ilk/snb only */ #define PIPECONF_INTERLACE_MODE_MASK (7 << 21) +#define PIPECONF_EDP_RR_MODE_SWITCH (1 << 20) #define PIPECONF_CXSR_DOWNCLOCK (1<<16) #define PIPECONF_COLOR_RANGE_SELECT (1 << 13) #define PIPECONF_BPC_MASK (0x7 << 5) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f2735de..9640df1 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -736,6 +736,20 @@ intel_dp_set_clock(struct intel_encoder *encoder, } } +static void +intel_dp_set_m2_n2(struct intel_crtc *crtc, struct intel_link_m_n *m_n) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + enum transcoder transcoder = crtc->config.cpu_transcoder; + + I915_WRITE(PIPE_DATA_M2(transcoder), + TU_SIZE(m_n->tu) | m_n->gmch_m); + I915_WRITE(PIPE_DATA_N2(transcoder), m_n->gmch_n); + I915_WRITE(PIPE_LINK_M2(transcoder), m_n->link_m); + I915_WRITE(PIPE_LINK_N2(transcoder), m_n->link_n); +} + bool intel_dp_compute_config(struct intel_encoder *encoder, struct intel_crtc_config *pipe_config) @@ -840,6 +854,15 @@ found: pipe_config->port_clock, &pipe_config->dp_m_n); + if (intel_connector->panel.downclock_mode != NULL && + intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) { + intel_link_compute_m_n(bpp, lane_count, + intel_connector->panel.downclock_mode->clock, + pipe_config->port_clock, + &pipe_config->dp_m2_n2); + } + + intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); return true; @@ -3611,6 +3634,87 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_READ(pp_div_reg)); } +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; + struct intel_dp *intel_dp = NULL; + struct intel_crtc_config *config = NULL; + struct intel_crtc *intel_crtc = NULL; + struct intel_connector *intel_connector = dev_priv->drrs.connector; + u32 reg, val; + int index = 0; + + if (refresh_rate <= 0) { + DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n"); + return; + } + + if (intel_connector == NULL) { + DRM_DEBUG_KMS("DRRS supported for eDP only.\n"); + return; + } + + encoder = intel_attached_encoder(&intel_connector->base); + intel_dp = enc_to_intel_dp(&encoder->base); + intel_crtc = encoder->new_crtc; + + if (!intel_crtc) { + DRM_DEBUG_KMS("DRRS: intel_crtc not initialized\n"); + return; + } + + config = &intel_crtc->config; + + if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) { + DRM_DEBUG_KMS("Seamless DRRS not supported.\n"); + return; + } + + if (intel_connector->panel.fixed_mode->vrefresh == refresh_rate) + index = DRRS_HIGH_RR; + else + index = DRRS_LOW_RR; + + if (index == intel_dp->drrs_state.refresh_rate_type) { + DRM_DEBUG_KMS( + "DRRS requested for previously set RR...ignoring\n"); + return; + } + + if (!intel_crtc->active) { + DRM_DEBUG_KMS("eDP encoder disabled. CRTC not Active\n"); + return; + } + + if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) { + reg = PIPECONF(intel_crtc->config.cpu_transcoder); + val = I915_READ(reg); + if (index > DRRS_HIGH_RR) { + val |= PIPECONF_EDP_RR_MODE_SWITCH; + intel_dp_set_m2_n2(intel_crtc, &config->dp_m2_n2); + } else { + val &= ~PIPECONF_EDP_RR_MODE_SWITCH; + } + I915_WRITE(reg, val); + } + + /* + * mutex taken to ensure that there is no race between differnt + * drrs calls trying to update refresh rate. This scenario may occur + * in future when idleness detection based DRRS in kernel and + * possible calls from user space to set differnt RR are made. + */ + + mutex_lock(&intel_dp->drrs_state.mutex); + + intel_dp->drrs_state.refresh_rate_type = index; + + mutex_unlock(&intel_dp->drrs_state.mutex); + + DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate); +} + static struct drm_display_mode * intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector, @@ -3647,6 +3751,10 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port, if (downclock_mode != NULL && dev_priv->vbt.drrs_type == SEAMLESS_DRRS_SUPPORT) { + dev_priv->drrs.connector = intel_connector; + + mutex_init(&intel_dp->drrs_state.mutex); + intel_dp->drrs_state.type = dev_priv->vbt.drrs_type; intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d781165..46fc8b3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -305,6 +305,9 @@ struct intel_crtc_config { int pipe_bpp; struct intel_link_m_n dp_m_n; + /* m2_n2 for eDP downclock */ + struct intel_link_m_n dp_m2_n2; + /* * Frequence the dpll for the port should run at. Differs from the * adjusted dotclock e.g. for DP or 12bpc hdmi mode. This is also @@ -535,6 +538,7 @@ struct intel_dp { struct { enum drrs_support_type type; enum edp_drrs_refresh_rate_type refresh_rate_type; + struct mutex mutex; } drrs_state; }; @@ -789,7 +793,7 @@ void intel_edp_panel_off(struct intel_dp *intel_dp); void intel_edp_psr_enable(struct intel_dp *intel_dp); void intel_edp_psr_disable(struct intel_dp *intel_dp); void intel_edp_psr_update(struct drm_device *dev); - +void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate); /* intel_dsi.c */ bool intel_dsi_init(struct drm_device *dev);