diff mbox

[v3] drm/i915/dp: DP audio API changes for MST

Message ID 1470858117-2321-1-git-send-email-dhinakaran.pandiyan@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Dhinakaran Pandiyan Aug. 10, 2016, 7:41 p.m. UTC
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 (Libin) for build to
succeed. The audio side drivers will send the right 'pipe' values 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

Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h    |  3 +-
 drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------
 include/drm/i915_component.h       |  6 +--
 include/sound/hda_i915.h           | 11 +++--
 sound/hda/hdac_i915.c              |  9 ++--
 sound/pci/hda/patch_hdmi.c         |  7 +--
 sound/soc/codecs/hdac_hdmi.c       |  2 +-
 7 files changed, 86 insertions(+), 45 deletions(-)

Comments

Ville Syrjala Aug. 11, 2016, 6:26 a.m. UTC | #1
On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:
> 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 (Libin) for build to
> succeed. The audio side drivers will send the right 'pipe' values 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
> 
> Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> ---
>  drivers/gpu/drm/i915/i915_drv.h    |  3 +-
>  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------
>  include/drm/i915_component.h       |  6 +--
>  include/sound/hda_i915.h           | 11 +++--
>  sound/hda/hdac_i915.c              |  9 ++--
>  sound/pci/hda/patch_hdmi.c         |  7 +--
>  sound/soc/codecs/hdac_hdmi.c       |  2 +-
>  7 files changed, 86 insertions(+), 45 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index c36d176..8e4a88f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
> index ef20875..a7467ea 100644
> --- a/drivers/gpu/drm/i915/intel_audio.c
> +++ b/drivers/gpu/drm/i915/intel_audio.c
> @@ -500,6 +500,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 = crtc->pipe;
>  
>  	connector = drm_select_eld(encoder);
>  	if (!connector)
> @@ -524,12 +525,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);
>  }
>  
>  /**
> @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
>  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
>  {
>  	struct drm_encoder *encoder = &intel_encoder->base;
> +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
>  	struct drm_device *dev = encoder->dev;
>  	struct drm_i915_private *dev_priv = to_i915(dev);
>  	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 = 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);
>  }
>  
>  /**
> @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
>  	return dev_priv->cdclk_freq;
>  }
>  
> -static int i915_audio_component_sync_audio_rate(struct device *dev,
> -						int port, int rate)
> +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],
> +					       int port, int pipe)
> +{
> +	struct drm_encoder *encoder;
> +
> +	if (WARN_ON(pipe >= I915_MAX_PIPES))
> +		return NULL;
> +
> +	/* MST */
> +	if (pipe != -1)

I'd make that < 0

> +		return av_enc_map[pipe];
> +
> +	/* Non-MST */
> +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {

for_each_pipe() would be nicer.

> +		if (!av_enc_map[pipe])
> +			continue;
> +
> +		encoder = &av_enc_map[pipe]->base;
> +		if (port == enc_to_dig_port(encoder)->port)
> +			return av_enc_map[pipe];
> +	}
> +
> +	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;
> @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
>  
>  	i915_audio_component_get_power(dev);
>  	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->av_enc_map, port, pipe);
>  	if (!intel_encoder || !intel_encoder->base.crtc ||
>  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {

Did we have a followup planned to deal with MST here? I know there's
that SST M/N patch floating around, but I think we'll want it for MST
too.

> -		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 */
> @@ -708,7 +741,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);
> @@ -717,16 +750,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->av_enc_map, port, pipe);
> +	if (!intel_encoder) {
> +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));

Print the pipe name too, if we have a valid pipe?

> +		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);
> diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
> index b46fa0e..545c6e0 100644
> --- a/include/drm/i915_component.h
> +++ b/include/drm/i915_component.h
> @@ -64,7 +64,7 @@ struct i915_audio_component_ops {
>  	 * Called from audio driver. After audio driver sets the
>  	 * sample rate, it will call this function to set n/cts
>  	 */
> -	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
>  	 *
> @@ -77,7 +77,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);
>  };
>  
> @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {
>  	 * status accordingly (even when the HDA controller is in power save
>  	 * mode).
>  	 */
> -	void (*pin_eld_notify)(void *audio_ptr, int port);
> +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
>  };
>  
>  /**
> diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
> index 796cabf..07fd64e 100644
> --- a/include/sound/hda_i915.h
> +++ b/include/sound/hda_i915.h
> @@ -10,8 +10,9 @@
>  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
>  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
>  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
> -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);
> -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> +			     int pipe, int rate);
> +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
>  			   bool *audio_enabled, char *buffer, int max_bytes);
>  int snd_hdac_i915_init(struct hdac_bus *bus);
>  int snd_hdac_i915_exit(struct hdac_bus *bus);
> @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
>  {
>  }
>  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
> -					   hda_nid_t nid, int rate)
> +					   hda_nid_t nid, int pipe, int rate)
>  {
>  	return 0;
>  }
>  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> -					 bool *audio_enabled, char *buffer,
> -					 int max_bytes)
> +					 int pipe, bool *audio_enabled,
> +					 char *buffer, int max_bytes)
>  {
>  	return -ENODEV;
>  }
> diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
> index c9af022..b99994b 100644
> --- a/sound/hda/hdac_i915.c
> +++ b/sound/hda/hdac_i915.c
> @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
>   * This function sets N/CTS value based on the given sample rate.
>   * Returns zero for success, or a negative error code.
>   */
> -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> +			     int pipe, int rate)

I thought you'd still want to call it 'dev_id' on the hda side, and just
do the dev_id->pipe conversion here next to the pin->port conversion?
Just figured that would be less confusing for people who are just familiar
with hda and not i915.

Anyways, the patch looks pretty good to me from the i915 POV. Whether
you want to do those small changes I proposed is up to you, and either
way the i915 parts are
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

>  {
>  	struct hdac_bus *bus = codec->bus;
>  	struct i915_audio_component *acomp = bus->audio_component;
> @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
>  	port = pin2port(codec, nid);
>  	if (port < 0)
>  		return -EINVAL;
> -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
> +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
>  }
>  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
>  
> @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
>   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
>   * that only a part of ELD bytes have been fetched.
>   */
> -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
>  			   bool *audio_enabled, char *buffer, int max_bytes)
>  {
>  	struct hdac_bus *bus = codec->bus;
> @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
>  	port = pin2port(codec, nid);
>  	if (port < 0)
>  		return -EINVAL;
> -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
> +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
>  				   buffer, max_bytes);
>  }
>  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
> diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> index d0d5ad8..67890df 100644
> --- a/sound/pci/hda/patch_hdmi.c
> +++ b/sound/pci/hda/patch_hdmi.c
> @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
>  
>  	mutex_lock(&per_pin->lock);
>  	eld->monitor_present = false;
> -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
> +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
>  				      &eld->monitor_present, eld->eld_buffer,
>  				      ELD_MAX_SIZE);
>  	if (size > 0) {
> @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
>  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
>  	/* Todo: add DP1.2 MST audio support later */
>  	if (codec_has_acomp(codec))
> -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
> +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
> +					 runtime->rate);
>  
>  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
>  	mutex_lock(&per_pin->lock);
> @@ -2285,7 +2286,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;
> diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
> index 2abb742..cf57ab3 100644
> --- a/sound/soc/codecs/hdac_hdmi.c
> +++ b/sound/soc/codecs/hdac_hdmi.c
> @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
>  	return hdac_hdmi_init_dai_map(edev);
>  }
>  
> -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
> +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
>  {
>  	struct hdac_ext_device *edev = aptr;
>  	struct hdac_hdmi_priv *hdmi = edev->private_data;
> -- 
> 2.5.0
Dhinakaran Pandiyan Aug. 11, 2016, 7:10 a.m. UTC | #2
On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:
> On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:

> > 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 (Libin) for build to

> > succeed. The audio side drivers will send the right 'pipe' values 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

> > 

> > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

> > ---

> >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-

> >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------

> >  include/drm/i915_component.h       |  6 +--

> >  include/sound/hda_i915.h           | 11 +++--

> >  sound/hda/hdac_i915.c              |  9 ++--

> >  sound/pci/hda/patch_hdmi.c         |  7 +--

> >  sound/soc/codecs/hdac_hdmi.c       |  2 +-

> >  7 files changed, 86 insertions(+), 45 deletions(-)

> > 

> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h

> > index c36d176..8e4a88f 100644

> > --- a/drivers/gpu/drm/i915/i915_drv.h

> > +++ b/drivers/gpu/drm/i915/i915_drv.h

> > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c

> > index ef20875..a7467ea 100644

> > --- a/drivers/gpu/drm/i915/intel_audio.c

> > +++ b/drivers/gpu/drm/i915/intel_audio.c

> > @@ -500,6 +500,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 = crtc->pipe;

> >  

> >  	connector = drm_select_eld(encoder);

> >  	if (!connector)

> > @@ -524,12 +525,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);

> >  }

> >  

> >  /**

> > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)

> >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)

> >  {

> >  	struct drm_encoder *encoder = &intel_encoder->base;

> > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);

> >  	struct drm_device *dev = encoder->dev;

> >  	struct drm_i915_private *dev_priv = to_i915(dev);

> >  	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 = 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);

> >  }

> >  

> >  /**

> > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)

> >  	return dev_priv->cdclk_freq;

> >  }

> >  

> > -static int i915_audio_component_sync_audio_rate(struct device *dev,

> > -						int port, int rate)

> > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],

> > +					       int port, int pipe)

> > +{

> > +	struct drm_encoder *encoder;

> > +

> > +	if (WARN_ON(pipe >= I915_MAX_PIPES))

> > +		return NULL;

> > +

> > +	/* MST */

> > +	if (pipe != -1)

> 

> I'd make that < 0

> 

Thanks for reviewing.
Do you mean this? - handle the non-MST branch first with 

if (pipe < 0){ 
	for_each_pipe(){

		...
	}
}
else 
	return av_enc_map[pipe];

> > +		return av_enc_map[pipe];

> > +

> > +	/* Non-MST */

> > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {

> 

> for_each_pipe() would be nicer.

> 

> > +		if (!av_enc_map[pipe])

> > +			continue;

> > +

> > +		encoder = &av_enc_map[pipe]->base;

> > +		if (port == enc_to_dig_port(encoder)->port)

> > +			return av_enc_map[pipe];

> > +	}

> > +

> > +	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;

> > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,

> >  

> >  	i915_audio_component_get_power(dev);

> >  	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->av_enc_map, port, pipe);

> >  	if (!intel_encoder || !intel_encoder->base.crtc ||

> >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {

> 

> Did we have a followup planned to deal with MST here? I know there's

> that SST M/N patch floating around, but I think we'll want it for MST

> too.

> 

Looks like Libin Yang is working on the DP patch, I will check with him.

> > -		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 */

> > @@ -708,7 +741,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);

> > @@ -717,16 +750,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->av_enc_map, port, pipe);

> > +	if (!intel_encoder) {

> > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));

> 

> Print the pipe name too, if we have a valid pipe?

> 

> > +		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);

> > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h

> > index b46fa0e..545c6e0 100644

> > --- a/include/drm/i915_component.h

> > +++ b/include/drm/i915_component.h

> > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {

> >  	 * Called from audio driver. After audio driver sets the

> >  	 * sample rate, it will call this function to set n/cts

> >  	 */

> > -	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

> >  	 *

> > @@ -77,7 +77,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);

> >  };

> >  

> > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {

> >  	 * status accordingly (even when the HDA controller is in power save

> >  	 * mode).

> >  	 */

> > -	void (*pin_eld_notify)(void *audio_ptr, int port);

> > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);

> >  };

> >  

> >  /**

> > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h

> > index 796cabf..07fd64e 100644

> > --- a/include/sound/hda_i915.h

> > +++ b/include/sound/hda_i915.h

> > @@ -10,8 +10,9 @@

> >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);

> >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);

> >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);

> > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);

> > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > +			     int pipe, int rate);

> > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> >  			   bool *audio_enabled, char *buffer, int max_bytes);

> >  int snd_hdac_i915_init(struct hdac_bus *bus);

> >  int snd_hdac_i915_exit(struct hdac_bus *bus);

> > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)

> >  {

> >  }

> >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,

> > -					   hda_nid_t nid, int rate)

> > +					   hda_nid_t nid, int pipe, int rate)

> >  {

> >  	return 0;

> >  }

> >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > -					 bool *audio_enabled, char *buffer,

> > -					 int max_bytes)

> > +					 int pipe, bool *audio_enabled,

> > +					 char *buffer, int max_bytes)

> >  {

> >  	return -ENODEV;

> >  }

> > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c

> > index c9af022..b99994b 100644

> > --- a/sound/hda/hdac_i915.c

> > +++ b/sound/hda/hdac_i915.c

> > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)

> >   * This function sets N/CTS value based on the given sample rate.

> >   * Returns zero for success, or a negative error code.

> >   */

> > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > +			     int pipe, int rate)

> 

> I thought you'd still want to call it 'dev_id' on the hda side, and just

> do the dev_id->pipe conversion here next to the pin->port conversion?

> Just figured that would be less confusing for people who are just familiar

> with hda and not i915.

> 

Yeah, that makes sense. 

> Anyways, the patch looks pretty good to me from the i915 POV. Whether

> you want to do those small changes I proposed is up to you, and either

> way the i915 parts are

> Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> 


I have assumed enc_to_dig_port() works for MST encoders. Do you think
it's good idea to have this
https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html
now?
 
> >  {

> >  	struct hdac_bus *bus = codec->bus;

> >  	struct i915_audio_component *acomp = bus->audio_component;

> > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> >  	port = pin2port(codec, nid);

> >  	if (port < 0)

> >  		return -EINVAL;

> > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);

> > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);

> >  }

> >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> >  

> > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies

> >   * that only a part of ELD bytes have been fetched.

> >   */

> > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> >  			   bool *audio_enabled, char *buffer, int max_bytes)

> >  {

> >  	struct hdac_bus *bus = codec->bus;

> > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> >  	port = pin2port(codec, nid);

> >  	if (port < 0)

> >  		return -EINVAL;

> > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,

> > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,

> >  				   buffer, max_bytes);

> >  }

> >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);

> > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c

> > index d0d5ad8..67890df 100644

> > --- a/sound/pci/hda/patch_hdmi.c

> > +++ b/sound/pci/hda/patch_hdmi.c

> > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,

> >  

> >  	mutex_lock(&per_pin->lock);

> >  	eld->monitor_present = false;

> > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,

> > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,

> >  				      &eld->monitor_present, eld->eld_buffer,

> >  				      ELD_MAX_SIZE);

> >  	if (size > 0) {

> > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,

> >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */

> >  	/* Todo: add DP1.2 MST audio support later */

> >  	if (codec_has_acomp(codec))

> > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);

> > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,

> > +					 runtime->rate);

> >  

> >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);

> >  	mutex_lock(&per_pin->lock);

> > @@ -2285,7 +2286,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;

> > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c

> > index 2abb742..cf57ab3 100644

> > --- a/sound/soc/codecs/hdac_hdmi.c

> > +++ b/sound/soc/codecs/hdac_hdmi.c

> > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,

> >  	return hdac_hdmi_init_dai_map(edev);

> >  }

> >  

> > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)

> > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)

> >  {

> >  	struct hdac_ext_device *edev = aptr;

> >  	struct hdac_hdmi_priv *hdmi = edev->private_data;

> > -- 

> > 2.5.0

>
Takashi Iwai Aug. 11, 2016, 7:23 a.m. UTC | #3
On Thu, 11 Aug 2016 08:26:31 +0200,
Ville Syrjälä wrote:
> 
> > --- a/sound/hda/hdac_i915.c
> > +++ b/sound/hda/hdac_i915.c
> > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
> >   * This function sets N/CTS value based on the given sample rate.
> >   * Returns zero for success, or a negative error code.
> >   */
> > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> > +			     int pipe, int rate)
> 
> I thought you'd still want to call it 'dev_id' on the hda side, and just
> do the dev_id->pipe conversion here next to the pin->port conversion?
> Just figured that would be less confusing for people who are just familiar
> with hda and not i915.

Agreed, it's more consistent to have a pair of the same terms
(pipe, port) vs (dev_id, nid).

Except for that, the changes in the audio side look trivial, and it's
probably better to go through drm tree, so feel free to take my ack:

Reviewed-by: Takashi Iwai <tiwai@suse.de>


thanks,

Takashi
Ville Syrjala Aug. 11, 2016, 7:39 a.m. UTC | #4
On Thu, Aug 11, 2016 at 07:10:39AM +0000, Pandiyan, Dhinakaran wrote:
> On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:
> > On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:
> > > 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 (Libin) for build to
> > > succeed. The audio side drivers will send the right 'pipe' values 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
> > > 
> > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-
> > >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------
> > >  include/drm/i915_component.h       |  6 +--
> > >  include/sound/hda_i915.h           | 11 +++--
> > >  sound/hda/hdac_i915.c              |  9 ++--
> > >  sound/pci/hda/patch_hdmi.c         |  7 +--
> > >  sound/soc/codecs/hdac_hdmi.c       |  2 +-
> > >  7 files changed, 86 insertions(+), 45 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > > index c36d176..8e4a88f 100644
> > > --- a/drivers/gpu/drm/i915/i915_drv.h
> > > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
> > > index ef20875..a7467ea 100644
> > > --- a/drivers/gpu/drm/i915/intel_audio.c
> > > +++ b/drivers/gpu/drm/i915/intel_audio.c
> > > @@ -500,6 +500,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 = crtc->pipe;
> > >  
> > >  	connector = drm_select_eld(encoder);
> > >  	if (!connector)
> > > @@ -524,12 +525,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);
> > >  }
> > >  
> > >  /**
> > > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
> > >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
> > >  {
> > >  	struct drm_encoder *encoder = &intel_encoder->base;
> > > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> > >  	struct drm_device *dev = encoder->dev;
> > >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > >  	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 = 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);
> > >  }
> > >  
> > >  /**
> > > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
> > >  	return dev_priv->cdclk_freq;
> > >  }
> > >  
> > > -static int i915_audio_component_sync_audio_rate(struct device *dev,
> > > -						int port, int rate)
> > > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],
> > > +					       int port, int pipe)
> > > +{
> > > +	struct drm_encoder *encoder;
> > > +
> > > +	if (WARN_ON(pipe >= I915_MAX_PIPES))
> > > +		return NULL;
> > > +
> > > +	/* MST */
> > > +	if (pipe != -1)
> > 
> > I'd make that < 0
> > 
> Thanks for reviewing.
> Do you mean this? - handle the non-MST branch first with 
> 
> if (pipe < 0){ 
> 	for_each_pipe(){
> 
> 		...
> 	}
> }
> else 
> 	return av_enc_map[pipe];

Sorry, no. I like your current code structure, so what I really meant
was 'pipe >= 0', so:

if (pipe >= 0)
	return ...

for_each_pipe()
	...
	

> 
> > > +		return av_enc_map[pipe];
> > > +
> > > +	/* Non-MST */
> > > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {
> > 
> > for_each_pipe() would be nicer.
> > 
> > > +		if (!av_enc_map[pipe])
> > > +			continue;
> > > +
> > > +		encoder = &av_enc_map[pipe]->base;
> > > +		if (port == enc_to_dig_port(encoder)->port)
> > > +			return av_enc_map[pipe];
> > > +	}
> > > +
> > > +	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;
> > > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
> > >  
> > >  	i915_audio_component_get_power(dev);
> > >  	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->av_enc_map, port, pipe);
> > >  	if (!intel_encoder || !intel_encoder->base.crtc ||
> > >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
> > 
> > Did we have a followup planned to deal with MST here? I know there's
> > that SST M/N patch floating around, but I think we'll want it for MST
> > too.
> > 
> Looks like Libin Yang is working on the DP patch, I will check with him.
> 
> > > -		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 */
> > > @@ -708,7 +741,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);
> > > @@ -717,16 +750,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->av_enc_map, port, pipe);
> > > +	if (!intel_encoder) {
> > > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));
> > 
> > Print the pipe name too, if we have a valid pipe?
> > 
> > > +		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);
> > > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
> > > index b46fa0e..545c6e0 100644
> > > --- a/include/drm/i915_component.h
> > > +++ b/include/drm/i915_component.h
> > > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {
> > >  	 * Called from audio driver. After audio driver sets the
> > >  	 * sample rate, it will call this function to set n/cts
> > >  	 */
> > > -	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
> > >  	 *
> > > @@ -77,7 +77,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);
> > >  };
> > >  
> > > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {
> > >  	 * status accordingly (even when the HDA controller is in power save
> > >  	 * mode).
> > >  	 */
> > > -	void (*pin_eld_notify)(void *audio_ptr, int port);
> > > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
> > >  };
> > >  
> > >  /**
> > > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
> > > index 796cabf..07fd64e 100644
> > > --- a/include/sound/hda_i915.h
> > > +++ b/include/sound/hda_i915.h
> > > @@ -10,8 +10,9 @@
> > >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
> > >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
> > >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
> > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);
> > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> > > +			     int pipe, int rate);
> > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
> > >  			   bool *audio_enabled, char *buffer, int max_bytes);
> > >  int snd_hdac_i915_init(struct hdac_bus *bus);
> > >  int snd_hdac_i915_exit(struct hdac_bus *bus);
> > > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
> > >  {
> > >  }
> > >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
> > > -					   hda_nid_t nid, int rate)
> > > +					   hda_nid_t nid, int pipe, int rate)
> > >  {
> > >  	return 0;
> > >  }
> > >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > -					 bool *audio_enabled, char *buffer,
> > > -					 int max_bytes)
> > > +					 int pipe, bool *audio_enabled,
> > > +					 char *buffer, int max_bytes)
> > >  {
> > >  	return -ENODEV;
> > >  }
> > > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
> > > index c9af022..b99994b 100644
> > > --- a/sound/hda/hdac_i915.c
> > > +++ b/sound/hda/hdac_i915.c
> > > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
> > >   * This function sets N/CTS value based on the given sample rate.
> > >   * Returns zero for success, or a negative error code.
> > >   */
> > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> > > +			     int pipe, int rate)
> > 
> > I thought you'd still want to call it 'dev_id' on the hda side, and just
> > do the dev_id->pipe conversion here next to the pin->port conversion?
> > Just figured that would be less confusing for people who are just familiar
> > with hda and not i915.
> > 
> Yeah, that makes sense. 
> 
> > Anyways, the patch looks pretty good to me from the i915 POV. Whether
> > you want to do those small changes I proposed is up to you, and either
> > way the i915 parts are
> > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> 
> I have assumed enc_to_dig_port() works for MST encoders. Do you think
> it's good idea to have this
> https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html
> now?

Oh I forgot about that part. I'm not really excited about that patch.
I'd prefer that people have to think a bit when dealing with MST
encoders, otherwise they might assume they work just like any other
encoder.

So I'd prefer that you explicitly handle the MST case when looking up
the encoder. For your audio use case, I think you just need the 'port'
information from the dig_port, no? I think making that part generic isn't
a huge problem since that way at least you're not getting your hands
 on a dig_port structure that you don't really own.

So you could almost use intel_ddi_get_encoder_port(), except using a
DDI specific function in generic code isn't very nice. We could extract
the generic part to a separate function, like so:

enum port intel_encoder_get_port(struct intel_encoder *encoder)
{
        switch (encoder->type) {
        case INTEL_OUTPUT_DP_MST:
                return enc_to_mst(&encoder->base)->primary->port;
        case INTEL_OUTPUT_DP:
        case INTEL_OUTPUT_EDP:
        case INTEL_OUTPUT_HDMI:
        case INTEL_OUTPUT_UNKNOWN:
                return enc_to_dig_port(&encoder->base)->port;
        default:
                MISSING_CASE(encoder->type);
                return PORT_A;
        }
}

enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)
{
        switch (encoder->type) {
        case INTEL_OUTPUT_ANALOG:
		return PORT_E;
        default:
		return intel_encoder_get_port(encoder);
        }
}

or you could just your own function for intel_audio.c at this time, like:

static enum port encoder_get_port(encoder)
{
	if (encoder->type == MST;
		return enc_to_mst()...;
	else
		return enc_to_dig_port()...;
}
	


>  
> > >  {
> > >  	struct hdac_bus *bus = codec->bus;
> > >  	struct i915_audio_component *acomp = bus->audio_component;
> > > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> > >  	port = pin2port(codec, nid);
> > >  	if (port < 0)
> > >  		return -EINVAL;
> > > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
> > > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
> > >  }
> > >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
> > >  
> > > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
> > >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
> > >   * that only a part of ELD bytes have been fetched.
> > >   */
> > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
> > >  			   bool *audio_enabled, char *buffer, int max_bytes)
> > >  {
> > >  	struct hdac_bus *bus = codec->bus;
> > > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > >  	port = pin2port(codec, nid);
> > >  	if (port < 0)
> > >  		return -EINVAL;
> > > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
> > > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
> > >  				   buffer, max_bytes);
> > >  }
> > >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
> > > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> > > index d0d5ad8..67890df 100644
> > > --- a/sound/pci/hda/patch_hdmi.c
> > > +++ b/sound/pci/hda/patch_hdmi.c
> > > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
> > >  
> > >  	mutex_lock(&per_pin->lock);
> > >  	eld->monitor_present = false;
> > > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
> > > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
> > >  				      &eld->monitor_present, eld->eld_buffer,
> > >  				      ELD_MAX_SIZE);
> > >  	if (size > 0) {
> > > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
> > >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
> > >  	/* Todo: add DP1.2 MST audio support later */
> > >  	if (codec_has_acomp(codec))
> > > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
> > > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
> > > +					 runtime->rate);
> > >  
> > >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
> > >  	mutex_lock(&per_pin->lock);
> > > @@ -2285,7 +2286,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;
> > > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
> > > index 2abb742..cf57ab3 100644
> > > --- a/sound/soc/codecs/hdac_hdmi.c
> > > +++ b/sound/soc/codecs/hdac_hdmi.c
> > > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
> > >  	return hdac_hdmi_init_dai_map(edev);
> > >  }
> > >  
> > > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
> > > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
> > >  {
> > >  	struct hdac_ext_device *edev = aptr;
> > >  	struct hdac_hdmi_priv *hdmi = edev->private_data;
> > > -- 
> > > 2.5.0
> > 
>
Dhinakaran Pandiyan Aug. 12, 2016, 4:28 a.m. UTC | #5
On Thu, 2016-08-11 at 10:39 +0300, Ville Syrjälä wrote:
> On Thu, Aug 11, 2016 at 07:10:39AM +0000, Pandiyan, Dhinakaran wrote:

> > On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:

> > > On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:

> > > > 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 (Libin) for build to

> > > > succeed. The audio side drivers will send the right 'pipe' values 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

> > > > 

> > > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

> > > > ---

> > > >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-

> > > >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------

> > > >  include/drm/i915_component.h       |  6 +--

> > > >  include/sound/hda_i915.h           | 11 +++--

> > > >  sound/hda/hdac_i915.c              |  9 ++--

> > > >  sound/pci/hda/patch_hdmi.c         |  7 +--

> > > >  sound/soc/codecs/hdac_hdmi.c       |  2 +-

> > > >  7 files changed, 86 insertions(+), 45 deletions(-)

> > > > 

> > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h

> > > > index c36d176..8e4a88f 100644

> > > > --- a/drivers/gpu/drm/i915/i915_drv.h

> > > > +++ b/drivers/gpu/drm/i915/i915_drv.h

> > > > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c

> > > > index ef20875..a7467ea 100644

> > > > --- a/drivers/gpu/drm/i915/intel_audio.c

> > > > +++ b/drivers/gpu/drm/i915/intel_audio.c

> > > > @@ -500,6 +500,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 = crtc->pipe;

> > > >  

> > > >  	connector = drm_select_eld(encoder);

> > > >  	if (!connector)

> > > > @@ -524,12 +525,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);

> > > >  }

> > > >  

> > > >  /**

> > > > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)

> > > >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)

> > > >  {

> > > >  	struct drm_encoder *encoder = &intel_encoder->base;

> > > > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);

> > > >  	struct drm_device *dev = encoder->dev;

> > > >  	struct drm_i915_private *dev_priv = to_i915(dev);

> > > >  	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 = 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);

> > > >  }

> > > >  

> > > >  /**

> > > > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)

> > > >  	return dev_priv->cdclk_freq;

> > > >  }

> > > >  

> > > > -static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > > -						int port, int rate)

> > > > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],

> > > > +					       int port, int pipe)

> > > > +{

> > > > +	struct drm_encoder *encoder;

> > > > +

> > > > +	if (WARN_ON(pipe >= I915_MAX_PIPES))

> > > > +		return NULL;

> > > > +

> > > > +	/* MST */

> > > > +	if (pipe != -1)

> > > 

> > > I'd make that < 0

> > > 

> > Thanks for reviewing.

> > Do you mean this? - handle the non-MST branch first with 

> > 

> > if (pipe < 0){ 

> > 	for_each_pipe(){

> > 

> > 		...

> > 	}

> > }

> > else 

> > 	return av_enc_map[pipe];

> 

> Sorry, no. I like your current code structure, so what I really meant

> was 'pipe >= 0', so:

> 

> if (pipe >= 0)

> 	return ...

> 

> for_each_pipe()

> 	...

> 	

> 


I'll make this change.

> > 

> > > > +		return av_enc_map[pipe];

> > > > +

> > > > +	/* Non-MST */

> > > > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {

> > > 

> > > for_each_pipe() would be nicer.

> > > 

> > > > +		if (!av_enc_map[pipe])

> > > > +			continue;

> > > > +

> > > > +		encoder = &av_enc_map[pipe]->base;

> > > > +		if (port == enc_to_dig_port(encoder)->port)

> > > > +			return av_enc_map[pipe];

> > > > +	}

> > > > +

> > > > +	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;

> > > > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > >  

> > > >  	i915_audio_component_get_power(dev);

> > > >  	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->av_enc_map, port, pipe);

> > > >  	if (!intel_encoder || !intel_encoder->base.crtc ||

> > > >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {

> > > 

> > > Did we have a followup planned to deal with MST here? I know there's

> > > that SST M/N patch floating around, but I think we'll want it for MST

> > > too.

> > > 

> > Looks like Libin Yang is working on the DP patch, I will check with him.

> > 

> > > > -		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 */

> > > > @@ -708,7 +741,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);

> > > > @@ -717,16 +750,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->av_enc_map, port, pipe);

> > > > +	if (!intel_encoder) {

> > > > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));

> > > 

> > > Print the pipe name too, if we have a valid pipe?

> > > 

> > > > +		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);

> > > > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h

> > > > index b46fa0e..545c6e0 100644

> > > > --- a/include/drm/i915_component.h

> > > > +++ b/include/drm/i915_component.h

> > > > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {

> > > >  	 * Called from audio driver. After audio driver sets the

> > > >  	 * sample rate, it will call this function to set n/cts

> > > >  	 */

> > > > -	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

> > > >  	 *

> > > > @@ -77,7 +77,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);

> > > >  };

> > > >  

> > > > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {

> > > >  	 * status accordingly (even when the HDA controller is in power save

> > > >  	 * mode).

> > > >  	 */

> > > > -	void (*pin_eld_notify)(void *audio_ptr, int port);

> > > > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);

> > > >  };

> > > >  

> > > >  /**

> > > > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h

> > > > index 796cabf..07fd64e 100644

> > > > --- a/include/sound/hda_i915.h

> > > > +++ b/include/sound/hda_i915.h

> > > > @@ -10,8 +10,9 @@

> > > >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);

> > > >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);

> > > >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);

> > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);

> > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > +			     int pipe, int rate);

> > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > >  			   bool *audio_enabled, char *buffer, int max_bytes);

> > > >  int snd_hdac_i915_init(struct hdac_bus *bus);

> > > >  int snd_hdac_i915_exit(struct hdac_bus *bus);

> > > > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)

> > > >  {

> > > >  }

> > > >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,

> > > > -					   hda_nid_t nid, int rate)

> > > > +					   hda_nid_t nid, int pipe, int rate)

> > > >  {

> > > >  	return 0;

> > > >  }

> > > >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > -					 bool *audio_enabled, char *buffer,

> > > > -					 int max_bytes)

> > > > +					 int pipe, bool *audio_enabled,

> > > > +					 char *buffer, int max_bytes)

> > > >  {

> > > >  	return -ENODEV;

> > > >  }

> > > > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c

> > > > index c9af022..b99994b 100644

> > > > --- a/sound/hda/hdac_i915.c

> > > > +++ b/sound/hda/hdac_i915.c

> > > > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)

> > > >   * This function sets N/CTS value based on the given sample rate.

> > > >   * Returns zero for success, or a negative error code.

> > > >   */

> > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > +			     int pipe, int rate)

> > > 

> > > I thought you'd still want to call it 'dev_id' on the hda side, and just

> > > do the dev_id->pipe conversion here next to the pin->port conversion?

> > > Just figured that would be less confusing for people who are just familiar

> > > with hda and not i915.

> > > 

> > Yeah, that makes sense. 

> > 

> > > Anyways, the patch looks pretty good to me from the i915 POV. Whether

> > > you want to do those small changes I proposed is up to you, and either

> > > way the i915 parts are

> > > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> > > 

> > 

> > I have assumed enc_to_dig_port() works for MST encoders. Do you think

> > it's good idea to have this

> > https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html

> > now?

> 

> Oh I forgot about that part. I'm not really excited about that patch.

> I'd prefer that people have to think a bit when dealing with MST

> encoders, otherwise they might assume they work just like any other

> encoder.

> 

> So I'd prefer that you explicitly handle the MST case when looking up

> the encoder. For your audio use case, I think you just need the 'port'

> information from the dig_port, no? I think making that part generic isn't

> a huge problem since that way at least you're not getting your hands

>  on a dig_port structure that you don't really own.

> 

> So you could almost use intel_ddi_get_encoder_port(), except using a

> DDI specific function in generic code isn't very nice. We could extract

> the generic part to a separate function, like so:

> 

> enum port intel_encoder_get_port(struct intel_encoder *encoder)

> {

>         switch (encoder->type) {

>         case INTEL_OUTPUT_DP_MST:

>                 return enc_to_mst(&encoder->base)->primary->port;

>         case INTEL_OUTPUT_DP:

>         case INTEL_OUTPUT_EDP:

>         case INTEL_OUTPUT_HDMI:

>         case INTEL_OUTPUT_UNKNOWN:

>                 return enc_to_dig_port(&encoder->base)->port;

>         default:

>                 MISSING_CASE(encoder->type);

>                 return PORT_A;

>         }

> }

> 

> enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)

> {

>         switch (encoder->type) {

>         case INTEL_OUTPUT_ANALOG:

> 		return PORT_E;

>         default:

> 		return intel_encoder_get_port(encoder);

>         }

> }



I like the idea of not passing the pointer to intel_dig_port. But, the
generic naming of intel_encoder_get_port() sounds like it should handle
DDI and Non-DDI platforms. Can we just have intel_encoder_get_port()?
IOW, rename intel_ddi_get_encoder_port() to intel_encoder_get_port() and
move it out of intel_ddi.c?


> 

> or you could just your own function for intel_audio.c at this time, like:

> 

> static enum port encoder_get_port(encoder)

> {

> 	if (encoder->type == MST;

> 		return enc_to_mst()...;

> 	else

> 		return enc_to_dig_port()...;

> }

> 	

> 

> 

> >  

> > > >  {

> > > >  	struct hdac_bus *bus = codec->bus;

> > > >  	struct i915_audio_component *acomp = bus->audio_component;

> > > > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > >  	port = pin2port(codec, nid);

> > > >  	if (port < 0)

> > > >  		return -EINVAL;

> > > > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);

> > > > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);

> > > >  }

> > > >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > >  

> > > > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies

> > > >   * that only a part of ELD bytes have been fetched.

> > > >   */

> > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > >  			   bool *audio_enabled, char *buffer, int max_bytes)

> > > >  {

> > > >  	struct hdac_bus *bus = codec->bus;

> > > > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > >  	port = pin2port(codec, nid);

> > > >  	if (port < 0)

> > > >  		return -EINVAL;

> > > > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,

> > > > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,

> > > >  				   buffer, max_bytes);

> > > >  }

> > > >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);

> > > > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c

> > > > index d0d5ad8..67890df 100644

> > > > --- a/sound/pci/hda/patch_hdmi.c

> > > > +++ b/sound/pci/hda/patch_hdmi.c

> > > > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,

> > > >  

> > > >  	mutex_lock(&per_pin->lock);

> > > >  	eld->monitor_present = false;

> > > > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,

> > > > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,

> > > >  				      &eld->monitor_present, eld->eld_buffer,

> > > >  				      ELD_MAX_SIZE);

> > > >  	if (size > 0) {

> > > > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,

> > > >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */

> > > >  	/* Todo: add DP1.2 MST audio support later */

> > > >  	if (codec_has_acomp(codec))

> > > > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);

> > > > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,

> > > > +					 runtime->rate);

> > > >  

> > > >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);

> > > >  	mutex_lock(&per_pin->lock);

> > > > @@ -2285,7 +2286,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;

> > > > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c

> > > > index 2abb742..cf57ab3 100644

> > > > --- a/sound/soc/codecs/hdac_hdmi.c

> > > > +++ b/sound/soc/codecs/hdac_hdmi.c

> > > > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,

> > > >  	return hdac_hdmi_init_dai_map(edev);

> > > >  }

> > > >  

> > > > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)

> > > > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)

> > > >  {

> > > >  	struct hdac_ext_device *edev = aptr;

> > > >  	struct hdac_hdmi_priv *hdmi = edev->private_data;

> > > > -- 

> > > > 2.5.0

> > > 

> > 

>
Ville Syrjala Aug. 12, 2016, 5:18 a.m. UTC | #6
On Fri, Aug 12, 2016 at 04:28:09AM +0000, Pandiyan, Dhinakaran wrote:
> On Thu, 2016-08-11 at 10:39 +0300, Ville Syrjälä wrote:
> > On Thu, Aug 11, 2016 at 07:10:39AM +0000, Pandiyan, Dhinakaran wrote:
> > > On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:
> > > > On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:
> > > > > 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 (Libin) for build to
> > > > > succeed. The audio side drivers will send the right 'pipe' values 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
> > > > > 
> > > > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-
> > > > >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------
> > > > >  include/drm/i915_component.h       |  6 +--
> > > > >  include/sound/hda_i915.h           | 11 +++--
> > > > >  sound/hda/hdac_i915.c              |  9 ++--
> > > > >  sound/pci/hda/patch_hdmi.c         |  7 +--
> > > > >  sound/soc/codecs/hdac_hdmi.c       |  2 +-
> > > > >  7 files changed, 86 insertions(+), 45 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > > > > index c36d176..8e4a88f 100644
> > > > > --- a/drivers/gpu/drm/i915/i915_drv.h
> > > > > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > > > > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
> > > > > index ef20875..a7467ea 100644
> > > > > --- a/drivers/gpu/drm/i915/intel_audio.c
> > > > > +++ b/drivers/gpu/drm/i915/intel_audio.c
> > > > > @@ -500,6 +500,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 = crtc->pipe;
> > > > >  
> > > > >  	connector = drm_select_eld(encoder);
> > > > >  	if (!connector)
> > > > > @@ -524,12 +525,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);
> > > > >  }
> > > > >  
> > > > >  /**
> > > > > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
> > > > >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
> > > > >  {
> > > > >  	struct drm_encoder *encoder = &intel_encoder->base;
> > > > > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
> > > > >  	struct drm_device *dev = encoder->dev;
> > > > >  	struct drm_i915_private *dev_priv = to_i915(dev);
> > > > >  	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 = 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);
> > > > >  }
> > > > >  
> > > > >  /**
> > > > > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)
> > > > >  	return dev_priv->cdclk_freq;
> > > > >  }
> > > > >  
> > > > > -static int i915_audio_component_sync_audio_rate(struct device *dev,
> > > > > -						int port, int rate)
> > > > > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],
> > > > > +					       int port, int pipe)
> > > > > +{
> > > > > +	struct drm_encoder *encoder;
> > > > > +
> > > > > +	if (WARN_ON(pipe >= I915_MAX_PIPES))
> > > > > +		return NULL;
> > > > > +
> > > > > +	/* MST */
> > > > > +	if (pipe != -1)
> > > > 
> > > > I'd make that < 0
> > > > 
> > > Thanks for reviewing.
> > > Do you mean this? - handle the non-MST branch first with 
> > > 
> > > if (pipe < 0){ 
> > > 	for_each_pipe(){
> > > 
> > > 		...
> > > 	}
> > > }
> > > else 
> > > 	return av_enc_map[pipe];
> > 
> > Sorry, no. I like your current code structure, so what I really meant
> > was 'pipe >= 0', so:
> > 
> > if (pipe >= 0)
> > 	return ...
> > 
> > for_each_pipe()
> > 	...
> > 	
> > 
> 
> I'll make this change.
> 
> > > 
> > > > > +		return av_enc_map[pipe];
> > > > > +
> > > > > +	/* Non-MST */
> > > > > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {
> > > > 
> > > > for_each_pipe() would be nicer.
> > > > 
> > > > > +		if (!av_enc_map[pipe])
> > > > > +			continue;
> > > > > +
> > > > > +		encoder = &av_enc_map[pipe]->base;
> > > > > +		if (port == enc_to_dig_port(encoder)->port)
> > > > > +			return av_enc_map[pipe];
> > > > > +	}
> > > > > +
> > > > > +	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;
> > > > > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
> > > > >  
> > > > >  	i915_audio_component_get_power(dev);
> > > > >  	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->av_enc_map, port, pipe);
> > > > >  	if (!intel_encoder || !intel_encoder->base.crtc ||
> > > > >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {
> > > > 
> > > > Did we have a followup planned to deal with MST here? I know there's
> > > > that SST M/N patch floating around, but I think we'll want it for MST
> > > > too.
> > > > 
> > > Looks like Libin Yang is working on the DP patch, I will check with him.
> > > 
> > > > > -		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 */
> > > > > @@ -708,7 +741,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);
> > > > > @@ -717,16 +750,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->av_enc_map, port, pipe);
> > > > > +	if (!intel_encoder) {
> > > > > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));
> > > > 
> > > > Print the pipe name too, if we have a valid pipe?
> > > > 
> > > > > +		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);
> > > > > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
> > > > > index b46fa0e..545c6e0 100644
> > > > > --- a/include/drm/i915_component.h
> > > > > +++ b/include/drm/i915_component.h
> > > > > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {
> > > > >  	 * Called from audio driver. After audio driver sets the
> > > > >  	 * sample rate, it will call this function to set n/cts
> > > > >  	 */
> > > > > -	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
> > > > >  	 *
> > > > > @@ -77,7 +77,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);
> > > > >  };
> > > > >  
> > > > > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {
> > > > >  	 * status accordingly (even when the HDA controller is in power save
> > > > >  	 * mode).
> > > > >  	 */
> > > > > -	void (*pin_eld_notify)(void *audio_ptr, int port);
> > > > > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
> > > > >  };
> > > > >  
> > > > >  /**
> > > > > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
> > > > > index 796cabf..07fd64e 100644
> > > > > --- a/include/sound/hda_i915.h
> > > > > +++ b/include/sound/hda_i915.h
> > > > > @@ -10,8 +10,9 @@
> > > > >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
> > > > >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
> > > > >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
> > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);
> > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> > > > > +			     int pipe, int rate);
> > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
> > > > >  			   bool *audio_enabled, char *buffer, int max_bytes);
> > > > >  int snd_hdac_i915_init(struct hdac_bus *bus);
> > > > >  int snd_hdac_i915_exit(struct hdac_bus *bus);
> > > > > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
> > > > >  {
> > > > >  }
> > > > >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
> > > > > -					   hda_nid_t nid, int rate)
> > > > > +					   hda_nid_t nid, int pipe, int rate)
> > > > >  {
> > > > >  	return 0;
> > > > >  }
> > > > >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > > > -					 bool *audio_enabled, char *buffer,
> > > > > -					 int max_bytes)
> > > > > +					 int pipe, bool *audio_enabled,
> > > > > +					 char *buffer, int max_bytes)
> > > > >  {
> > > > >  	return -ENODEV;
> > > > >  }
> > > > > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
> > > > > index c9af022..b99994b 100644
> > > > > --- a/sound/hda/hdac_i915.c
> > > > > +++ b/sound/hda/hdac_i915.c
> > > > > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
> > > > >   * This function sets N/CTS value based on the given sample rate.
> > > > >   * Returns zero for success, or a negative error code.
> > > > >   */
> > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
> > > > > +			     int pipe, int rate)
> > > > 
> > > > I thought you'd still want to call it 'dev_id' on the hda side, and just
> > > > do the dev_id->pipe conversion here next to the pin->port conversion?
> > > > Just figured that would be less confusing for people who are just familiar
> > > > with hda and not i915.
> > > > 
> > > Yeah, that makes sense. 
> > > 
> > > > Anyways, the patch looks pretty good to me from the i915 POV. Whether
> > > > you want to do those small changes I proposed is up to you, and either
> > > > way the i915 parts are
> > > > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > 
> > > I have assumed enc_to_dig_port() works for MST encoders. Do you think
> > > it's good idea to have this
> > > https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html
> > > now?
> > 
> > Oh I forgot about that part. I'm not really excited about that patch.
> > I'd prefer that people have to think a bit when dealing with MST
> > encoders, otherwise they might assume they work just like any other
> > encoder.
> > 
> > So I'd prefer that you explicitly handle the MST case when looking up
> > the encoder. For your audio use case, I think you just need the 'port'
> > information from the dig_port, no? I think making that part generic isn't
> > a huge problem since that way at least you're not getting your hands
> >  on a dig_port structure that you don't really own.
> > 
> > So you could almost use intel_ddi_get_encoder_port(), except using a
> > DDI specific function in generic code isn't very nice. We could extract
> > the generic part to a separate function, like so:
> > 
> > enum port intel_encoder_get_port(struct intel_encoder *encoder)
> > {
> >         switch (encoder->type) {
> >         case INTEL_OUTPUT_DP_MST:
> >                 return enc_to_mst(&encoder->base)->primary->port;
> >         case INTEL_OUTPUT_DP:
> >         case INTEL_OUTPUT_EDP:
> >         case INTEL_OUTPUT_HDMI:
> >         case INTEL_OUTPUT_UNKNOWN:
> >                 return enc_to_dig_port(&encoder->base)->port;
> >         default:
> >                 MISSING_CASE(encoder->type);
> >                 return PORT_A;
> >         }
> > }
> > 
> > enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)
> > {
> >         switch (encoder->type) {
> >         case INTEL_OUTPUT_ANALOG:
> > 		return PORT_E;
> >         default:
> > 		return intel_encoder_get_port(encoder);
> >         }
> > }
> 
> 
> I like the idea of not passing the pointer to intel_dig_port. But, the
> generic naming of intel_encoder_get_port() sounds like it should handle
> DDI and Non-DDI platforms. Can we just have intel_encoder_get_port()?
> IOW, rename intel_ddi_get_encoder_port() to intel_encoder_get_port() and
> move it out of intel_ddi.c?

That's what I just described essentially. The only catch is that the FDI
port E case should stay in the DDI code and not be moved to generic
code. Hence I suggested splitting it up.

> 
> 
> > 
> > or you could just your own function for intel_audio.c at this time, like:
> > 
> > static enum port encoder_get_port(encoder)
> > {
> > 	if (encoder->type == MST;
> > 		return enc_to_mst()...;
> > 	else
> > 		return enc_to_dig_port()...;
> > }
> > 	
> > 
> > 
> > >  
> > > > >  {
> > > > >  	struct hdac_bus *bus = codec->bus;
> > > > >  	struct i915_audio_component *acomp = bus->audio_component;
> > > > > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
> > > > >  	port = pin2port(codec, nid);
> > > > >  	if (port < 0)
> > > > >  		return -EINVAL;
> > > > > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
> > > > > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
> > > > >  
> > > > > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
> > > > >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
> > > > >   * that only a part of ELD bytes have been fetched.
> > > > >   */
> > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
> > > > >  			   bool *audio_enabled, char *buffer, int max_bytes)
> > > > >  {
> > > > >  	struct hdac_bus *bus = codec->bus;
> > > > > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
> > > > >  	port = pin2port(codec, nid);
> > > > >  	if (port < 0)
> > > > >  		return -EINVAL;
> > > > > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
> > > > > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
> > > > >  				   buffer, max_bytes);
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
> > > > > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
> > > > > index d0d5ad8..67890df 100644
> > > > > --- a/sound/pci/hda/patch_hdmi.c
> > > > > +++ b/sound/pci/hda/patch_hdmi.c
> > > > > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,
> > > > >  
> > > > >  	mutex_lock(&per_pin->lock);
> > > > >  	eld->monitor_present = false;
> > > > > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
> > > > > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
> > > > >  				      &eld->monitor_present, eld->eld_buffer,
> > > > >  				      ELD_MAX_SIZE);
> > > > >  	if (size > 0) {
> > > > > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
> > > > >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
> > > > >  	/* Todo: add DP1.2 MST audio support later */
> > > > >  	if (codec_has_acomp(codec))
> > > > > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
> > > > > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
> > > > > +					 runtime->rate);
> > > > >  
> > > > >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
> > > > >  	mutex_lock(&per_pin->lock);
> > > > > @@ -2285,7 +2286,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;
> > > > > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
> > > > > index 2abb742..cf57ab3 100644
> > > > > --- a/sound/soc/codecs/hdac_hdmi.c
> > > > > +++ b/sound/soc/codecs/hdac_hdmi.c
> > > > > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
> > > > >  	return hdac_hdmi_init_dai_map(edev);
> > > > >  }
> > > > >  
> > > > > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
> > > > > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
> > > > >  {
> > > > >  	struct hdac_ext_device *edev = aptr;
> > > > >  	struct hdac_hdmi_priv *hdmi = edev->private_data;
> > > > > -- 
> > > > > 2.5.0
> > > > 
> > > 
> > 
>
Dhinakaran Pandiyan Aug. 13, 2016, 12:16 a.m. UTC | #7
On Fri, 2016-08-12 at 08:18 +0300, Ville Syrjälä wrote:
> On Fri, Aug 12, 2016 at 04:28:09AM +0000, Pandiyan, Dhinakaran wrote:

> > On Thu, 2016-08-11 at 10:39 +0300, Ville Syrjälä wrote:

> > > On Thu, Aug 11, 2016 at 07:10:39AM +0000, Pandiyan, Dhinakaran wrote:

> > > > On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:

> > > > > On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:

> > > > > > 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 (Libin) for build to

> > > > > > succeed. The audio side drivers will send the right 'pipe' values 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

> > > > > > 

> > > > > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

> > > > > > ---

> > > > > >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-

> > > > > >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------

> > > > > >  include/drm/i915_component.h       |  6 +--

> > > > > >  include/sound/hda_i915.h           | 11 +++--

> > > > > >  sound/hda/hdac_i915.c              |  9 ++--

> > > > > >  sound/pci/hda/patch_hdmi.c         |  7 +--

> > > > > >  sound/soc/codecs/hdac_hdmi.c       |  2 +-

> > > > > >  7 files changed, 86 insertions(+), 45 deletions(-)

> > > > > > 

> > > > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h

> > > > > > index c36d176..8e4a88f 100644

> > > > > > --- a/drivers/gpu/drm/i915/i915_drv.h

> > > > > > +++ b/drivers/gpu/drm/i915/i915_drv.h

> > > > > > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c

> > > > > > index ef20875..a7467ea 100644

> > > > > > --- a/drivers/gpu/drm/i915/intel_audio.c

> > > > > > +++ b/drivers/gpu/drm/i915/intel_audio.c

> > > > > > @@ -500,6 +500,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 = crtc->pipe;

> > > > > >  

> > > > > >  	connector = drm_select_eld(encoder);

> > > > > >  	if (!connector)

> > > > > > @@ -524,12 +525,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);

> > > > > >  }

> > > > > >  

> > > > > >  /**

> > > > > > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)

> > > > > >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)

> > > > > >  {

> > > > > >  	struct drm_encoder *encoder = &intel_encoder->base;

> > > > > > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);

> > > > > >  	struct drm_device *dev = encoder->dev;

> > > > > >  	struct drm_i915_private *dev_priv = to_i915(dev);

> > > > > >  	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 = 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);

> > > > > >  }

> > > > > >  

> > > > > >  /**

> > > > > > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)

> > > > > >  	return dev_priv->cdclk_freq;

> > > > > >  }

> > > > > >  

> > > > > > -static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > > > > -						int port, int rate)

> > > > > > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],

> > > > > > +					       int port, int pipe)

> > > > > > +{

> > > > > > +	struct drm_encoder *encoder;

> > > > > > +

> > > > > > +	if (WARN_ON(pipe >= I915_MAX_PIPES))

> > > > > > +		return NULL;

> > > > > > +

> > > > > > +	/* MST */

> > > > > > +	if (pipe != -1)

> > > > > 

> > > > > I'd make that < 0

> > > > > 

> > > > Thanks for reviewing.

> > > > Do you mean this? - handle the non-MST branch first with 

> > > > 

> > > > if (pipe < 0){ 

> > > > 	for_each_pipe(){

> > > > 

> > > > 		...

> > > > 	}

> > > > }

> > > > else 

> > > > 	return av_enc_map[pipe];

> > > 

> > > Sorry, no. I like your current code structure, so what I really meant

> > > was 'pipe >= 0', so:

> > > 

> > > if (pipe >= 0)

> > > 	return ...

> > > 

> > > for_each_pipe()

> > > 	...

> > > 	

> > > 

> > 

> > I'll make this change.

> > 

> > > > 

> > > > > > +		return av_enc_map[pipe];

> > > > > > +

> > > > > > +	/* Non-MST */

> > > > > > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {

> > > > > 

> > > > > for_each_pipe() would be nicer.

> > > > > 

> > > > > > +		if (!av_enc_map[pipe])

> > > > > > +			continue;

> > > > > > +

> > > > > > +		encoder = &av_enc_map[pipe]->base;

> > > > > > +		if (port == enc_to_dig_port(encoder)->port)

> > > > > > +			return av_enc_map[pipe];

> > > > > > +	}

> > > > > > +

> > > > > > +	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;

> > > > > > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > > > >  

> > > > > >  	i915_audio_component_get_power(dev);

> > > > > >  	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->av_enc_map, port, pipe);

> > > > > >  	if (!intel_encoder || !intel_encoder->base.crtc ||

> > > > > >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {

> > > > > 

> > > > > Did we have a followup planned to deal with MST here? I know there's

> > > > > that SST M/N patch floating around, but I think we'll want it for MST

> > > > > too.

> > > > > 

> > > > Looks like Libin Yang is working on the DP patch, I will check with him.

> > > > 

> > > > > > -		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 */

> > > > > > @@ -708,7 +741,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);

> > > > > > @@ -717,16 +750,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->av_enc_map, port, pipe);

> > > > > > +	if (!intel_encoder) {

> > > > > > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));

> > > > > 

> > > > > Print the pipe name too, if we have a valid pipe?

> > > > > 

> > > > > > +		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);

> > > > > > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h

> > > > > > index b46fa0e..545c6e0 100644

> > > > > > --- a/include/drm/i915_component.h

> > > > > > +++ b/include/drm/i915_component.h

> > > > > > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {

> > > > > >  	 * Called from audio driver. After audio driver sets the

> > > > > >  	 * sample rate, it will call this function to set n/cts

> > > > > >  	 */

> > > > > > -	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

> > > > > >  	 *

> > > > > > @@ -77,7 +77,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);

> > > > > >  };

> > > > > >  

> > > > > > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {

> > > > > >  	 * status accordingly (even when the HDA controller is in power save

> > > > > >  	 * mode).

> > > > > >  	 */

> > > > > > -	void (*pin_eld_notify)(void *audio_ptr, int port);

> > > > > > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);

> > > > > >  };

> > > > > >  

> > > > > >  /**

> > > > > > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h

> > > > > > index 796cabf..07fd64e 100644

> > > > > > --- a/include/sound/hda_i915.h

> > > > > > +++ b/include/sound/hda_i915.h

> > > > > > @@ -10,8 +10,9 @@

> > > > > >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);

> > > > > >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);

> > > > > >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);

> > > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);

> > > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > > > +			     int pipe, int rate);

> > > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > > > >  			   bool *audio_enabled, char *buffer, int max_bytes);

> > > > > >  int snd_hdac_i915_init(struct hdac_bus *bus);

> > > > > >  int snd_hdac_i915_exit(struct hdac_bus *bus);

> > > > > > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)

> > > > > >  {

> > > > > >  }

> > > > > >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,

> > > > > > -					   hda_nid_t nid, int rate)

> > > > > > +					   hda_nid_t nid, int pipe, int rate)

> > > > > >  {

> > > > > >  	return 0;

> > > > > >  }

> > > > > >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > -					 bool *audio_enabled, char *buffer,

> > > > > > -					 int max_bytes)

> > > > > > +					 int pipe, bool *audio_enabled,

> > > > > > +					 char *buffer, int max_bytes)

> > > > > >  {

> > > > > >  	return -ENODEV;

> > > > > >  }

> > > > > > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c

> > > > > > index c9af022..b99994b 100644

> > > > > > --- a/sound/hda/hdac_i915.c

> > > > > > +++ b/sound/hda/hdac_i915.c

> > > > > > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)

> > > > > >   * This function sets N/CTS value based on the given sample rate.

> > > > > >   * Returns zero for success, or a negative error code.

> > > > > >   */

> > > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > > > +			     int pipe, int rate)

> > > > > 

> > > > > I thought you'd still want to call it 'dev_id' on the hda side, and just

> > > > > do the dev_id->pipe conversion here next to the pin->port conversion?

> > > > > Just figured that would be less confusing for people who are just familiar

> > > > > with hda and not i915.

> > > > > 

> > > > Yeah, that makes sense. 

> > > > 

> > > > > Anyways, the patch looks pretty good to me from the i915 POV. Whether

> > > > > you want to do those small changes I proposed is up to you, and either

> > > > > way the i915 parts are

> > > > > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> > > > > 

> > > > 

> > > > I have assumed enc_to_dig_port() works for MST encoders. Do you think

> > > > it's good idea to have this

> > > > https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html

> > > > now?

> > > 

> > > Oh I forgot about that part. I'm not really excited about that patch.

> > > I'd prefer that people have to think a bit when dealing with MST

> > > encoders, otherwise they might assume they work just like any other

> > > encoder.

> > > 

> > > So I'd prefer that you explicitly handle the MST case when looking up

> > > the encoder. For your audio use case, I think you just need the 'port'

> > > information from the dig_port, no? I think making that part generic isn't

> > > a huge problem since that way at least you're not getting your hands

> > >  on a dig_port structure that you don't really own.

> > > 

> > > So you could almost use intel_ddi_get_encoder_port(), except using a

> > > DDI specific function in generic code isn't very nice. We could extract

> > > the generic part to a separate function, like so:

> > > 

> > > enum port intel_encoder_get_port(struct intel_encoder *encoder)

> > > {

> > >         switch (encoder->type) {

> > >         case INTEL_OUTPUT_DP_MST:

> > >                 return enc_to_mst(&encoder->base)->primary->port;

> > >         case INTEL_OUTPUT_DP:

> > >         case INTEL_OUTPUT_EDP:

> > >         case INTEL_OUTPUT_HDMI:

> > >         case INTEL_OUTPUT_UNKNOWN:

> > >                 return enc_to_dig_port(&encoder->base)->port;

> > >         default:

> > >                 MISSING_CASE(encoder->type);

> > >                 return PORT_A;

> > >         }

> > > }

> > > 

> > > enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)

> > > {

> > >         switch (encoder->type) {

> > >         case INTEL_OUTPUT_ANALOG:

> > > 		return PORT_E;

> > >         default:

> > > 		return intel_encoder_get_port(encoder);

> > >         }

> > > }

> > 

> > 

> > I like the idea of not passing the pointer to intel_dig_port. But, the

> > generic naming of intel_encoder_get_port() sounds like it should handle

> > DDI and Non-DDI platforms. Can we just have intel_encoder_get_port()?

> > IOW, rename intel_ddi_get_encoder_port() to intel_encoder_get_port() and

> > move it out of intel_ddi.c?

> 

> That's what I just described essentially. The only catch is that the FDI

> port E case should stay in the DDI code and not be moved to generic

> code. Hence I suggested splitting it up.

> 


This is what I meant -

intel_get_encoder_port() is the generic catchall function, we should
expect it to handle analog encoders as well and leave the DDI specific
case to the DDI function.

enum port intel_get_encoder_port(struct intel_encoder *encoder)
{
        switch (encoder->type) {
        case INTEL_OUTPUT_DP_MST:
                return enc_to_mst(&encoder->base)->primary->port;
        case INTEL_OUTPUT_DP:
        case INTEL_OUTPUT_EDP:
        case INTEL_OUTPUT_HDMI:
        case INTEL_OUTPUT_UNKNOWN:
                return enc_to_dig_port(&encoder->base)->port;
        case INTEL_OUTPUT_ANALOG:
                return intel_ddi_get_analog_encoder_port(encoder);
        default:
                MISSING_CASE(encoder->type);
                return PORT_A;
        }
}


enum port intel_ddi_get_analog_encoder_port(struct intel_encoder
*encoder)
{
    return PORT_E;
}


> > 

> > 

> > > 

> > > or you could just your own function for intel_audio.c at this time, like:

> > > 

> > > static enum port encoder_get_port(encoder)

> > > {

> > > 	if (encoder->type == MST;

> > > 		return enc_to_mst()...;

> > > 	else

> > > 		return enc_to_dig_port()...;

> > > }

> > > 	

> > > 

> > > 

> > > >  

> > > > > >  {

> > > > > >  	struct hdac_bus *bus = codec->bus;

> > > > > >  	struct i915_audio_component *acomp = bus->audio_component;

> > > > > > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > > > >  	port = pin2port(codec, nid);

> > > > > >  	if (port < 0)

> > > > > >  		return -EINVAL;

> > > > > > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);

> > > > > > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);

> > > > > >  }

> > > > > >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > > > >  

> > > > > > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > > > >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies

> > > > > >   * that only a part of ELD bytes have been fetched.

> > > > > >   */

> > > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > > > >  			   bool *audio_enabled, char *buffer, int max_bytes)

> > > > > >  {

> > > > > >  	struct hdac_bus *bus = codec->bus;

> > > > > > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > >  	port = pin2port(codec, nid);

> > > > > >  	if (port < 0)

> > > > > >  		return -EINVAL;

> > > > > > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,

> > > > > > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,

> > > > > >  				   buffer, max_bytes);

> > > > > >  }

> > > > > >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);

> > > > > > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c

> > > > > > index d0d5ad8..67890df 100644

> > > > > > --- a/sound/pci/hda/patch_hdmi.c

> > > > > > +++ b/sound/pci/hda/patch_hdmi.c

> > > > > > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,

> > > > > >  

> > > > > >  	mutex_lock(&per_pin->lock);

> > > > > >  	eld->monitor_present = false;

> > > > > > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,

> > > > > > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,

> > > > > >  				      &eld->monitor_present, eld->eld_buffer,

> > > > > >  				      ELD_MAX_SIZE);

> > > > > >  	if (size > 0) {

> > > > > > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,

> > > > > >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */

> > > > > >  	/* Todo: add DP1.2 MST audio support later */

> > > > > >  	if (codec_has_acomp(codec))

> > > > > > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);

> > > > > > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,

> > > > > > +					 runtime->rate);

> > > > > >  

> > > > > >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);

> > > > > >  	mutex_lock(&per_pin->lock);

> > > > > > @@ -2285,7 +2286,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;

> > > > > > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c

> > > > > > index 2abb742..cf57ab3 100644

> > > > > > --- a/sound/soc/codecs/hdac_hdmi.c

> > > > > > +++ b/sound/soc/codecs/hdac_hdmi.c

> > > > > > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,

> > > > > >  	return hdac_hdmi_init_dai_map(edev);

> > > > > >  }

> > > > > >  

> > > > > > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)

> > > > > > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)

> > > > > >  {

> > > > > >  	struct hdac_ext_device *edev = aptr;

> > > > > >  	struct hdac_hdmi_priv *hdmi = edev->private_data;

> > > > > > -- 

> > > > > > 2.5.0

> > > > > 

> > > > 

> > > 

> > 

>
Dhinakaran Pandiyan Aug. 13, 2016, 12:50 a.m. UTC | #8
On Sat, 2016-08-13 at 00:16 +0000, Pandiyan, Dhinakaran wrote:
> On Fri, 2016-08-12 at 08:18 +0300, Ville Syrjälä wrote:

> > On Fri, Aug 12, 2016 at 04:28:09AM +0000, Pandiyan, Dhinakaran wrote:

> > > On Thu, 2016-08-11 at 10:39 +0300, Ville Syrjälä wrote:

> > > > On Thu, Aug 11, 2016 at 07:10:39AM +0000, Pandiyan, Dhinakaran wrote:

> > > > > On Thu, 2016-08-11 at 09:26 +0300, Ville Syrjälä wrote:

> > > > > > On Wed, Aug 10, 2016 at 12:41:57PM -0700, Dhinakaran Pandiyan wrote:

> > > > > > > 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 (Libin) for build to

> > > > > > > succeed. The audio side drivers will send the right 'pipe' values 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

> > > > > > > 

> > > > > > > Signed-off-by: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com>

> > > > > > > ---

> > > > > > >  drivers/gpu/drm/i915/i915_drv.h    |  3 +-

> > > > > > >  drivers/gpu/drm/i915/intel_audio.c | 93 ++++++++++++++++++++++++++------------

> > > > > > >  include/drm/i915_component.h       |  6 +--

> > > > > > >  include/sound/hda_i915.h           | 11 +++--

> > > > > > >  sound/hda/hdac_i915.c              |  9 ++--

> > > > > > >  sound/pci/hda/patch_hdmi.c         |  7 +--

> > > > > > >  sound/soc/codecs/hdac_hdmi.c       |  2 +-

> > > > > > >  7 files changed, 86 insertions(+), 45 deletions(-)

> > > > > > > 

> > > > > > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h

> > > > > > > index c36d176..8e4a88f 100644

> > > > > > > --- a/drivers/gpu/drm/i915/i915_drv.h

> > > > > > > +++ b/drivers/gpu/drm/i915/i915_drv.h

> > > > > > > @@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c

> > > > > > > index ef20875..a7467ea 100644

> > > > > > > --- a/drivers/gpu/drm/i915/intel_audio.c

> > > > > > > +++ b/drivers/gpu/drm/i915/intel_audio.c

> > > > > > > @@ -500,6 +500,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 = crtc->pipe;

> > > > > > >  

> > > > > > >  	connector = drm_select_eld(encoder);

> > > > > > >  	if (!connector)

> > > > > > > @@ -524,12 +525,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);

> > > > > > >  }

> > > > > > >  

> > > > > > >  /**

> > > > > > > @@ -542,22 +549,29 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)

> > > > > > >  void intel_audio_codec_disable(struct intel_encoder *intel_encoder)

> > > > > > >  {

> > > > > > >  	struct drm_encoder *encoder = &intel_encoder->base;

> > > > > > > +	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);

> > > > > > >  	struct drm_device *dev = encoder->dev;

> > > > > > >  	struct drm_i915_private *dev_priv = to_i915(dev);

> > > > > > >  	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 = 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);

> > > > > > >  }

> > > > > > >  

> > > > > > >  /**

> > > > > > > @@ -632,15 +646,39 @@ static int i915_audio_component_get_cdclk_freq(struct device *dev)

> > > > > > >  	return dev_priv->cdclk_freq;

> > > > > > >  }

> > > > > > >  

> > > > > > > -static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > > > > > -						int port, int rate)

> > > > > > > +static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],

> > > > > > > +					       int port, int pipe)

> > > > > > > +{

> > > > > > > +	struct drm_encoder *encoder;

> > > > > > > +

> > > > > > > +	if (WARN_ON(pipe >= I915_MAX_PIPES))

> > > > > > > +		return NULL;

> > > > > > > +

> > > > > > > +	/* MST */

> > > > > > > +	if (pipe != -1)

> > > > > > 

> > > > > > I'd make that < 0

> > > > > > 

> > > > > Thanks for reviewing.

> > > > > Do you mean this? - handle the non-MST branch first with 

> > > > > 

> > > > > if (pipe < 0){ 

> > > > > 	for_each_pipe(){

> > > > > 

> > > > > 		...

> > > > > 	}

> > > > > }

> > > > > else 

> > > > > 	return av_enc_map[pipe];

> > > > 

> > > > Sorry, no. I like your current code structure, so what I really meant

> > > > was 'pipe >= 0', so:

> > > > 

> > > > if (pipe >= 0)

> > > > 	return ...

> > > > 

> > > > for_each_pipe()

> > > > 	...

> > > > 	

> > > > 

> > > 

> > > I'll make this change.

> > > 

> > > > > 

> > > > > > > +		return av_enc_map[pipe];

> > > > > > > +

> > > > > > > +	/* Non-MST */

> > > > > > > +	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {

> > > > > > 

> > > > > > for_each_pipe() would be nicer.

> > > > > > 

> > > > > > > +		if (!av_enc_map[pipe])

> > > > > > > +			continue;

> > > > > > > +

> > > > > > > +		encoder = &av_enc_map[pipe]->base;

> > > > > > > +		if (port == enc_to_dig_port(encoder)->port)

> > > > > > > +			return av_enc_map[pipe];

> > > > > > > +	}

> > > > > > > +

> > > > > > > +	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;

> > > > > > > @@ -654,25 +692,20 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,

> > > > > > >  

> > > > > > >  	i915_audio_component_get_power(dev);

> > > > > > >  	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->av_enc_map, port, pipe);

> > > > > > >  	if (!intel_encoder || !intel_encoder->base.crtc ||

> > > > > > >  	    intel_encoder->type != INTEL_OUTPUT_HDMI) {

> > > > > > 

> > > > > > Did we have a followup planned to deal with MST here? I know there's

> > > > > > that SST M/N patch floating around, but I think we'll want it for MST

> > > > > > too.

> > > > > > 

> > > > > Looks like Libin Yang is working on the DP patch, I will check with him.

> > > > > 

> > > > > > > -		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 */

> > > > > > > @@ -708,7 +741,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);

> > > > > > > @@ -717,16 +750,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->av_enc_map, port, pipe);

> > > > > > > +	if (!intel_encoder) {

> > > > > > > +		DRM_DEBUG_KMS("Not valid for port %c\n", port_name(port));

> > > > > > 

> > > > > > Print the pipe name too, if we have a valid pipe?

> > > > > > 

> > > > > > > +		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);

> > > > > > > diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h

> > > > > > > index b46fa0e..545c6e0 100644

> > > > > > > --- a/include/drm/i915_component.h

> > > > > > > +++ b/include/drm/i915_component.h

> > > > > > > @@ -64,7 +64,7 @@ struct i915_audio_component_ops {

> > > > > > >  	 * Called from audio driver. After audio driver sets the

> > > > > > >  	 * sample rate, it will call this function to set n/cts

> > > > > > >  	 */

> > > > > > > -	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

> > > > > > >  	 *

> > > > > > > @@ -77,7 +77,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);

> > > > > > >  };

> > > > > > >  

> > > > > > > @@ -97,7 +97,7 @@ struct i915_audio_component_audio_ops {

> > > > > > >  	 * status accordingly (even when the HDA controller is in power save

> > > > > > >  	 * mode).

> > > > > > >  	 */

> > > > > > > -	void (*pin_eld_notify)(void *audio_ptr, int port);

> > > > > > > +	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);

> > > > > > >  };

> > > > > > >  

> > > > > > >  /**

> > > > > > > diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h

> > > > > > > index 796cabf..07fd64e 100644

> > > > > > > --- a/include/sound/hda_i915.h

> > > > > > > +++ b/include/sound/hda_i915.h

> > > > > > > @@ -10,8 +10,9 @@

> > > > > > >  int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);

> > > > > > >  int snd_hdac_display_power(struct hdac_bus *bus, bool enable);

> > > > > > >  void snd_hdac_i915_set_bclk(struct hdac_bus *bus);

> > > > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);

> > > > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > > > > +			     int pipe, int rate);

> > > > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > > > > >  			   bool *audio_enabled, char *buffer, int max_bytes);

> > > > > > >  int snd_hdac_i915_init(struct hdac_bus *bus);

> > > > > > >  int snd_hdac_i915_exit(struct hdac_bus *bus);

> > > > > > > @@ -29,13 +30,13 @@ static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)

> > > > > > >  {

> > > > > > >  }

> > > > > > >  static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,

> > > > > > > -					   hda_nid_t nid, int rate)

> > > > > > > +					   hda_nid_t nid, int pipe, int rate)

> > > > > > >  {

> > > > > > >  	return 0;

> > > > > > >  }

> > > > > > >  static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > > -					 bool *audio_enabled, char *buffer,

> > > > > > > -					 int max_bytes)

> > > > > > > +					 int pipe, bool *audio_enabled,

> > > > > > > +					 char *buffer, int max_bytes)

> > > > > > >  {

> > > > > > >  	return -ENODEV;

> > > > > > >  }

> > > > > > > diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c

> > > > > > > index c9af022..b99994b 100644

> > > > > > > --- a/sound/hda/hdac_i915.c

> > > > > > > +++ b/sound/hda/hdac_i915.c

> > > > > > > @@ -201,7 +201,8 @@ static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)

> > > > > > >   * This function sets N/CTS value based on the given sample rate.

> > > > > > >   * Returns zero for success, or a negative error code.

> > > > > > >   */

> > > > > > > -int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > > > > > +int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,

> > > > > > > +			     int pipe, int rate)

> > > > > > 

> > > > > > I thought you'd still want to call it 'dev_id' on the hda side, and just

> > > > > > do the dev_id->pipe conversion here next to the pin->port conversion?

> > > > > > Just figured that would be less confusing for people who are just familiar

> > > > > > with hda and not i915.

> > > > > > 

> > > > > Yeah, that makes sense. 

> > > > > 

> > > > > > Anyways, the patch looks pretty good to me from the i915 POV. Whether

> > > > > > you want to do those small changes I proposed is up to you, and either

> > > > > > way the i915 parts are

> > > > > > Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

> > > > > > 

> > > > > 

> > > > > I have assumed enc_to_dig_port() works for MST encoders. Do you think

> > > > > it's good idea to have this

> > > > > https://lists.freedesktop.org/archives/intel-gfx/2016-August/102994.html

> > > > > now?

> > > > 

> > > > Oh I forgot about that part. I'm not really excited about that patch.

> > > > I'd prefer that people have to think a bit when dealing with MST

> > > > encoders, otherwise they might assume they work just like any other

> > > > encoder.

> > > > 

> > > > So I'd prefer that you explicitly handle the MST case when looking up

> > > > the encoder. For your audio use case, I think you just need the 'port'

> > > > information from the dig_port, no? I think making that part generic isn't

> > > > a huge problem since that way at least you're not getting your hands

> > > >  on a dig_port structure that you don't really own.

> > > > 

> > > > So you could almost use intel_ddi_get_encoder_port(), except using a

> > > > DDI specific function in generic code isn't very nice. We could extract

> > > > the generic part to a separate function, like so:

> > > > 

> > > > enum port intel_encoder_get_port(struct intel_encoder *encoder)

> > > > {

> > > >         switch (encoder->type) {

> > > >         case INTEL_OUTPUT_DP_MST:

> > > >                 return enc_to_mst(&encoder->base)->primary->port;

> > > >         case INTEL_OUTPUT_DP:

> > > >         case INTEL_OUTPUT_EDP:

> > > >         case INTEL_OUTPUT_HDMI:

> > > >         case INTEL_OUTPUT_UNKNOWN:

> > > >                 return enc_to_dig_port(&encoder->base)->port;

> > > >         default:

> > > >                 MISSING_CASE(encoder->type);

> > > >                 return PORT_A;

> > > >         }

> > > > }

> > > > 

> > > > enum port intel_ddi_get_encoder_port(struct intel_encoder *encoder)

> > > > {

> > > >         switch (encoder->type) {

> > > >         case INTEL_OUTPUT_ANALOG:

> > > > 		return PORT_E;

> > > >         default:

> > > > 		return intel_encoder_get_port(encoder);

> > > >         }

> > > > }

> > > 

> > > 

> > > I like the idea of not passing the pointer to intel_dig_port. But, the

> > > generic naming of intel_encoder_get_port() sounds like it should handle

> > > DDI and Non-DDI platforms. Can we just have intel_encoder_get_port()?

> > > IOW, rename intel_ddi_get_encoder_port() to intel_encoder_get_port() and

> > > move it out of intel_ddi.c?

> > 

> > That's what I just described essentially. The only catch is that the FDI

> > port E case should stay in the DDI code and not be moved to generic

> > code. Hence I suggested splitting it up.

> > 

> 

> This is what I meant -

> 

> intel_get_encoder_port() is the generic catchall function, we should

> expect it to handle analog encoders as well and leave the DDI specific

> case to the DDI function.

> 

> enum port intel_get_encoder_port(struct intel_encoder *encoder)

> {

>         switch (encoder->type) {

>         case INTEL_OUTPUT_DP_MST:

>                 return enc_to_mst(&encoder->base)->primary->port;

>         case INTEL_OUTPUT_DP:

>         case INTEL_OUTPUT_EDP:

>         case INTEL_OUTPUT_HDMI:

>         case INTEL_OUTPUT_UNKNOWN:

>                 return enc_to_dig_port(&encoder->base)->port;

>         case INTEL_OUTPUT_ANALOG:

>                 return intel_ddi_get_analog_encoder_port(encoder);

>         default:

>                 MISSING_CASE(encoder->type);

>                 return PORT_A;

>         }

> }

> 

> 

> enum port intel_ddi_get_analog_encoder_port(struct intel_encoder

> *encoder)

> {

>     return PORT_E;

> }

> 

> 

*Removing the audio list from cc as this is i915 specific.

Sorry, no parameters for intel_ddi_get_analog_encoder_port()


> > > 

> > > 

> > > > 

> > > > or you could just your own function for intel_audio.c at this time, like:

> > > > 

> > > > static enum port encoder_get_port(encoder)

> > > > {

> > > > 	if (encoder->type == MST;

> > > > 		return enc_to_mst()...;

> > > > 	else

> > > > 		return enc_to_dig_port()...;

> > > > }

> > > > 	

> > > > 

> > > > 

> > > > >  

> > > > > > >  {

> > > > > > >  	struct hdac_bus *bus = codec->bus;

> > > > > > >  	struct i915_audio_component *acomp = bus->audio_component;

> > > > > > > @@ -212,7 +213,7 @@ int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)

> > > > > > >  	port = pin2port(codec, nid);

> > > > > > >  	if (port < 0)

> > > > > > >  		return -EINVAL;

> > > > > > > -	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);

> > > > > > > +	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);

> > > > > > >  }

> > > > > > >  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > > > > >  

> > > > > > > @@ -236,7 +237,7 @@ EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);

> > > > > > >   * thus it may be over @max_bytes.  If it's over @max_bytes, it implies

> > > > > > >   * that only a part of ELD bytes have been fetched.

> > > > > > >   */

> > > > > > > -int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > > +int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,

> > > > > > >  			   bool *audio_enabled, char *buffer, int max_bytes)

> > > > > > >  {

> > > > > > >  	struct hdac_bus *bus = codec->bus;

> > > > > > > @@ -249,7 +250,7 @@ int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,

> > > > > > >  	port = pin2port(codec, nid);

> > > > > > >  	if (port < 0)

> > > > > > >  		return -EINVAL;

> > > > > > > -	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,

> > > > > > > +	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,

> > > > > > >  				   buffer, max_bytes);

> > > > > > >  }

> > > > > > >  EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);

> > > > > > > diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c

> > > > > > > index d0d5ad8..67890df 100644

> > > > > > > --- a/sound/pci/hda/patch_hdmi.c

> > > > > > > +++ b/sound/pci/hda/patch_hdmi.c

> > > > > > > @@ -1485,7 +1485,7 @@ static void sync_eld_via_acomp(struct hda_codec *codec,

> > > > > > >  

> > > > > > >  	mutex_lock(&per_pin->lock);

> > > > > > >  	eld->monitor_present = false;

> > > > > > > -	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,

> > > > > > > +	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,

> > > > > > >  				      &eld->monitor_present, eld->eld_buffer,

> > > > > > >  				      ELD_MAX_SIZE);

> > > > > > >  	if (size > 0) {

> > > > > > > @@ -1739,7 +1739,8 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,

> > > > > > >  	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */

> > > > > > >  	/* Todo: add DP1.2 MST audio support later */

> > > > > > >  	if (codec_has_acomp(codec))

> > > > > > > -		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);

> > > > > > > +		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,

> > > > > > > +					 runtime->rate);

> > > > > > >  

> > > > > > >  	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);

> > > > > > >  	mutex_lock(&per_pin->lock);

> > > > > > > @@ -2285,7 +2286,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;

> > > > > > > diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c

> > > > > > > index 2abb742..cf57ab3 100644

> > > > > > > --- a/sound/soc/codecs/hdac_hdmi.c

> > > > > > > +++ b/sound/soc/codecs/hdac_hdmi.c

> > > > > > > @@ -1366,7 +1366,7 @@ static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,

> > > > > > >  	return hdac_hdmi_init_dai_map(edev);

> > > > > > >  }

> > > > > > >  

> > > > > > > -static void hdac_hdmi_eld_notify_cb(void *aptr, int port)

> > > > > > > +static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)

> > > > > > >  {

> > > > > > >  	struct hdac_ext_device *edev = aptr;

> > > > > > >  	struct hdac_hdmi_priv *hdmi = edev->private_data;

> > > > > > > -- 

> > > > > > > 2.5.0

> > > > > > 

> > > > > 

> > > > 

> > > 

> > 

> 

> _______________________________________________

> Intel-gfx mailing list

> Intel-gfx@lists.freedesktop.org

> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c36d176..8e4a88f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2036,7 +2036,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/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index ef20875..a7467ea 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -500,6 +500,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 = crtc->pipe;
 
 	connector = drm_select_eld(encoder);
 	if (!connector)
@@ -524,12 +525,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);
 }
 
 /**
@@ -542,22 +549,29 @@  void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
 void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
 {
 	struct drm_encoder *encoder = &intel_encoder->base;
+	struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
 	struct drm_device *dev = encoder->dev;
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	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 = 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);
 }
 
 /**
@@ -632,15 +646,39 @@  static int i915_audio_component_get_cdclk_freq(struct device *dev)
 	return dev_priv->cdclk_freq;
 }
 
-static int i915_audio_component_sync_audio_rate(struct device *dev,
-						int port, int rate)
+static struct intel_encoder *get_saved_enc(struct intel_encoder *av_enc_map[],
+					       int port, int pipe)
+{
+	struct drm_encoder *encoder;
+
+	if (WARN_ON(pipe >= I915_MAX_PIPES))
+		return NULL;
+
+	/* MST */
+	if (pipe != -1)
+		return av_enc_map[pipe];
+
+	/* Non-MST */
+	for (pipe = PIPE_A; pipe < I915_MAX_PIPES; pipe++) {
+		if (!av_enc_map[pipe])
+			continue;
+
+		encoder = &av_enc_map[pipe]->base;
+		if (port == enc_to_dig_port(encoder)->port)
+			return av_enc_map[pipe];
+	}
+
+	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;
@@ -654,25 +692,20 @@  static int i915_audio_component_sync_audio_rate(struct device *dev,
 
 	i915_audio_component_get_power(dev);
 	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->av_enc_map, 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 */
@@ -708,7 +741,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);
@@ -717,16 +750,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->av_enc_map, 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);
diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h
index b46fa0e..545c6e0 100644
--- a/include/drm/i915_component.h
+++ b/include/drm/i915_component.h
@@ -64,7 +64,7 @@  struct i915_audio_component_ops {
 	 * Called from audio driver. After audio driver sets the
 	 * sample rate, it will call this function to set n/cts
 	 */
-	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
 	 *
@@ -77,7 +77,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);
 };
 
@@ -97,7 +97,7 @@  struct i915_audio_component_audio_ops {
 	 * status accordingly (even when the HDA controller is in power save
 	 * mode).
 	 */
-	void (*pin_eld_notify)(void *audio_ptr, int port);
+	void (*pin_eld_notify)(void *audio_ptr, int port, int pipe);
 };
 
 /**
diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h
index 796cabf..07fd64e 100644
--- a/include/sound/hda_i915.h
+++ b/include/sound/hda_i915.h
@@ -10,8 +10,9 @@ 
 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
 int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
 void snd_hdac_i915_set_bclk(struct hdac_bus *bus);
-int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate);
-int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
+int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
+			     int pipe, int rate);
+int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
 			   bool *audio_enabled, char *buffer, int max_bytes);
 int snd_hdac_i915_init(struct hdac_bus *bus);
 int snd_hdac_i915_exit(struct hdac_bus *bus);
@@ -29,13 +30,13 @@  static inline void snd_hdac_i915_set_bclk(struct hdac_bus *bus)
 {
 }
 static inline int snd_hdac_sync_audio_rate(struct hdac_device *codec,
-					   hda_nid_t nid, int rate)
+					   hda_nid_t nid, int pipe, int rate)
 {
 	return 0;
 }
 static inline int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
-					 bool *audio_enabled, char *buffer,
-					 int max_bytes)
+					 int pipe, bool *audio_enabled,
+					 char *buffer, int max_bytes)
 {
 	return -ENODEV;
 }
diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c
index c9af022..b99994b 100644
--- a/sound/hda/hdac_i915.c
+++ b/sound/hda/hdac_i915.c
@@ -201,7 +201,8 @@  static int pin2port(struct hdac_device *codec, hda_nid_t pin_nid)
  * This function sets N/CTS value based on the given sample rate.
  * Returns zero for success, or a negative error code.
  */
-int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
+int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid,
+			     int pipe, int rate)
 {
 	struct hdac_bus *bus = codec->bus;
 	struct i915_audio_component *acomp = bus->audio_component;
@@ -212,7 +213,7 @@  int snd_hdac_sync_audio_rate(struct hdac_device *codec, hda_nid_t nid, int rate)
 	port = pin2port(codec, nid);
 	if (port < 0)
 		return -EINVAL;
-	return acomp->ops->sync_audio_rate(acomp->dev, port, rate);
+	return acomp->ops->sync_audio_rate(acomp->dev, port, pipe, rate);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
 
@@ -236,7 +237,7 @@  EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate);
  * thus it may be over @max_bytes.  If it's over @max_bytes, it implies
  * that only a part of ELD bytes have been fetched.
  */
-int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
+int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid, int pipe,
 			   bool *audio_enabled, char *buffer, int max_bytes)
 {
 	struct hdac_bus *bus = codec->bus;
@@ -249,7 +250,7 @@  int snd_hdac_acomp_get_eld(struct hdac_device *codec, hda_nid_t nid,
 	port = pin2port(codec, nid);
 	if (port < 0)
 		return -EINVAL;
-	return acomp->ops->get_eld(acomp->dev, port, audio_enabled,
+	return acomp->ops->get_eld(acomp->dev, port, pipe, audio_enabled,
 				   buffer, max_bytes);
 }
 EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index d0d5ad8..67890df 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1485,7 +1485,7 @@  static void sync_eld_via_acomp(struct hda_codec *codec,
 
 	mutex_lock(&per_pin->lock);
 	eld->monitor_present = false;
-	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+	size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid, -1,
 				      &eld->monitor_present, eld->eld_buffer,
 				      ELD_MAX_SIZE);
 	if (size > 0) {
@@ -1739,7 +1739,8 @@  static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
 	/* Call sync_audio_rate to set the N/CTS/M manually if necessary */
 	/* Todo: add DP1.2 MST audio support later */
 	if (codec_has_acomp(codec))
-		snd_hdac_sync_audio_rate(&codec->core, pin_nid, runtime->rate);
+		snd_hdac_sync_audio_rate(&codec->core, pin_nid, -1,
+					 runtime->rate);
 
 	non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
 	mutex_lock(&per_pin->lock);
@@ -2285,7 +2286,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;
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 2abb742..cf57ab3 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -1366,7 +1366,7 @@  static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev,
 	return hdac_hdmi_init_dai_map(edev);
 }
 
-static void hdac_hdmi_eld_notify_cb(void *aptr, int port)
+static void hdac_hdmi_eld_notify_cb(void *aptr, int port, int pipe)
 {
 	struct hdac_ext_device *edev = aptr;
 	struct hdac_hdmi_priv *hdmi = edev->private_data;