summarylogtreecommitdiffstats
path: root/cherry-trail-sound.patch
diff options
context:
space:
mode:
Diffstat (limited to 'cherry-trail-sound.patch')
-rw-r--r--cherry-trail-sound.patch379
1 files changed, 379 insertions, 0 deletions
diff --git a/cherry-trail-sound.patch b/cherry-trail-sound.patch
new file mode 100644
index 000000000000..2bc3baf6c770
--- /dev/null
+++ b/cherry-trail-sound.patch
@@ -0,0 +1,379 @@
+From 8a2d6ae1f737fd22eaeadd0dc32b85c92f239025 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com>
+Date: Thu, 27 Apr 2017 19:02:30 +0300
+Subject: ALSA: x86: Register multiple PCM devices for the LPE audio card
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Now that everything is in place let's register a PCM device for
+each port of the display engine. This will make it possible to
+actually output audio to multiple displays at the same time. And
+it avoids modesets on unrelated displays from clobbering up the
+ELD and whatnot for the display currently doing the playback.
+
+v2: Add a PCM per port instead of per pipe
+v3: Fix off by one error with port numbers (Pierre-Louis)
+ Fix .notify_audio_lpe() prototype (Pierre-Louis)
+
+Cc: Takashi Iwai <tiwai@suse.de>
+Cc: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
+Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
+Link: http://patchwork.freedesktop.org/patch/msgid/20170427160231.13337-12-ville.syrjala@linux.intel.com
+Reviewed-by: Takashi Iwai <tiwai@suse.de>
+---
+ drivers/gpu/drm/i915/intel_lpe_audio.c | 19 ++---
+ include/drm/intel_lpe_audio.h | 6 +-
+ sound/x86/intel_hdmi_audio.c | 126 +++++++++++++++++++--------------
+ sound/x86/intel_hdmi_audio.h | 7 +-
+ 4 files changed, 92 insertions(+), 66 deletions(-)
+
+diff --git a/drivers/gpu/drm/i915/intel_lpe_audio.c b/drivers/gpu/drm/i915/intel_lpe_audio.c
+index bdbc235..3bf6528 100644
+--- a/drivers/gpu/drm/i915/intel_lpe_audio.c
++++ b/drivers/gpu/drm/i915/intel_lpe_audio.c
+@@ -111,7 +111,11 @@ lpe_audio_platdev_create(struct drm_i915_private *dev_priv)
+ pinfo.size_data = sizeof(*pdata);
+ pinfo.dma_mask = DMA_BIT_MASK(32);
+
+- pdata->port.pipe = -1;
++ pdata->num_pipes = INTEL_INFO(dev_priv)->num_pipes;
++ pdata->num_ports = IS_CHERRYVIEW(dev_priv) ? 3 : 2; /* B,C,D or B,C */
++ pdata->port[0].pipe = -1;
++ pdata->port[1].pipe = -1;
++ pdata->port[2].pipe = -1;
+ spin_lock_init(&pdata->lpe_audio_slock);
+
+ platdev = platform_device_register_full(&pinfo);
+@@ -319,7 +323,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
+ enum pipe pipe, enum port port,
+ const void *eld, int ls_clock, bool dp_output)
+ {
+- unsigned long irq_flags;
++ unsigned long irqflags;
+ struct intel_hdmi_lpe_audio_pdata *pdata;
+ struct intel_hdmi_lpe_audio_port_pdata *ppdata;
+ u32 audio_enable;
+@@ -328,14 +332,12 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
+ return;
+
+ pdata = dev_get_platdata(&dev_priv->lpe_audio.platdev->dev);
+- ppdata = &pdata->port;
++ ppdata = &pdata->port[port - PORT_B];
+
+- spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags);
++ spin_lock_irqsave(&pdata->lpe_audio_slock, irqflags);
+
+ audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port));
+
+- ppdata->port = port;
+-
+ if (eld != NULL) {
+ memcpy(ppdata->eld, eld, HDMI_MAX_ELD_BYTES);
+ ppdata->pipe = pipe;
+@@ -357,8 +359,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
+ }
+
+ if (pdata->notify_audio_lpe)
+- pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev);
++ pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev, port - PORT_B);
+
+- spin_unlock_irqrestore(&pdata->lpe_audio_slock,
+- irq_flags);
++ spin_unlock_irqrestore(&pdata->lpe_audio_slock, irqflags);
+ }
+diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h
+index 211f1cd..b6121c8 100644
+--- a/include/drm/intel_lpe_audio.h
++++ b/include/drm/intel_lpe_audio.h
+@@ -40,9 +40,11 @@ struct intel_hdmi_lpe_audio_port_pdata {
+ };
+
+ struct intel_hdmi_lpe_audio_pdata {
+- struct intel_hdmi_lpe_audio_port_pdata port;
++ struct intel_hdmi_lpe_audio_port_pdata port[3]; /* for ports B,C,D */
++ int num_ports;
++ int num_pipes;
+
+- void (*notify_audio_lpe)(struct platform_device *pdev);
++ void (*notify_audio_lpe)(struct platform_device *pdev, int port); /* port: 0==B,1==C,2==D */
+ spinlock_t lpe_audio_slock;
+ };
+
+diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
+index 12fae26..909391d 100644
+--- a/sound/x86/intel_hdmi_audio.c
++++ b/sound/x86/intel_hdmi_audio.c
+@@ -42,6 +42,8 @@
+ #include <drm/intel_lpe_audio.h>
+ #include "intel_hdmi_audio.h"
+
++#define for_each_pipe(card_ctx, pipe) \
++ for ((pipe) = 0; (pipe) < (card_ctx)->num_pipes; (pipe)++)
+ #define for_each_port(card_ctx, port) \
+ for ((port) = 0; (port) < (card_ctx)->num_ports; (port)++)
+
+@@ -192,15 +194,30 @@ static void had_substream_put(struct snd_intelhad *intelhaddata)
+ spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
+ }
+
++static u32 had_config_offset(int pipe)
++{
++ switch (pipe) {
++ default:
++ case 0:
++ return AUDIO_HDMI_CONFIG_A;
++ case 1:
++ return AUDIO_HDMI_CONFIG_B;
++ case 2:
++ return AUDIO_HDMI_CONFIG_C;
++ }
++}
++
+ /* Register access functions */
+-static u32 had_read_register_raw(struct snd_intelhad *ctx, u32 reg)
++static u32 had_read_register_raw(struct snd_intelhad_card *card_ctx,
++ int pipe, u32 reg)
+ {
+- return ioread32(ctx->card_ctx->mmio_start + ctx->had_config_offset + reg);
++ return ioread32(card_ctx->mmio_start + had_config_offset(pipe) + reg);
+ }
+
+-static void had_write_register_raw(struct snd_intelhad *ctx, u32 reg, u32 val)
++static void had_write_register_raw(struct snd_intelhad_card *card_ctx,
++ int pipe, u32 reg, u32 val)
+ {
+- iowrite32(val, ctx->card_ctx->mmio_start + ctx->had_config_offset + reg);
++ iowrite32(val, card_ctx->mmio_start + had_config_offset(pipe) + reg);
+ }
+
+ static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
+@@ -208,13 +225,13 @@ static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val)
+ if (!ctx->connected)
+ *val = 0;
+ else
+- *val = had_read_register_raw(ctx, reg);
++ *val = had_read_register_raw(ctx->card_ctx, ctx->pipe, reg);
+ }
+
+ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
+ {
+ if (ctx->connected)
+- had_write_register_raw(ctx, reg, val);
++ had_write_register_raw(ctx->card_ctx, ctx->pipe, reg, val);
+ }
+
+ /*
+@@ -1361,6 +1378,9 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
+ return;
+ }
+
++ /* Disable Audio */
++ had_enable_audio(intelhaddata, false);
++
+ intelhaddata->connected = true;
+ dev_dbg(intelhaddata->dev,
+ "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
+@@ -1523,26 +1543,31 @@ static const struct snd_kcontrol_new had_controls[] = {
+ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
+ {
+ struct snd_intelhad_card *card_ctx = dev_id;
+- int port;
++ u32 audio_stat[3] = {};
++ int pipe, port;
++
++ for_each_pipe(card_ctx, pipe) {
++ /* use raw register access to ack IRQs even while disconnected */
++ audio_stat[pipe] = had_read_register_raw(card_ctx, pipe,
++ AUD_HDMI_STATUS) &
++ (HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE);
++
++ if (audio_stat[pipe])
++ had_write_register_raw(card_ctx, pipe,
++ AUD_HDMI_STATUS, audio_stat[pipe]);
++ }
+
+ for_each_port(card_ctx, port) {
+ struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
+- u32 audio_stat;
++ int pipe = ctx->pipe;
+
+- /* use raw register access to ack IRQs even while disconnected */
+- audio_stat = had_read_register_raw(ctx, AUD_HDMI_STATUS);
+-
+- if (audio_stat & HDMI_AUDIO_UNDERRUN) {
+- had_write_register_raw(ctx, AUD_HDMI_STATUS,
+- HDMI_AUDIO_UNDERRUN);
+- had_process_buffer_underrun(ctx);
+- }
++ if (pipe < 0)
++ continue;
+
+- if (audio_stat & HDMI_AUDIO_BUFFER_DONE) {
+- had_write_register_raw(ctx, AUD_HDMI_STATUS,
+- HDMI_AUDIO_BUFFER_DONE);
++ if (audio_stat[pipe] & HDMI_AUDIO_BUFFER_DONE)
+ had_process_buffer_done(ctx);
+- }
++ if (audio_stat[pipe] & HDMI_AUDIO_UNDERRUN)
++ had_process_buffer_underrun(ctx);
+ }
+
+ return IRQ_HANDLED;
+@@ -1551,16 +1576,12 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
+ /*
+ * monitor plug/unplug notification from i915; just kick off the work
+ */
+-static void notify_audio_lpe(struct platform_device *pdev)
++static void notify_audio_lpe(struct platform_device *pdev, int port)
+ {
+ struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev);
+- int port;
++ struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
+
+- for_each_port(card_ctx, port) {
+- struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
+-
+- schedule_work(&ctx->hdmi_audio_wq);
+- }
++ schedule_work(&ctx->hdmi_audio_wq);
+ }
+
+ /* the work to handle monitor hot plug/unplug */
+@@ -1569,34 +1590,27 @@ static void had_audio_wq(struct work_struct *work)
+ struct snd_intelhad *ctx =
+ container_of(work, struct snd_intelhad, hdmi_audio_wq);
+ struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
+- struct intel_hdmi_lpe_audio_port_pdata *ppdata = &pdata->port;
++ struct intel_hdmi_lpe_audio_port_pdata *ppdata = &pdata->port[ctx->port];
+
+ pm_runtime_get_sync(ctx->dev);
+ mutex_lock(&ctx->mutex);
+ if (ppdata->pipe < 0) {
+- dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n",
+- __func__);
++ dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG : port = %d\n",
++ __func__, ctx->port);
++
+ memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
++
++ ctx->dp_output = false;
++ ctx->tmds_clock_speed = 0;
++ ctx->link_rate = 0;
++
++ /* Shut down the stream */
+ had_process_hot_unplug(ctx);
++
++ ctx->pipe = -1;
+ } else {
+ dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
+- __func__, ppdata->port, ppdata->ls_clock);
+-
+- switch (ppdata->pipe) {
+- case 0:
+- ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+- break;
+- case 1:
+- ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
+- break;
+- case 2:
+- ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
+- break;
+- default:
+- dev_dbg(ctx->dev, "Invalid pipe %d\n",
+- ppdata->pipe);
+- break;
+- }
++ __func__, ctx->port, ppdata->ls_clock);
+
+ memcpy(ctx->eld, ppdata->eld, sizeof(ctx->eld));
+
+@@ -1609,11 +1623,18 @@ static void had_audio_wq(struct work_struct *work)
+ ctx->link_rate = 0;
+ }
+
++ /*
++ * Shut down the stream before we change
++ * the pipe assignment for this pcm device
++ */
+ had_process_hot_plug(ctx);
+
+- /* Process mode change if stream is active */
++ ctx->pipe = ppdata->pipe;
++
++ /* Restart the stream if necessary */
+ had_process_mode_change(ctx);
+ }
++
+ mutex_unlock(&ctx->mutex);
+ pm_runtime_mark_last_busy(ctx->dev);
+ pm_runtime_put_autosuspend(ctx->dev);
+@@ -1794,7 +1815,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
+
+ init_channel_allocations();
+
+- card_ctx->num_ports = 1;
++ card_ctx->num_pipes = pdata->num_pipes;
++ card_ctx->num_ports = pdata->num_ports;
+
+ for_each_port(card_ctx, port) {
+ struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
+@@ -1802,12 +1824,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
+
+ ctx->card_ctx = card_ctx;
+ ctx->dev = card_ctx->dev;
++ ctx->port = port;
++ ctx->pipe = -1;
+
+ INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
+
+- ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
+-
+- ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
++ ret = snd_pcm_new(card, INTEL_HAD, port, MAX_PB_STREAMS,
+ MAX_CAP_STREAMS, &pcm);
+ if (ret)
+ goto err;
+diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
+index 2725964..0d91bb5 100644
+--- a/sound/x86/intel_hdmi_audio.h
++++ b/sound/x86/intel_hdmi_audio.h
+@@ -32,7 +32,6 @@
+
+ #include "intel_hdmi_lpe_audio.h"
+
+-#define PCM_INDEX 0
+ #define MAX_PB_STREAMS 1
+ #define MAX_CAP_STREAMS 0
+ #define BYTES_PER_WORD 0x4
+@@ -112,6 +111,8 @@ struct snd_intelhad {
+ struct snd_pcm_chmap *chmap;
+ int tmds_clock_speed;
+ int link_rate;
++ int port; /* fixed */
++ int pipe; /* can change dynamically */
+
+ /* ring buffer (BD) position index */
+ unsigned int bd_head;
+@@ -123,7 +124,6 @@ struct snd_intelhad {
+ unsigned int period_bytes; /* PCM period size in bytes */
+
+ /* internal stuff */
+- unsigned int had_config_offset;
+ union aud_cfg aud_config; /* AUD_CONFIG reg value cache */
+ struct work_struct hdmi_audio_wq;
+ struct mutex mutex; /* for protecting chmap and eld */
+@@ -138,8 +138,9 @@ struct snd_intelhad_card {
+ /* internal stuff */
+ int irq;
+ void __iomem *mmio_start;
++ int num_pipes;
+ int num_ports;
+- struct snd_intelhad pcm_ctx[3];
++ struct snd_intelhad pcm_ctx[3]; /* one for each port */
+ };
+
+ #endif /* _INTEL_HDMI_AUDIO_ */
+--
+cgit v1.1
+