@@ -3168,6 +3168,7 @@
#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)
@@ -3118,6 +3118,12 @@ intel_dp_set_property(struct drm_connector *connector,
if (ret)
return ret;
+ if (is_edp(intel_dp) && property ==
+ intel_dp->drrs_state.seamless_drrs_property) {
+ intel_dp_set_drrs_state(connector->dev, val);
+ return 0;
+ }
+
if (property == dev_priv->force_audio_property) {
int i = val;
bool has_audio;
@@ -3300,6 +3306,9 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
intel_dp->color_range_auto = true;
if (is_edp(intel_dp)) {
+ if (intel_dp->drrs_state.is_drrs_supported !=
+ DRRS_NOT_SUPPORTED)
+ intel_dp_attach_drrs_properties(intel_dp, connector);
drm_mode_create_scaling_mode_property(connector->dev);
drm_object_attach_property(
&connector->base,
@@ -3820,6 +3829,7 @@ intel_dp_find_drrs_lowclk(struct intel_digital_port *intel_dig_port,
dev_priv->vbt.drrs_mode == SEAMLESS_DRRS_SUPPORT) {
intel_dp_drrs_modelist_create(intel_dig_port, fixed_mode,
temp_mode);
+ mutex_init(&intel_dp->drrs_state.mutex);
intel_dp->drrs_state.is_drrs_supported =
dev_priv->vbt.drrs_mode;
intel_dp->drrs_state.drrs_refresh_rate_type = DRRS_HIGH_RR;
@@ -3829,3 +3839,153 @@ intel_dp_find_drrs_lowclk(struct intel_digital_port *intel_dig_port,
return;
}
+void
+intel_dp_attach_drrs_properties(struct intel_dp *intel_dp,
+ struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_property *prop;
+ const struct drm_prop_enum_list seamless_drrs_names[] = {
+ { intel_dp->drrs_state.refresh_rate_array[DRRS_HIGH_RR],
+ "high_rr"},
+ { intel_dp->drrs_state.refresh_rate_array[DRRS_LOW_RR],
+ "low_rr"},
+ /**
+ * add more entries if more DRRS RRs supported.
+ * The no.of entries should be equal to
+ * DRRS_MAX_RR.
+ */
+ };
+
+ prop = intel_dp->drrs_state.seamless_drrs_property;
+ if (prop == NULL) {
+ prop = drm_property_create_enum(dev, 0,
+ "seamless_drrs",
+ seamless_drrs_names,
+ ARRAY_SIZE(seamless_drrs_names));
+ if (prop == NULL)
+ return;
+ intel_dp->drrs_state.seamless_drrs_property = prop;
+ }
+ drm_object_attach_property(&connector->base, prop,
+ intel_dp->drrs_state.refresh_rate_array[0]);
+}
+
+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;
+
+ if (INTEL_INFO(dev)->gen >= 5 && INTEL_INFO(dev)->gen < 8) {
+ 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);
+ }
+ return;
+}
+
+void
+intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_mode_config *mode_config = &dev->mode_config;
+ 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 = NULL;
+ bool found_edp = false;
+ u32 reg, val;
+ int index = 0;
+
+ if (refresh_rate <= 0) {
+ DRM_INFO("Refresh rate should be positive non-zero.\n");
+ goto out;
+ }
+
+ list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+ if (encoder->type == INTEL_OUTPUT_EDP) {
+ intel_dp = enc_to_intel_dp(&encoder->base);
+ intel_crtc = encoder->new_crtc;
+ if (!intel_crtc) {
+ DRM_INFO("DRRS: intel_crtc not initialized\n");
+ goto out;
+ }
+ config = &intel_crtc->config;
+ intel_connector = intel_dp->attached_connector;
+ found_edp = true;
+ break;
+ }
+ }
+
+ if (!found_edp) {
+ DRM_INFO("DRRS supported for eDP only.\n");
+ goto out;
+ }
+
+ if (intel_dp->drrs_state.is_drrs_supported < SEAMLESS_DRRS_SUPPORT) {
+ DRM_INFO("Seamless DRRS not supported.\n");
+ goto out;
+ }
+
+ for (; index < DRRS_MAX_RR; index++) {
+ if (intel_dp->drrs_state.refresh_rate_array[index] ==
+ refresh_rate)
+ break;
+ }
+
+ if (index >= DRRS_MAX_RR) {
+ DRM_INFO("Invalid refresh rate requested for DRRS.\n");
+ goto out;
+ }
+
+ if (index == intel_dp->drrs_state.drrs_refresh_rate_type) {
+ DRM_INFO("DRRS requested for previously set RR...ignoring\n");
+ goto out;
+ }
+
+ if (!intel_crtc->active) {
+ DRM_INFO("eDP encoder has been disabled. CRTC not Active\n");
+ goto out;
+ }
+
+ mutex_lock(&intel_dp->drrs_state.mutex);
+
+ intel_link_compute_m_n(config->pipe_bpp, intel_dp->lane_count,
+ intel_dp->drrs_state.pixel_clock[index],
+ config->port_clock,
+ &intel_dp->drrs_state.dp_m2_n2);
+
+ if (INTEL_INFO(dev)->gen >= 8)
+ intel_dp_set_m2_n2(intel_crtc, &intel_dp->drrs_state.dp_m2_n2);
+ else {
+ /* Haswell and below */
+ reg = PIPECONF(intel_crtc->config.cpu_transcoder);
+ val = I915_READ(reg);
+ if (index > DRRS_HIGH_RR) {
+ if ((val & PIPECONF_EDP_RR_MODE_SWITCH) != 0) {
+ val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+ I915_WRITE(reg, val);
+ }
+ intel_dp_set_m2_n2(intel_crtc,
+ &intel_dp->drrs_state.dp_m2_n2);
+ val |= PIPECONF_EDP_RR_MODE_SWITCH;
+ } else
+ val &= ~PIPECONF_EDP_RR_MODE_SWITCH;
+ I915_WRITE(reg, val);
+ }
+
+ intel_dp->drrs_state.drrs_refresh_rate_type = index;
+ DRM_INFO("eDP Refresh Rate set to : %dHz\n",
+ intel_dp->drrs_state.refresh_rate_array[index]);
+
+ mutex_unlock(&intel_dp->drrs_state.mutex);
+
+out:
+ return;
+}
+
@@ -478,6 +478,9 @@ struct drrs_info {
int drrs_refresh_rate_type;
int refresh_rate_array[DRRS_MAX_RR];
int pixel_clock[DRRS_MAX_RR];
+ struct intel_link_m_n dp_m2_n2;
+ struct drm_property *seamless_drrs_property;
+ struct mutex mutex;
};
struct intel_dp {
@@ -824,6 +827,9 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
extern void intel_dp_find_drrs_lowclk(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector,
struct drm_display_mode *fixed_mode);
+extern void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
+extern void intel_dp_attach_drrs_properties(struct intel_dp *intel_dp,
+ struct drm_connector *connector);
/* intel_panel.c */
int intel_panel_init(struct intel_panel *panel,