From patchwork Tue Nov 19 06:07:01 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: vandana.kannan@intel.com X-Patchwork-Id: 3200171 Return-Path: X-Original-To: patchwork-intel-gfx@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 6654DC045B for ; Tue, 19 Nov 2013 06:00:44 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5473A202F7 for ; Tue, 19 Nov 2013 06:00:43 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 3E0C020348 for ; Tue, 19 Nov 2013 06:00:42 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D0A3DFD4AC; Mon, 18 Nov 2013 22:00:36 -0800 (PST) X-Original-To: intel-gfx@lists.freedesktop.org Delivered-To: intel-gfx@lists.freedesktop.org Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by gabe.freedesktop.org (Postfix) with ESMTP id 96BE0FD47E for ; Mon, 18 Nov 2013 22:00:28 -0800 (PST) Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 18 Nov 2013 22:00:28 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.93,535,1378882800"; d="scan'208";a="437577583" Received: from vkannan-desktop.iind.intel.com ([10.223.25.35]) by orsmga002.jf.intel.com with ESMTP; 18 Nov 2013 22:00:24 -0800 From: Vandana Kannan To: intel-gfx@lists.freedesktop.org Date: Tue, 19 Nov 2013 11:37:01 +0530 Message-Id: <1384841225-4688-4-git-send-email-vandana.kannan@intel.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1384841225-4688-1-git-send-email-vandana.kannan@intel.com> References: <1384841225-4688-1-git-send-email-vandana.kannan@intel.com> Subject: [Intel-gfx] [PATCH 3/6] drm/i915: Add support for DRRS set property to switch RR X-BeenThere: intel-gfx@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Intel graphics driver community testing & development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: intel-gfx-bounces@lists.freedesktop.org Errors-To: intel-gfx-bounces@lists.freedesktop.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Pradeep Bhat This patch provides a set_property interface for user space to seamlessly switch between different DRRS refresh rates. The patch creates the property only if seamless DRRS is supported. It implements the support for computing Data & Link M/N for any given Refresh Rate and programs the same in 2nd M/N/TU for switching to different refresh rate dynamically using DRM set property IOCTL. The PIPECONF_EDP_RR_MODE_SWITCH bit helps toggle between alternate refresh rates programmed in 2nd M/N/TU registers. The user space should use this property to switch to any required refresh rate based on its policy. This feature enables user space in acheiving better power savings for certain use cases. This feature is for PV2 and not PV1. Signed-off-by: Pradeep Bhat Signed-off-by: Vandana Kannan --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_dp.c | 160 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 6 ++ 3 files changed, 167 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3f303ba..d1f8cc7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -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) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 46f202b..ff156d2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -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; +} + diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bd7964d..7c22fcf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -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,