]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
drm/i915: Add get_eld audio component
authorTakashi Iwai <tiwai@suse.de>
Thu, 12 Nov 2015 14:23:41 +0000 (15:23 +0100)
committerTim Gardner <tim.gardner@canonical.com>
Wed, 6 Apr 2016 09:21:12 +0000 (10:21 +0100)
BugLink: http://bugs.launchpad.net/bugs/1540390
Implement a new i915_audio_component_ops, get_eld().  It's called by
the audio driver to fetch the current audio status and ELD of the
given HDMI/DP port.  It returns the size of expected ELD bytes if it's
valid, zero if no valid ELD is found, or a negative error code.  The
current state of audio on/off is stored in the given pointer, too.

Note that the returned size isn't limited to the given max bytes.  If
the size is greater than the max bytes, it means that only a part of
ELD has been copied back.

For achieving this implementation, a new field audio_connector is
added to struct intel_digital_port.  It points to the connector
assigned to the given digital port.  It's set/reset at each audio
enable/disable call in intel_audio.c, and protected with av_mutex.

Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
(cherry picked from commit cae666ceb8c3f154351f7df29c522f7a7016bdc0)
Signed-off-by: Timo Aaltonen <timo.aaltonen@canonical.com>
Signed-off-by: Andy Whitcroft <apw@canonical.com>
drivers/gpu/drm/i915/intel_audio.c
drivers/gpu/drm/i915/intel_drv.h
include/drm/i915_component.h

index 4dccd9b003a1cf8000d039d6f78d97a14375f50e..7f45e73f58f5ad18adbdfc762cd68afbc0055639 100644 (file)
@@ -525,6 +525,10 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
                dev_priv->display.audio_codec_enable(connector, intel_encoder,
                                                     adjusted_mode);
 
+       mutex_lock(&dev_priv->av_mutex);
+       intel_dig_port->audio_connector = connector;
+       mutex_unlock(&dev_priv->av_mutex);
+
        if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
                acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
 }
@@ -548,6 +552,10 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder)
        if (dev_priv->display.audio_codec_disable)
                dev_priv->display.audio_codec_disable(intel_encoder);
 
+       mutex_lock(&dev_priv->av_mutex);
+       intel_dig_port->audio_connector = NULL;
+       mutex_unlock(&dev_priv->av_mutex);
+
        if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify)
                acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port);
 }
@@ -706,6 +714,39 @@ static int i915_audio_component_sync_audio_rate(struct device *dev,
        return 0;
 }
 
+static int i915_audio_component_get_eld(struct device *dev, int port,
+                                       bool *enabled,
+                                       unsigned char *buf, int max_bytes)
+{
+       struct drm_i915_private *dev_priv = dev_to_i915(dev);
+       struct drm_device *drm_dev = dev_priv->dev;
+       struct intel_encoder *intel_encoder;
+       struct intel_digital_port *intel_dig_port;
+       const u8 *eld;
+       int ret = -EINVAL;
+
+       mutex_lock(&dev_priv->av_mutex);
+       for_each_intel_encoder(drm_dev, intel_encoder) {
+               if (intel_encoder->type != INTEL_OUTPUT_DISPLAYPORT &&
+                   intel_encoder->type != INTEL_OUTPUT_HDMI)
+                       continue;
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               if (port == intel_dig_port->port) {
+                       ret = 0;
+                       *enabled = intel_dig_port->audio_connector != NULL;
+                       if (!*enabled)
+                               break;
+                       eld = intel_dig_port->audio_connector->eld;
+                       ret = drm_eld_size(eld);
+                       memcpy(buf, eld, min(max_bytes, ret));
+                       break;
+               }
+       }
+
+       mutex_unlock(&dev_priv->av_mutex);
+       return ret;
+}
+
 static const struct i915_audio_component_ops i915_audio_component_ops = {
        .owner          = THIS_MODULE,
        .get_power      = i915_audio_component_get_power,
@@ -713,6 +754,7 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
        .codec_wake_override = i915_audio_component_codec_wake_override,
        .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
        .sync_audio_rate = i915_audio_component_sync_audio_rate,
+       .get_eld        = i915_audio_component_get_eld,
 };
 
 static int i915_audio_component_bind(struct device *i915_dev,
index 0d00f07b7163c90c10d8e994b037b7b24b508d34..962d8d4408f3960192a09af4ab66fbb70afdd404 100644 (file)
@@ -799,6 +799,8 @@ struct intel_digital_port {
        struct intel_hdmi hdmi;
        enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
        bool release_cl2_override;
+       /* for communication with audio component; protected by av_mutex */
+       const struct drm_connector *audio_connector;
 };
 
 struct intel_dp_mst_encoder {
index 30d89e0da2c6b21352ba46b8d52f514f94a4ebbf..90f7f236aced7e958e138b50cc257912b2dd0bdb 100644 (file)
@@ -46,6 +46,20 @@ struct i915_audio_component_ops {
        void (*codec_wake_override)(struct device *, bool enable);
        int (*get_cdclk_freq)(struct device *);
        int (*sync_audio_rate)(struct device *, int port, int rate);
+       /**
+        * @get_eld: fill the audio state and ELD bytes for the given port
+        *
+        * Called from audio driver to get the HDMI/DP audio state of the given
+        * digital port, and also fetch ELD bytes to the given pointer.
+        *
+        * It returns the byte size of the original ELD (not the actually
+        * copied size), zero for an invalid ELD, or a negative error code.
+        *
+        * 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,
+                      unsigned char *buf, int max_bytes);
 };
 
 struct i915_audio_component_audio_ops {