public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
From: Ramalingam C <ramalingam.c@intel.com>
To: intel-gfx@lists.freedesktop.org, daniel.vetter@ffwll.ch,
	chris@chris-wilson.co.uk, rodrigo.vivi@intel.com
Cc: paulo.r.zanoni@intel.com
Subject: [RFC PATCH 06/18] drm/i915: VLV dsi drrs support
Date: Fri, 26 Jun 2015 19:21:50 +0530	[thread overview]
Message-ID: <1435326722-24633-7-git-send-email-ramalingam.c@intel.com> (raw)
In-Reply-To: <1435326722-24633-1-git-send-email-ramalingam.c@intel.com>

VLV related dsi drrs functions are implemented and registered
with generic dsi drrs.

This will provide the service to generic dsi drrs stack to calculate
the pll divider values and program the pll registers for DRRS
functionality.

Signed-off-by: Ramalingam C <ramalingam.c@intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h       |    4 +
 drivers/gpu/drm/i915/intel_dsi_drrs.c |   27 ++++
 drivers/gpu/drm/i915/intel_dsi_drrs.h |    5 +
 drivers/gpu/drm/i915/intel_dsi_pll.c  |  225 ++++++++++++++++++++++++++++++---
 4 files changed, 243 insertions(+), 18 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 0b979ad..9f1332b 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -2964,6 +2964,10 @@ enum skl_disp_power_wells {
 #define  VLV_EDP_PSR_IN_TRANS		(1<<7)
 #define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
 
+#define VERTICAL_ACTIVE_DISPLAY_MASK		(0xfff)
+#define VERTICAL_TOTAL_DISPLAY_OFFSET		16
+#define VERTICAL_TOTAL_DISPLAY_MASK		(0xfff<<16)
+
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 #define EDP_PSR_CTL(dev)			(EDP_PSR_BASE(dev) + 0)
diff --git a/drivers/gpu/drm/i915/intel_dsi_drrs.c b/drivers/gpu/drm/i915/intel_dsi_drrs.c
index 6ab0e9e..eb0758a 100644
--- a/drivers/gpu/drm/i915/intel_dsi_drrs.c
+++ b/drivers/gpu/drm/i915/intel_dsi_drrs.c
@@ -20,6 +20,23 @@
 #include "intel_drv.h"
 #include "intel_dsi.h"
 
+/*
+ * VLV and CHV platform code
+ */
+struct drrs_dsi_platform_ops vlv_dsi_drrs_ops = {
+	.configure_dsi_pll		= vlv_drrs_configure_dsi_pll,
+	.mnp_calculate_for_mode		= vlv_dsi_mnp_calculate_for_mode,
+};
+
+inline struct drrs_dsi_platform_ops *get_vlv_dsi_drrs_ops(void)
+{
+	return &vlv_dsi_drrs_ops;
+}
+
+/*
+ * Generic DSI DRRS code
+ */
+
 /* Work function for DSI deferred work */
 static void intel_mipi_drrs_work_fn(struct work_struct *__work)
 {
@@ -243,6 +260,16 @@ int intel_dsi_drrs_init(struct i915_drrs *drrs,
 
 	panel->target_mode = NULL;
 
+	if (IS_VALLEYVIEW(intel_encoder->base.dev)) {
+
+		/* VLV and CHV */
+		dsi_drrs->ops = get_vlv_dsi_drrs_ops();
+	} else {
+		DRM_ERROR("DRRS: Unsupported platform\n");
+		ret = -EINVAL;
+		goto out_err_2;
+	}
+
 	if (!dsi_drrs->ops || !dsi_drrs->ops->mnp_calculate_for_mode ||
 					!dsi_drrs->ops->configure_dsi_pll) {
 		DRM_ERROR("DSI platform ops not initialized\n");
diff --git a/drivers/gpu/drm/i915/intel_dsi_drrs.h b/drivers/gpu/drm/i915/intel_dsi_drrs.h
index 27736a0..02f76f0 100644
--- a/drivers/gpu/drm/i915/intel_dsi_drrs.h
+++ b/drivers/gpu/drm/i915/intel_dsi_drrs.h
@@ -58,4 +58,9 @@ struct dsi_drrs {
 };
 
 extern inline struct drrs_encoder_ops *get_intel_dsi_drrs_ops(void);
+int vlv_dsi_mnp_calculate_for_mode(struct intel_encoder *encoder,
+				struct dsi_mnp *dsi_mnp,
+				struct drm_display_mode *mode);
+int vlv_drrs_configure_dsi_pll(struct intel_encoder *encoder,
+						struct dsi_mnp *dsi_mnp);
 #endif /* INTEL_DSI_DRRS_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index ce5949f..46346b3 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -29,6 +29,7 @@
 #include "intel_drv.h"
 #include "i915_drv.h"
 #include "intel_dsi.h"
+#include "intel_drrs.h"
 
 #define DSI_HSS_PACKET_SIZE		4
 #define DSI_HSE_PACKET_SIZE		4
@@ -38,6 +39,8 @@
 #define DSI_HFP_PACKET_EXTRA_SIZE	6
 #define DSI_EOTP_PACKET_SIZE		4
 
+#define DSI_DRRS_PLL_CONFIG_TIMEOUT_MS	100
+
 static const u32 lfsr_converts[] = {
 	426, 469, 234, 373, 442, 221, 110, 311, 411,		/* 62 - 70 */
 	461, 486, 243, 377, 188, 350, 175, 343, 427, 213,	/* 71 - 80 */
@@ -256,39 +259,225 @@ static int dsi_calc_mnp(int target_dsi_clk, struct dsi_mnp *dsi_mnp)
 }
 
 /*
+ * vlv_dsi_pll_reg_configure:
+ *	Function to configure the CCK registers for PLL control and dividers
+ *
+ * pll		: Pll that is getting configure
+ * dsi_mnp	: Struct with divider values
+ * pll_enable	: Flag to indicate whether it is a fresh pll enable call or
+ *		  call on DRRS purpose
+ */
+static void vlv_dsi_pll_reg_configure(struct intel_encoder *encoder,
+				struct dsi_mnp *dsi_mnp, bool pll_enable)
+{
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+	if (!intel_crtc)
+		return;
+
+	if (pll_enable) {
+		vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
+
+		if (intel_dsi->ports & (1 << PORT_A))
+			dsi_mnp->dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+
+		if (intel_dsi->ports & (1 << PORT_C))
+			dsi_mnp->dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
+
+	} else {
+
+		/*
+		 * Updating the M1, N1, P1 div values alone on the
+		 * CCK registers. these new values are abstracted from
+		 * the dsi_mnp struction
+		 */
+		dsi_mnp->dsi_pll_ctrl =
+			(dsi_mnp->dsi_pll_ctrl & DSI_PLL_P1_POST_DIV_MASK) |
+			(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
+			~DSI_PLL_P1_POST_DIV_MASK);
+		dsi_mnp->dsi_pll_div = (dsi_mnp->dsi_pll_div &
+			(DSI_PLL_M1_DIV_MASK | DSI_PLL_N1_DIV_MASK)) |
+			(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_DIVIDER)
+			& ~(DSI_PLL_M1_DIV_MASK | DSI_PLL_N1_DIV_MASK));
+	}
+
+	DRM_DEBUG("dsi_pll: div %08x, ctrl %08x\n",
+				dsi_mnp->dsi_pll_div, dsi_mnp->dsi_pll_ctrl);
+
+	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, dsi_mnp->dsi_pll_div);
+	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp->dsi_pll_ctrl);
+}
+
+/*
+ * vlv_drrs_configure_dsi_pll:
+ *	Function to configure the PLL dividers and bring the new values
+ * into effect by power cycling the VCO. This power cycle is supposed
+ * to be completed within the vblank period. This is software implementation
+ * and depends on the CCK register access. Needs to be tested thoroughly.
+ *
+ * encoder	: target encoder
+ * dsi_mnp	: struct with pll divider values
+ */
+int vlv_drrs_configure_dsi_pll(struct intel_encoder *encoder,
+						struct dsi_mnp *dsi_mnp)
+{
+	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+	struct dsi_drrs *dsi_drrs = &intel_dsi->dsi_drrs;
+	struct intel_mipi_drrs_work *work = dsi_drrs->mipi_drrs_work;
+	enum pipe pipe;
+	u32 dsl_offset, dsl1, dsl2;
+	u32 vactive, vtotal, vblank, vblank_30_percent, vblank_70_percent;
+	unsigned long timeout;
+
+	if (!intel_crtc)
+		return -EPERM;
+
+	pipe = intel_crtc->pipe;
+	dsl_offset = PIPEDSL(pipe);
+
+	mutex_lock(&dev_priv->sb_lock);
+	vlv_dsi_pll_reg_configure(encoder, dsi_mnp, false);
+	mutex_unlock(&dev_priv->sb_lock);
+
+	DRM_DEBUG("dsi_mnp:: ctrl: 0x%X, div: 0x%X\n", dsi_mnp->dsi_pll_ctrl,
+							dsi_mnp->dsi_pll_div);
+
+	dsi_mnp->dsi_pll_ctrl &= (~DSI_PLL_VCO_EN);
+
+	vtotal = I915_READ(VTOTAL(pipe));
+	vactive = (vtotal & VERTICAL_ACTIVE_DISPLAY_MASK);
+	vtotal = (vtotal & VERTICAL_TOTAL_DISPLAY_MASK) >>
+					VERTICAL_TOTAL_DISPLAY_OFFSET;
+	vblank = vtotal - vactive;
+	vblank_30_percent = vactive + DIV_ROUND_UP((vblank * 3), 10);
+	vblank_70_percent = vactive + DIV_ROUND_UP((vblank * 7), 10);
+
+	timeout = jiffies + msecs_to_jiffies(DSI_DRRS_PLL_CONFIG_TIMEOUT_MS);
+
+tap_vblank_start:
+	do {
+		if (atomic_read(&work->abort_wait_loop) == 1) {
+			DRM_DEBUG_KMS("Aborting the pll update\n");
+			return -EPERM;
+		}
+
+		if (time_after(jiffies, timeout)) {
+			DRM_DEBUG("Timeout at waiting for Vblank\n");
+			return -ETIMEDOUT;
+		}
+
+		dsl1 = (I915_READ(dsl_offset) & DSL_LINEMASK_GEN3);
+
+	} while (dsl1 <= vactive || dsl1 > vblank_30_percent);
+
+	mutex_lock(&dev_priv->sb_lock);
+
+	dsl2 = I915_READ(dsl_offset) & DSL_LINEMASK_GEN3;
+
+	/*
+	 * Did we cross Vblank due to delay in mutex acquirement?
+	 * Keeping two scanlines in vblank as buffer for ops.
+	 */
+	if (dsl2 < vactive || dsl2 > vblank_70_percent) {
+		mutex_unlock(&dev_priv->sb_lock);
+		goto tap_vblank_start;
+	}
+
+	/* Toggle the VCO_EN to bring in the new dividers values */
+	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp->dsi_pll_ctrl);
+	dsi_mnp->dsi_pll_ctrl |= DSI_PLL_VCO_EN;
+	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp->dsi_pll_ctrl);
+
+	dsl2 = I915_READ(dsl_offset) & DSL_LINEMASK_GEN3;
+
+	mutex_unlock(&dev_priv->sb_lock);
+
+	if (wait_for(I915_READ(PIPECONF(pipe)) &
+					PIPECONF_DSI_PLL_LOCKED, 20)) {
+		DRM_ERROR("DSI PLL lock failed\n");
+		return -1;
+	}
+
+	DRM_DEBUG("PLL Changed between DSL: %u, %u\n", dsl1, dsl2);
+	DRM_DEBUG("DSI PLL locked\n");
+	return 0;
+}
+
+/*
+ * vlv_dsi_mnp_calculate_for_mode:
+ *	calculates the dsi_mnp values for a given mode
+ *
+ * encoder	: Target encoder
+ * dsi_mnp	: output struct to store divider values
+ * mode		: Input mode for which mnp is calculated
+ */
+int vlv_dsi_mnp_calculate_for_mode(struct intel_encoder *encoder,
+				struct dsi_mnp *dsi_mnp,
+				struct drm_display_mode *mode)
+{
+	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	u32 dsi_clk, ret;
+
+	dsi_clk = dsi_clk_from_pclk(intel_dsi, mode);
+
+	DRM_DEBUG("Mode->clk: %u, dsi_clk: %u\n", mode->clock, dsi_clk);
+
+	ret = dsi_calc_mnp(dsi_clk, dsi_mnp);
+	if (ret)
+		DRM_DEBUG("dsi_calc_mnp failed\n");
+	else
+		DRM_DEBUG("dsi_mnp: ctrl : 0x%X, div : 0x%X\n",
+						dsi_mnp->dsi_pll_ctrl,
+							dsi_mnp->dsi_pll_div);
+	return ret;
+}
+
+/*
  * XXX: The muxing and gating is hard coded for now. Need to add support for
  * sharing PLLs with two DSI outputs.
  */
 static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
 {
 	struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
 	struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+	struct dsi_drrs *dsi_drrs = &intel_dsi->dsi_drrs;
+	struct i915_drrs *drrs;
 	struct intel_connector *intel_connector = intel_dsi->attached_connector;
-	int ret;
-	struct dsi_mnp dsi_mnp;
-	u32 dsi_clk;
-
-	dsi_clk = dsi_clk_from_pclk(intel_dsi,
-				    intel_connector->panel.fixed_mode);
+	int ret, index;
 
-	ret = dsi_calc_mnp(dsi_clk, &dsi_mnp);
-	if (ret) {
-		DRM_DEBUG_KMS("dsi_calc_mnp failed\n");
+	ret = vlv_dsi_mnp_calculate_for_mode(encoder,
+					&dsi_drrs->mnp[DRRS_HIGH_RR],
+					intel_connector->panel.fixed_mode);
+	if (ret < 0) {
+		DRM_ERROR("dsi_mnp calculations failed\n");
 		return;
 	}
 
-	if (intel_dsi->ports & (1 << PORT_A))
-		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+	index = get_drrs_struct_index_for_crtc(dev_priv, intel_crtc);
+	if (index < 0)
+		return;
 
-	if (intel_dsi->ports & (1 << PORT_C))
-		dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
+	drrs = dev_priv->drrs[index];
+	if (!drrs || !drrs->has_drrs)
+		return;
 
-	DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
-		      dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl);
+	if (drrs && drrs->has_drrs &&
+				intel_connector->panel.downclock_mode) {
+		ret = vlv_dsi_mnp_calculate_for_mode(encoder,
+					&dsi_drrs->mnp[DRRS_LOW_RR],
+					intel_connector->panel.downclock_mode);
+		if (ret < 0) {
+			DRM_ERROR("dsi_mnp calculations failed\n");
+			return;
+		}
+	}
 
-	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, 0);
-	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_DIVIDER, dsi_mnp.dsi_pll_div);
-	vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, dsi_mnp.dsi_pll_ctrl);
+	vlv_dsi_pll_reg_configure(encoder, &dsi_drrs->mnp[DRRS_HIGH_RR], true);
 }
 
 void vlv_enable_dsi_pll(struct intel_encoder *encoder)
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

  parent reply	other threads:[~2015-06-26 14:00 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-06-26 13:51 [RFC PATCH 00/18] Generic DRRS implementation across the encoders Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 01/18] drm/i915: Removing the eDP specific DRRS implementation Ramalingam C
2015-06-26 16:50   ` Daniel Vetter
2015-06-29 11:24     ` Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 02/18] drm/i915: Generic DRRS state Machine Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 03/18] drm/i915: Addition of the drrs_min_vrefresh in VBT Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 04/18] drm/i915: Implementation of Generic DSI DRRS Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 05/18] drm/i915: Adjusting the pclk for dual link and burst mode Ramalingam C
2015-06-26 13:51 ` Ramalingam C [this message]
2015-06-26 13:51 ` [RFC PATCH 07/18] drm/i915: Generic eDP DRRS implementation Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 08/18] drm/i915: VLV eDP DRRS methods Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 09/18] drm/i915: Cloned mode check Ramalingam C
2015-06-26 17:08   ` Daniel Vetter
2015-06-26 17:14     ` Chris Wilson
2015-06-26 17:38       ` Daniel Vetter
2015-06-29 11:48     ` Ramalingam C
2015-06-29 16:16       ` Daniel Vetter
2015-06-26 13:51 ` [RFC PATCH 10/18] drm/i915: Initializing DRRS for all connectors Ramalingam C
2015-06-26 17:12   ` Daniel Vetter
2015-06-29 14:52     ` Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 11/18] drm/i915: Updating the crtc modes in DRRS transitions Ramalingam C
2015-06-26 17:11   ` Daniel Vetter
2015-06-29 14:58     ` Ramalingam C
2015-06-29 16:23       ` Daniel Vetter
2015-06-26 13:51 ` [RFC PATCH 12/18] drm/i915: Redesigning dp_set_m_n to receive divider values Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 13/18] drm/i915: MEDIA_RR support in general DRRS state machine Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 14/18] drm/i915: MEDIA_RR support in eDP DRRS module Ramalingam C
2015-06-26 13:51 ` [RFC PATCH 15/18] drm/i915: MEDIA_RR support in DSI " Ramalingam C
2015-06-26 13:52 ` [RFC PATCH 16/18] drm/i915: Filtering media playback DRRS requests Ramalingam C
2015-06-26 13:52 ` [RFC PATCH 17/18] drm/i915: Addition of downclock mode to connector modelist Ramalingam C
2015-06-26 13:52 ` [RFC PATCH 18/18] drm/i915: Connector property for DRRS capability Ramalingam C
2015-06-26 17:16 ` [RFC PATCH 00/18] Generic DRRS implementation across the encoders Daniel Vetter
2015-06-29 11:22   ` Ramalingam C
2015-06-29 16:27     ` Daniel Vetter
2015-06-30  6:29       ` Ramalingam C
2015-06-30 10:02         ` Daniel Vetter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1435326722-24633-7-git-send-email-ramalingam.c@intel.com \
    --to=ramalingam.c@intel.com \
    --cc=chris@chris-wilson.co.uk \
    --cc=daniel.vetter@ffwll.ch \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=paulo.r.zanoni@intel.com \
    --cc=rodrigo.vivi@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox