[PATCH 5/8] drm/i915/dp: DP audio API changes for MST

Timo Aaltonen tjaalton at ubuntu.com
Thu Jun 1 13:19:24 UTC 2017


From: "Pandiyan, Dhinakaran" <dhinakaran.pandiyan at intel.com>

BugLink: http://bugs.launchpad.net/bugs/1694665

DP MST provides the capability to send multiple video and audio streams
through a single port. This requires the API's between i915 and audio
drivers to distinguish between multiple audio capable displays that can be
connected to a port. Currently only the port identity is shared in the
APIs. This patch adds support for MST with an additional parameter
'int pipe'. The existing parameter 'port' does not change it's meaning.

pipe =
	MST	: display pipe that the stream originates from
	Non-MST	: -1

Affected APIs:
struct i915_audio_component_ops
-       int (*sync_audio_rate)(struct device *, int port, int rate);
+	int (*sync_audio_rate)(struct device *, int port, int pipe,
+	     int rate);

-       int (*get_eld)(struct device *, int port, bool *enabled,
-                       unsigned char *buf, int max_bytes);
+       int (*get_eld)(struct device *, int port, int pipe,
+		       bool *enabled, unsigned char *buf, int max_bytes);

struct i915_audio_component_audio_ops
-       void (*pin_eld_notify)(void *audio_ptr, int port);
+       void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);

This patch makes dummy changes in the audio drivers (thanks Libin) for
build to succeed. The audio side drivers will send the right 'pipe' values
for MST in patches that will follow.

v2:
Renamed the new API parameter from 'dev_id' to 'pipe'. (Jim, Ville)
Included Asoc driver API compatibility changes from Jeeja.
Added WARN_ON() for invalid pipe in get_saved_encoder(). (Takashi)
Added comment for av_enc_map[] definition. (Takashi)

v3:
Fixed logic error introduced while renaming 'dev_id' as 'pipe' (Ville)
Renamed get_saved_encoder() to get_saved_enc() to reduce line length

v4:
Rebased.
Parameter check for pipe < -1 values in get_saved_enc() (Ville)
Switched to for_each_pipe() in get_saved_enc() (Ville)
Renamed 'pipe' to 'dev_id' in audio side code (Takashi)

v5:
Included a comment for the dev_id arg. (Libin)

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan at intel.com>
Reviewed-by: Takashi Iwai <tiwai at suse.de>
Reviewed-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi at intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/1474488168-2343-1-git-send-email-dhinakaran.pandiyan@intel.com
(backported from commit f931894194b9395313d1c34f95ceb8d91f49790d)
Signed-off-by: Timo Aaltonen <timo.aaltonen at canonical.com>
---
 drivers/gpu/drm/i915/intel_audio.c |  8 +++-
 include/drm/i915_component.h       |  6 +--
 sound/pci/hda/patch_hdmi.c         |  4 +-
 ubuntu/i915/i915_drv.h             |  3 +-
 ubuntu/i915/intel_audio.c          | 94 ++++++++++++++++++++++++++------------
 5 files changed, 79 insertions(+), 36 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 7f45e73..c0483e4d 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -503,6 +503,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	enum port port = intel_dig_port->port;
+	enum pipe pipe = -1;
 
 	connector = drm_select_eld(encoder);
 	if (!connector)
@@ -530,7 +531,8 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
 	mutex_unlock(&dev_priv->av_mutex);
 
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						(int) port, (int) pipe);
 }
 
 /**
@@ -548,6 +550,7 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder);
 	enum port port = intel_dig_port->port;
+	enum pipe pipe = -1;
 
 	if (dev_priv->display.audio_codec_disable)
 		dev_priv->display.audio_codec_disable(intel_encoder);
@@ -557,7 +560,8 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
 	mutex_unlock(&dev_priv->av_mutex);
 
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						(int) port, (int) pipe);
 }
 
 /**
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index 90f7f23..559a984 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -45,7 +45,7 @@ struct i915_audio_component_ops {
 	void (*put_power)(struct device *);
 	void (*codec_wake_override)(struct device *, bool enable);
 	int (*get_cdclk_freq)(struct device *);
-	int (*sync_audio_rate)(struct device *, int port, int rate);
+	int (*sync_audio_rate)(struct device *, int port, int pipe, int rate);
 	/**
 	 * @get_eld: fill the audio state and ELD bytes for the given port
 	 *
@@ -58,7 +58,7 @@ struct i915_audio_component_ops {
 	 * Note that the returned size may be over @max_bytes.  Then it
 	 * implies that only a part of ELD has been copied to the buffer.
 	 */
-	int (*get_eld)(struct device *, int port, bool *enabled,
+	int (*get_eld)(struct device *, int port, int pipe, bool *enabled,
 		       unsigned char *buf, int max_bytes);
 };
 
@@ -70,7 +70,7 @@ struct i915_audio_component_audio_ops {
 	 * @audio_ptr:		HDA driver object
 	 * @port:	Which port has changed (PORTA / PORTB / PORTC etc)
 	 */
-	void (*pin_eld_notify)(void *audio_ptr, int port);
+	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
 };
 
 /**
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index f5c29e3..a9ac06c 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1827,7 +1827,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	/* Todo: add DP1.2 MST audio support later */
 	if (acomp && acomp->ops && acomp->ops->sync_audio_rate)
 		acomp->ops->sync_audio_rate(acomp->dev,
-				intel_pin2port(pin_nid),
+				intel_pin2port(pin_nid), -1,
 				runtime->rate);
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
@@ -2350,7 +2350,7 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
 	snd_hda_codec_set_power_to_all(codec, fg, power_state);
 }
 
-static void intel_pin_eld_notify(void *audio_ptr, int port)
+static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
 {
 	struct hda_codec *codec = audio_ptr;
 	int pin_nid = port + 0x04;
diff --git a/ubuntu/i915/i915_drv.h b/ubuntu/i915/i915_drv.h
index d6eed03..fd608bc 100644
--- a/ubuntu/i915/i915_drv.h
+++ b/ubuntu/i915/i915_drv.h
@@ -1995,7 +1995,8 @@ struct drm_i915_private {
 	/* perform PHY state sanity checks? */
 	bool chv_phy_assert[2];
 
-	struct intel_encoder *dig_port_map[I915_MAX_PORTS];
+	/* Used to save the pipe-to-encoder mapping for audio */
+	struct intel_encoder *av_enc_map[I915_MAX_PIPES];
 
 	/*
 	 * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
diff --git a/ubuntu/i915/intel_audio.c b/ubuntu/i915/intel_audio.c
index 6e55afc..3c32e68 100644
--- a/ubuntu/i915/intel_audio.c
+++ b/ubuntu/i915/intel_audio.c
@@ -491,6 +491,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	enum port port = intel_encoder->port;
+	enum pipe pipe = crtc->pipe;
 
 	connector = drm_select_eld(encoder);
 	if (!connector)
@@ -515,12 +516,18 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
 
 	mutex_lock(&dev_priv->av_mutex);
 	intel_encoder->audio_connector = connector;
+
 	/* referred in audio callbacks */
-	dev_priv->dig_port_map[port] = intel_encoder;
+	dev_priv->av_enc_map[pipe] = intel_encoder;
 	mutex_unlock(&dev_priv->av_mutex);
 
+	/* audio drivers expect pipe = -1 to indicate Non-MST cases */
+	if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+		pipe = -1;
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						 (int) port, (int) pipe);
 }
 
 /**
@@ -536,17 +543,24 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
 	struct drm_i915_private *dev_priv = encoder->dev->dev_private;
 	struct i915_audio_component *acomp = dev_priv->audio_component;
 	enum port port = intel_encoder->port;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+	enum pipe pipe = crtc->pipe;
 
 	if (dev_priv->display.audio_codec_disable)
 		dev_priv->display.audio_codec_disable(intel_encoder);
 
 	mutex_lock(&dev_priv->av_mutex);
 	intel_encoder->audio_connector = NULL;
-	dev_priv->dig_port_map[port] = NULL;
+	dev_priv->av_enc_map[pipe] = NULL;
 	mutex_unlock(&dev_priv->av_mutex);
 
+	/* audio drivers expect pipe = -1 to indicate Non-MST cases */
+	if (intel_encoder->type != INTEL_OUTPUT_DP_MST)
+		pipe = -1;
+
 	if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
-		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
+		acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr,
+						 (int) port, (int) pipe);
 }
 
 /**
@@ -623,15 +637,40 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
 	return ret;
 }
 
-static int i915_audio_component_sync_audio_rate(struct device *dev,
-						int port, int rate)
+static struct intel_encoder *get_saved_enc(struct drm_i915_private *dev_priv,
+					       int port, int pipe)
+{
+
+	if (WARN_ON(pipe >= I915_MAX_PIPES))
+		return NULL;
+
+	/* MST */
+	if (pipe >= 0)
+		return dev_priv->av_enc_map[pipe];
+
+	/* Non-MST */
+	for_each_pipe(dev_priv, pipe) {
+		struct intel_encoder *encoder;
+
+		encoder = dev_priv->av_enc_map[pipe];
+		if (encoder == NULL)
+			continue;
+
+		if (port == encoder->port)
+			return encoder;
+	}
+
+	return NULL;
+}
+
+static int i915_audio_component_sync_audio_rate(struct device *dev, int port,
+						int pipe, int rate)
 {
 	struct drm_i915_private *dev_priv = dev_to_i915(dev);
 	struct intel_encoder *intel_encoder;
 	struct intel_crtc *crtc;
 	struct drm_display_mode *mode;
 	struct i915_audio_component *acomp = dev_priv->audio_component;
-	enum pipe pipe = INVALID_PIPE;
 	u32 tmp;
 	int n;
 	int err = 0;
@@ -644,25 +683,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 		return 0;
 
 	mutex_lock(&dev_priv->av_mutex);
+
 	/* 1. get the pipe */
-	intel_encoder = dev_priv->dig_port_map[port];
-	/* intel_encoder might be NULL for DP MST */
+	intel_encoder = get_saved_enc(dev_priv, port, pipe);
 	if (!intel_encoder || !intel_encoder->base.crtc ||
 	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
-		DRM_DEBUG_KMS("no valid port %c\n", port_name(port));
+		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));
 		err = -ENODEV;
 		goto unlock;
 	}
+
+	/* pipe passed from the audio driver will be -1 for Non-MST case */
 	crtc = to_intel_crtc(intel_encoder->base.crtc);
 	pipe = crtc->pipe;
-	if (pipe == INVALID_PIPE) {
-		DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port));
-		err = -ENODEV;
-		goto unlock;
-	}
 
-	DRM_DEBUG_KMS("pipe %c connects port %c\n",
-				  pipe_name(pipe), port_name(port));
 	mode = &crtc->config->base.adjusted_mode;
 
 	/* port must be valid now, otherwise the pipe will be invalid */
@@ -697,7 +731,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
 }
 
 static int i915_audio_component_get_eld(struct device *dev, int port,
-					bool *enabled,
+					int pipe, bool *enabled,
 					unsigned char *buf, int max_bytes)
 {
 	struct drm_i915_private *dev_priv = dev_to_i915(dev);
@@ -706,16 +740,20 @@ static int i915_audio_component_get_eld(struct device *dev, int port,
 	int ret = -EINVAL;
 
 	mutex_lock(&dev_priv->av_mutex);
-	intel_encoder = dev_priv->dig_port_map[port];
-	/* intel_encoder might be NULL for DP MST */
-	if (intel_encoder) {
-		ret = 0;
-		*enabled = intel_encoder->audio_connector != NULL;
-		if (*enabled) {
-			eld = intel_encoder->audio_connector->eld;
-			ret = drm_eld_size(eld);
-			memcpy(buf, eld, min(max_bytes, ret));
-		}
+
+	intel_encoder = get_saved_enc(dev_priv, port, pipe);
+	if (!intel_encoder) {
+		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));
+		mutex_unlock(&dev_priv->av_mutex);
+		return ret;
+	}
+
+	ret = 0;
+	*enabled = intel_encoder->audio_connector != NULL;
+	if (*enabled) {
+		eld = intel_encoder->audio_connector->eld;
+		ret = drm_eld_size(eld);
+		memcpy(buf, eld, min(max_bytes, ret));
 	}
 
 	mutex_unlock(&dev_priv->av_mutex);
-- 
2.7.4





More information about the kernel-team mailing list