public inbox for intel-gfx@lists.freedesktop.org
 help / color / mirror / Atom feed
From: libin.yang@linux.intel.com
To: intel-gfx@lists.freedesktop.org, jani.nikula@linux.intel.com,
	ville.syrjala@linux.intel.com, daniel.vetter@intel.com,
	tiwai@suse.de
Cc: Libin Yang <libin.yang@linux.intel.com>
Subject: [PATCH v4 1/3] drm/i915: set proper N/M in modeset
Date: Thu, 18 Aug 2016 14:42:26 +0800	[thread overview]
Message-ID: <1471502548-137544-2-git-send-email-libin.yang@linux.intel.com> (raw)
In-Reply-To: <1471502548-137544-1-git-send-email-libin.yang@linux.intel.com>

From: Libin Yang <libin.yang@linux.intel.com>

When modeset occurs and the LS_CLK is set to some
special values in DP mode, the N/M need to be set
manually if audio is playing. Otherwise the first
several seconds may be silent in audio playback.

The relationship of Maud and Naud is expressed in
the following equation:
Maud/Naud = 512 * fs / f_LS_Clk

Please refer VESA DisplayPort Standard spec for details.

Signed-off-by: Libin Yang <libin.yang@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h    |   7 ++
 drivers/gpu/drm/i915/intel_audio.c | 143 +++++++++++++++++++++++++++++++++----
 2 files changed, 136 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index d4adf28..239f0af 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -7337,6 +7337,13 @@ enum {
 #define _HSW_AUD_MISC_CTRL_B		0x65110
 #define HSW_AUD_MISC_CTRL(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_MISC_CTRL_A, _HSW_AUD_MISC_CTRL_B)
 
+#define _HSW_AUD_M_CTS_ENABLE_A		0x65028
+#define _HSW_AUD_M_CTS_ENABLE_B		0x65128
+#define HSW_AUD_M_CTS_ENABLE(pipe)		_MMIO_PIPE(pipe, _HSW_AUD_M_CTS_ENABLE_A, _HSW_AUD_M_CTS_ENABLE_B)
+#define   AUD_M_CTS_M_VALUE_INDEX	(1 << 21)
+#define   AUD_M_CTS_M_PROG_ENABLE	(1 << 20)
+#define   AUD_CONFIG_M_MASK		0xfffff
+
 #define _HSW_AUD_DIP_ELD_CTRL_ST_A	0x650b4
 #define _HSW_AUD_DIP_ELD_CTRL_ST_B	0x651b4
 #define HSW_AUD_DIP_ELD_CTRL(pipe)	_MMIO_PIPE(pipe, _HSW_AUD_DIP_ELD_CTRL_ST_A, _HSW_AUD_DIP_ELD_CTRL_ST_B)
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 85389cd..a8cec50 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -98,6 +98,38 @@ static const struct {
 	{ 192000, TMDS_297M, 20480, 247500 },
 };
 
+#define LC_540M 540000
+#define LC_270M 270000
+#define LC_162M 162000
+static const struct {
+	int sample_rate;
+	int clock;
+	u16 n;
+	u16 m;
+} aud_nm[] = {
+	{ 192000, LC_540M, 5625, 1024 },
+	{ 176400, LC_540M, 9375, 1568 },
+	{ 96000, LC_540M, 5625, 512 },
+	{ 88200, LC_540M, 9375, 784 },
+	{ 48000, LC_540M, 5625, 256 },
+	{ 44100, LC_540M, 9375, 392 },
+	{ 32000, LC_540M, 16875, 512 },
+	{ 192000, LC_270M, 5625, 2048 },
+	{ 176400, LC_270M, 9375, 3136 },
+	{ 96000, LC_270M, 5625, 1024 },
+	{ 88200, LC_270M, 9375, 1568 },
+	{ 48000, LC_270M, 5625, 512 },
+	{ 44100, LC_270M, 9375, 784 },
+	{ 32000, LC_270M, 16875, 1024 },
+	{ 192000, LC_162M, 3375, 2048 },
+	{ 176400, LC_162M, 5625, 3136 },
+	{ 96000, LC_162M, 3375, 1024 },
+	{ 88200, LC_162M, 5625, 1568 },
+	{ 48000, LC_162M, 3375, 512 },
+	{ 44100, LC_162M, 5625, 784 },
+	{ 32000, LC_162M, 10125, 1024 },
+};
+
 /* get AUD_CONFIG_PIXEL_CLOCK_HDMI_* value for mode */
 static u32 audio_config_hdmi_pixel_clock(const struct drm_display_mode *adjusted_mode)
 {
@@ -121,20 +153,50 @@ static u32 audio_config_hdmi_pixel_clock(const struct drm_display_mode *adjusted
 	return hdmi_audio_clock[i].config;
 }
 
-static int audio_config_get_n(const struct drm_display_mode *mode, int rate)
+static int audio_config_get_n(struct intel_crtc *crtc,
+			      const struct drm_display_mode *adjusted_mode,
+			      int rate)
+{
+	int i;
+
+	if (intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI)) {
+		for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) {
+			if ((rate == aud_ncts[i].sample_rate) &&
+			    (adjusted_mode->clock == aud_ncts[i].clock)) {
+				return aud_ncts[i].n;
+			}
+		}
+	}
+
+	if (intel_crtc_has_dp_encoder(crtc->config)) {
+		for (i = 0; i < ARRAY_SIZE(aud_nm); i++) {
+			if ((rate == aud_nm[i].sample_rate) &&
+			    (crtc->config->port_clock == aud_nm[i].clock)) {
+				return aud_nm[i].n;
+			}
+		}
+	}
+	return 0;
+}
+
+static int audio_config_get_m(struct intel_crtc *crtc, int rate)
 {
 	int i;
 
-	for (i = 0; i < ARRAY_SIZE(aud_ncts); i++) {
-		if ((rate == aud_ncts[i].sample_rate) &&
-			(mode->clock == aud_ncts[i].clock)) {
-			return aud_ncts[i].n;
+	if (intel_crtc_has_dp_encoder(crtc->config)) {
+		for (i = 0; i < ARRAY_SIZE(aud_nm); i++) {
+			if ((rate == aud_nm[i].sample_rate) &&
+			    (crtc->config->port_clock == aud_nm[i].clock)) {
+				return aud_nm[i].m;
+			}
 		}
 	}
+
 	return 0;
 }
 
-static uint32_t audio_config_setup_n_reg(int n, uint32_t val)
+static uint32_t audio_config_setup_n_reg(struct intel_crtc *crtc,
+					 int n, uint32_t val)
 {
 	int n_low, n_up;
 	uint32_t tmp = val;
@@ -145,17 +207,65 @@ static uint32_t audio_config_setup_n_reg(int n, uint32_t val)
 	tmp |= ((n_up << AUD_CONFIG_UPPER_N_SHIFT) |
 			(n_low << AUD_CONFIG_LOWER_N_SHIFT) |
 			AUD_CONFIG_N_PROG_ENABLE);
+	if (intel_crtc_has_dp_encoder(crtc->config))
+		tmp |= AUD_CONFIG_N_VALUE_INDEX;
+	else
+		tmp &= ~AUD_CONFIG_N_VALUE_INDEX;
+	return tmp;
+}
+
+static uint32_t audio_config_setup_m_reg(struct intel_crtc *crtc,
+					 int m, uint32_t val)
+{
+	uint32_t tmp = val;
+
+	tmp &= ~AUD_CONFIG_M_MASK;
+	tmp |= m;
+	tmp |= AUD_M_CTS_M_VALUE_INDEX;
+	tmp |= AUD_M_CTS_M_PROG_ENABLE;
+
 	return tmp;
 }
 
+static void audio_m_cts_setup(struct drm_device *dev,
+			      struct intel_crtc *crtc, int rate)
+{
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	uint32_t tmp, m;
+	/* pipe should be checked in the caller */
+	enum pipe pipe = crtc->pipe;
+
+	if (intel_crtc_has_dp_encoder(crtc->config)) {
+		/* setup m value for DP */
+		m = audio_config_get_m(crtc, rate);
+		if (m == 0)
+			return;
+		tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
+		tmp = audio_config_setup_m_reg(crtc, m, tmp);
+		I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
+	} else {
+		/* clear cts for HDMI */
+		tmp = I915_READ(HSW_AUD_M_CTS_ENABLE(pipe));
+		tmp &= ~AUD_CONFIG_M_MASK;
+		tmp &= ~AUD_M_CTS_M_VALUE_INDEX;
+		tmp |= AUD_M_CTS_M_PROG_ENABLE;
+		I915_WRITE(HSW_AUD_M_CTS_ENABLE(pipe), tmp);
+	}
+}
+
 /* check whether N/CTS/M need be set manually */
 static bool audio_rate_need_prog(struct intel_crtc *crtc,
-				 const struct drm_display_mode *mode)
+				 const struct drm_display_mode *adjusted_mode)
 {
-	if (((mode->clock == TMDS_297M) ||
-		 (mode->clock == TMDS_296M)) &&
+	if (((adjusted_mode->clock == TMDS_297M) ||
+		 (adjusted_mode->clock == TMDS_296M)) &&
 		intel_crtc_has_type(crtc->config, INTEL_OUTPUT_HDMI))
 		return true;
+	else if (((crtc->config->port_clock == LC_540M) ||
+		  (crtc->config->port_clock == LC_270M) ||
+		  (crtc->config->port_clock == LC_162M)) &&
+		  intel_crtc_has_dp_encoder(crtc->config))
+		return true;
 	else
 		return false;
 }
@@ -343,15 +453,17 @@ static void hsw_audio_codec_enable(struct drm_connector *connector,
 			DRM_ERROR("invalid port: %d\n", port);
 			rate = 0;
 		}
-		n = audio_config_get_n(adjusted_mode, rate);
+		n = audio_config_get_n(intel_crtc, adjusted_mode, rate);
 		if (n != 0)
-			tmp = audio_config_setup_n_reg(n, tmp);
+			tmp = audio_config_setup_n_reg(intel_crtc, n, tmp);
 		else
 			DRM_DEBUG_KMS("no suitable N value is found\n");
 	}
 
 	I915_WRITE(HSW_AUD_CFG(pipe), tmp);
 
+	audio_m_cts_setup(connector->dev, intel_crtc, rate);
+
 	mutex_unlock(&dev_priv->av_mutex);
 }
 
@@ -658,7 +770,8 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 	intel_encoder = dev_priv->dig_port_map[port];
 	/* intel_encoder might be NULL for DP MST */
 	if (!intel_encoder || !intel_encoder->base.crtc ||
-	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
+	    ((intel_encoder->type != INTEL_OUTPUT_HDMI) &&
+	     (intel_encoder->type != INTEL_OUTPUT_DP))) {
 		DRM_DEBUG_KMS("no valid port %c\n", port_name(port));
 		err = -ENODEV;
 		goto unlock;
@@ -686,7 +799,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 		goto unlock;
 	}
 
-	n = audio_config_get_n(mode, rate);
+	n = audio_config_get_n(crtc, mode, rate);
 	if (n == 0) {
 		DRM_DEBUG_KMS("Using automatic mode for N value on port %c\n",
 					  port_name(port));
@@ -698,9 +811,11 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 
 	/* 3. set the N/CTS/M */
 	tmp = I915_READ(HSW_AUD_CFG(pipe));
-	tmp = audio_config_setup_n_reg(n, tmp);
+	tmp = audio_config_setup_n_reg(crtc, n, tmp);
 	I915_WRITE(HSW_AUD_CFG(pipe), tmp);
 
+	audio_m_cts_setup(dev_get_drvdata(dev), crtc, pipe);
+
  unlock:
 	mutex_unlock(&dev_priv->av_mutex);
 	i915_audio_component_put_power(dev);
-- 
1.9.1

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

  reply	other threads:[~2016-08-18  6:46 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-18  6:42 [PATCH v4 0/3] drm/i915: fix some audio support 4K resolution issues libin.yang
2016-08-18  6:42 ` libin.yang [this message]
2016-08-18  6:42 ` [PATCH v4 2/3] drm/i915: set proper N/MCTS on more platforms libin.yang
2016-08-18  6:42 ` [PATCH v4 3/3] drm/i915: HDMI audio gets the TMDS clock by crtc_clock libin.yang
2016-08-18  8:29 ` ✗ Ro.CI.BAT: failure for drm/i915: fix some audio support 4K resolution issues Patchwork
2016-08-22  1:15 ` [PATCH v4 0/3] " Yang, Libin
2016-08-24  5:35   ` Yang, Libin
2016-08-24  5:52     ` Daniel Vetter
2016-08-24  6:10       ` Yang, Libin
2016-09-12  3:12     ` Yang, Libin
2016-09-21 18:39       ` Jani Nikula
2016-09-22  5:36         ` Yang, Libin
2016-09-22  5:49           ` Jani Nikula
2016-09-22  7:45             ` Jani Nikula
2016-09-22  7:52               ` Yang, Libin
2016-09-23  5:59               ` Yang, Libin

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=1471502548-137544-2-git-send-email-libin.yang@linux.intel.com \
    --to=libin.yang@linux.intel.com \
    --cc=daniel.vetter@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=jani.nikula@linux.intel.com \
    --cc=tiwai@suse.de \
    --cc=ville.syrjala@linux.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