summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2017-04-27 12:02:30 -0400
committerVille Syrjälä <ville.syrjala@linux.intel.com>2017-05-03 09:24:00 -0400
commit8a2d6ae1f737fd22eaeadd0dc32b85c92f239025 (patch)
tree738c1528fea69391a67b27648e976488c046532a
parentb4eb0d522fcba0ee819f955fd3279ff4682b8b33 (diff)
ALSA: x86: Register multiple PCM devices for the LPE audio card
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>
-rw-r--r--drivers/gpu/drm/i915/intel_lpe_audio.c19
-rw-r--r--include/drm/intel_lpe_audio.h6
-rw-r--r--sound/x86/intel_hdmi_audio.c126
-rw-r--r--sound/x86/intel_hdmi_audio.h7
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 bdbc235141b5..3bf65288ffff 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)
111 pinfo.size_data = sizeof(*pdata); 111 pinfo.size_data = sizeof(*pdata);
112 pinfo.dma_mask = DMA_BIT_MASK(32); 112 pinfo.dma_mask = DMA_BIT_MASK(32);
113 113
114 pdata->port.pipe = -1; 114 pdata->num_pipes = INTEL_INFO(dev_priv)->num_pipes;
115 pdata->num_ports = IS_CHERRYVIEW(dev_priv) ? 3 : 2; /* B,C,D or B,C */
116 pdata->port[0].pipe = -1;
117 pdata->port[1].pipe = -1;
118 pdata->port[2].pipe = -1;
115 spin_lock_init(&pdata->lpe_audio_slock); 119 spin_lock_init(&pdata->lpe_audio_slock);
116 120
117 platdev = platform_device_register_full(&pinfo); 121 platdev = platform_device_register_full(&pinfo);
@@ -319,7 +323,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
319 enum pipe pipe, enum port port, 323 enum pipe pipe, enum port port,
320 const void *eld, int ls_clock, bool dp_output) 324 const void *eld, int ls_clock, bool dp_output)
321{ 325{
322 unsigned long irq_flags; 326 unsigned long irqflags;
323 struct intel_hdmi_lpe_audio_pdata *pdata; 327 struct intel_hdmi_lpe_audio_pdata *pdata;
324 struct intel_hdmi_lpe_audio_port_pdata *ppdata; 328 struct intel_hdmi_lpe_audio_port_pdata *ppdata;
325 u32 audio_enable; 329 u32 audio_enable;
@@ -328,14 +332,12 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
328 return; 332 return;
329 333
330 pdata = dev_get_platdata(&dev_priv->lpe_audio.platdev->dev); 334 pdata = dev_get_platdata(&dev_priv->lpe_audio.platdev->dev);
331 ppdata = &pdata->port; 335 ppdata = &pdata->port[port - PORT_B];
332 336
333 spin_lock_irqsave(&pdata->lpe_audio_slock, irq_flags); 337 spin_lock_irqsave(&pdata->lpe_audio_slock, irqflags);
334 338
335 audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port)); 339 audio_enable = I915_READ(VLV_AUD_PORT_EN_DBG(port));
336 340
337 ppdata->port = port;
338
339 if (eld != NULL) { 341 if (eld != NULL) {
340 memcpy(ppdata->eld, eld, HDMI_MAX_ELD_BYTES); 342 memcpy(ppdata->eld, eld, HDMI_MAX_ELD_BYTES);
341 ppdata->pipe = pipe; 343 ppdata->pipe = pipe;
@@ -357,8 +359,7 @@ void intel_lpe_audio_notify(struct drm_i915_private *dev_priv,
357 } 359 }
358 360
359 if (pdata->notify_audio_lpe) 361 if (pdata->notify_audio_lpe)
360 pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev); 362 pdata->notify_audio_lpe(dev_priv->lpe_audio.platdev, port - PORT_B);
361 363
362 spin_unlock_irqrestore(&pdata->lpe_audio_slock, 364 spin_unlock_irqrestore(&pdata->lpe_audio_slock, irqflags);
363 irq_flags);
364} 365}
diff --git a/include/drm/intel_lpe_audio.h b/include/drm/intel_lpe_audio.h
index 211f1cd61153..b6121c8fe539 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 {
40}; 40};
41 41
42struct intel_hdmi_lpe_audio_pdata { 42struct intel_hdmi_lpe_audio_pdata {
43 struct intel_hdmi_lpe_audio_port_pdata port; 43 struct intel_hdmi_lpe_audio_port_pdata port[3]; /* for ports B,C,D */
44 int num_ports;
45 int num_pipes;
44 46
45 void (*notify_audio_lpe)(struct platform_device *pdev); 47 void (*notify_audio_lpe)(struct platform_device *pdev, int port); /* port: 0==B,1==C,2==D */
46 spinlock_t lpe_audio_slock; 48 spinlock_t lpe_audio_slock;
47}; 49};
48 50
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c
index 12fae26e70bb..909391d5270c 100644
--- a/sound/x86/intel_hdmi_audio.c
+++ b/sound/x86/intel_hdmi_audio.c
@@ -42,6 +42,8 @@
42#include <drm/intel_lpe_audio.h> 42#include <drm/intel_lpe_audio.h>
43#include "intel_hdmi_audio.h" 43#include "intel_hdmi_audio.h"
44 44
45#define for_each_pipe(card_ctx, pipe) \
46 for ((pipe) = 0; (pipe) < (card_ctx)->num_pipes; (pipe)++)
45#define for_each_port(card_ctx, port) \ 47#define for_each_port(card_ctx, port) \
46 for ((port) = 0; (port) < (card_ctx)->num_ports; (port)++) 48 for ((port) = 0; (port) < (card_ctx)->num_ports; (port)++)
47 49
@@ -192,15 +194,30 @@ static void had_substream_put(struct snd_intelhad *intelhaddata)
192 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags); 194 spin_unlock_irqrestore(&intelhaddata->had_spinlock, flags);
193} 195}
194 196
197static u32 had_config_offset(int pipe)
198{
199 switch (pipe) {
200 default:
201 case 0:
202 return AUDIO_HDMI_CONFIG_A;
203 case 1:
204 return AUDIO_HDMI_CONFIG_B;
205 case 2:
206 return AUDIO_HDMI_CONFIG_C;
207 }
208}
209
195/* Register access functions */ 210/* Register access functions */
196static u32 had_read_register_raw(struct snd_intelhad *ctx, u32 reg) 211static u32 had_read_register_raw(struct snd_intelhad_card *card_ctx,
212 int pipe, u32 reg)
197{ 213{
198 return ioread32(ctx->card_ctx->mmio_start + ctx->had_config_offset + reg); 214 return ioread32(card_ctx->mmio_start + had_config_offset(pipe) + reg);
199} 215}
200 216
201static void had_write_register_raw(struct snd_intelhad *ctx, u32 reg, u32 val) 217static void had_write_register_raw(struct snd_intelhad_card *card_ctx,
218 int pipe, u32 reg, u32 val)
202{ 219{
203 iowrite32(val, ctx->card_ctx->mmio_start + ctx->had_config_offset + reg); 220 iowrite32(val, card_ctx->mmio_start + had_config_offset(pipe) + reg);
204} 221}
205 222
206static void had_read_register(struct snd_intelhad *ctx, u32 reg, u32 *val) 223static 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)
208 if (!ctx->connected) 225 if (!ctx->connected)
209 *val = 0; 226 *val = 0;
210 else 227 else
211 *val = had_read_register_raw(ctx, reg); 228 *val = had_read_register_raw(ctx->card_ctx, ctx->pipe, reg);
212} 229}
213 230
214static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) 231static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
215{ 232{
216 if (ctx->connected) 233 if (ctx->connected)
217 had_write_register_raw(ctx, reg, val); 234 had_write_register_raw(ctx->card_ctx, ctx->pipe, reg, val);
218} 235}
219 236
220/* 237/*
@@ -1361,6 +1378,9 @@ static void had_process_hot_plug(struct snd_intelhad *intelhaddata)
1361 return; 1378 return;
1362 } 1379 }
1363 1380
1381 /* Disable Audio */
1382 had_enable_audio(intelhaddata, false);
1383
1364 intelhaddata->connected = true; 1384 intelhaddata->connected = true;
1365 dev_dbg(intelhaddata->dev, 1385 dev_dbg(intelhaddata->dev,
1366 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n", 1386 "%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
@@ -1523,26 +1543,31 @@ static const struct snd_kcontrol_new had_controls[] = {
1523static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id) 1543static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
1524{ 1544{
1525 struct snd_intelhad_card *card_ctx = dev_id; 1545 struct snd_intelhad_card *card_ctx = dev_id;
1526 int port; 1546 u32 audio_stat[3] = {};
1547 int pipe, port;
1548
1549 for_each_pipe(card_ctx, pipe) {
1550 /* use raw register access to ack IRQs even while disconnected */
1551 audio_stat[pipe] = had_read_register_raw(card_ctx, pipe,
1552 AUD_HDMI_STATUS) &
1553 (HDMI_AUDIO_UNDERRUN | HDMI_AUDIO_BUFFER_DONE);
1554
1555 if (audio_stat[pipe])
1556 had_write_register_raw(card_ctx, pipe,
1557 AUD_HDMI_STATUS, audio_stat[pipe]);
1558 }
1527 1559
1528 for_each_port(card_ctx, port) { 1560 for_each_port(card_ctx, port) {
1529 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; 1561 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
1530 u32 audio_stat; 1562 int pipe = ctx->pipe;
1531 1563
1532 /* use raw register access to ack IRQs even while disconnected */ 1564 if (pipe < 0)
1533 audio_stat = had_read_register_raw(ctx, AUD_HDMI_STATUS); 1565 continue;
1534
1535 if (audio_stat & HDMI_AUDIO_UNDERRUN) {
1536 had_write_register_raw(ctx, AUD_HDMI_STATUS,
1537 HDMI_AUDIO_UNDERRUN);
1538 had_process_buffer_underrun(ctx);
1539 }
1540 1566
1541 if (audio_stat & HDMI_AUDIO_BUFFER_DONE) { 1567 if (audio_stat[pipe] & HDMI_AUDIO_BUFFER_DONE)
1542 had_write_register_raw(ctx, AUD_HDMI_STATUS,
1543 HDMI_AUDIO_BUFFER_DONE);
1544 had_process_buffer_done(ctx); 1568 had_process_buffer_done(ctx);
1545 } 1569 if (audio_stat[pipe] & HDMI_AUDIO_UNDERRUN)
1570 had_process_buffer_underrun(ctx);
1546 } 1571 }
1547 1572
1548 return IRQ_HANDLED; 1573 return IRQ_HANDLED;
@@ -1551,16 +1576,12 @@ static irqreturn_t display_pipe_interrupt_handler(int irq, void *dev_id)
1551/* 1576/*
1552 * monitor plug/unplug notification from i915; just kick off the work 1577 * monitor plug/unplug notification from i915; just kick off the work
1553 */ 1578 */
1554static void notify_audio_lpe(struct platform_device *pdev) 1579static void notify_audio_lpe(struct platform_device *pdev, int port)
1555{ 1580{
1556 struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev); 1581 struct snd_intelhad_card *card_ctx = platform_get_drvdata(pdev);
1557 int port; 1582 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
1558 1583
1559 for_each_port(card_ctx, port) { 1584 schedule_work(&ctx->hdmi_audio_wq);
1560 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
1561
1562 schedule_work(&ctx->hdmi_audio_wq);
1563 }
1564} 1585}
1565 1586
1566/* the work to handle monitor hot plug/unplug */ 1587/* the work to handle monitor hot plug/unplug */
@@ -1569,34 +1590,27 @@ static void had_audio_wq(struct work_struct *work)
1569 struct snd_intelhad *ctx = 1590 struct snd_intelhad *ctx =
1570 container_of(work, struct snd_intelhad, hdmi_audio_wq); 1591 container_of(work, struct snd_intelhad, hdmi_audio_wq);
1571 struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data; 1592 struct intel_hdmi_lpe_audio_pdata *pdata = ctx->dev->platform_data;
1572 struct intel_hdmi_lpe_audio_port_pdata *ppdata = &pdata->port; 1593 struct intel_hdmi_lpe_audio_port_pdata *ppdata = &pdata->port[ctx->port];
1573 1594
1574 pm_runtime_get_sync(ctx->dev); 1595 pm_runtime_get_sync(ctx->dev);
1575 mutex_lock(&ctx->mutex); 1596 mutex_lock(&ctx->mutex);
1576 if (ppdata->pipe < 0) { 1597 if (ppdata->pipe < 0) {
1577 dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG\n", 1598 dev_dbg(ctx->dev, "%s: Event: HAD_NOTIFY_HOT_UNPLUG : port = %d\n",
1578 __func__); 1599 __func__, ctx->port);
1600
1579 memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */ 1601 memset(ctx->eld, 0, sizeof(ctx->eld)); /* clear the old ELD */
1602
1603 ctx->dp_output = false;
1604 ctx->tmds_clock_speed = 0;
1605 ctx->link_rate = 0;
1606
1607 /* Shut down the stream */
1580 had_process_hot_unplug(ctx); 1608 had_process_hot_unplug(ctx);
1609
1610 ctx->pipe = -1;
1581 } else { 1611 } else {
1582 dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n", 1612 dev_dbg(ctx->dev, "%s: HAD_NOTIFY_ELD : port = %d, tmds = %d\n",
1583 __func__, ppdata->port, ppdata->ls_clock); 1613 __func__, ctx->port, ppdata->ls_clock);
1584
1585 switch (ppdata->pipe) {
1586 case 0:
1587 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A;
1588 break;
1589 case 1:
1590 ctx->had_config_offset = AUDIO_HDMI_CONFIG_B;
1591 break;
1592 case 2:
1593 ctx->had_config_offset = AUDIO_HDMI_CONFIG_C;
1594 break;
1595 default:
1596 dev_dbg(ctx->dev, "Invalid pipe %d\n",
1597 ppdata->pipe);
1598 break;
1599 }
1600 1614
1601 memcpy(ctx->eld, ppdata->eld, sizeof(ctx->eld)); 1615 memcpy(ctx->eld, ppdata->eld, sizeof(ctx->eld));
1602 1616
@@ -1609,11 +1623,18 @@ static void had_audio_wq(struct work_struct *work)
1609 ctx->link_rate = 0; 1623 ctx->link_rate = 0;
1610 } 1624 }
1611 1625
1626 /*
1627 * Shut down the stream before we change
1628 * the pipe assignment for this pcm device
1629 */
1612 had_process_hot_plug(ctx); 1630 had_process_hot_plug(ctx);
1613 1631
1614 /* Process mode change if stream is active */ 1632 ctx->pipe = ppdata->pipe;
1633
1634 /* Restart the stream if necessary */
1615 had_process_mode_change(ctx); 1635 had_process_mode_change(ctx);
1616 } 1636 }
1637
1617 mutex_unlock(&ctx->mutex); 1638 mutex_unlock(&ctx->mutex);
1618 pm_runtime_mark_last_busy(ctx->dev); 1639 pm_runtime_mark_last_busy(ctx->dev);
1619 pm_runtime_put_autosuspend(ctx->dev); 1640 pm_runtime_put_autosuspend(ctx->dev);
@@ -1794,7 +1815,8 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
1794 1815
1795 init_channel_allocations(); 1816 init_channel_allocations();
1796 1817
1797 card_ctx->num_ports = 1; 1818 card_ctx->num_pipes = pdata->num_pipes;
1819 card_ctx->num_ports = pdata->num_ports;
1798 1820
1799 for_each_port(card_ctx, port) { 1821 for_each_port(card_ctx, port) {
1800 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port]; 1822 struct snd_intelhad *ctx = &card_ctx->pcm_ctx[port];
@@ -1802,12 +1824,12 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev)
1802 1824
1803 ctx->card_ctx = card_ctx; 1825 ctx->card_ctx = card_ctx;
1804 ctx->dev = card_ctx->dev; 1826 ctx->dev = card_ctx->dev;
1827 ctx->port = port;
1828 ctx->pipe = -1;
1805 1829
1806 INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq); 1830 INIT_WORK(&ctx->hdmi_audio_wq, had_audio_wq);
1807 1831
1808 ctx->had_config_offset = AUDIO_HDMI_CONFIG_A; 1832 ret = snd_pcm_new(card, INTEL_HAD, port, MAX_PB_STREAMS,
1809
1810 ret = snd_pcm_new(card, INTEL_HAD, PCM_INDEX, MAX_PB_STREAMS,
1811 MAX_CAP_STREAMS, &pcm); 1833 MAX_CAP_STREAMS, &pcm);
1812 if (ret) 1834 if (ret)
1813 goto err; 1835 goto err;
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h
index 2725964ebc46..0d91bb5dbab7 100644
--- a/sound/x86/intel_hdmi_audio.h
+++ b/sound/x86/intel_hdmi_audio.h
@@ -32,7 +32,6 @@
32 32
33#include "intel_hdmi_lpe_audio.h" 33#include "intel_hdmi_lpe_audio.h"
34 34
35#define PCM_INDEX 0
36#define MAX_PB_STREAMS 1 35#define MAX_PB_STREAMS 1
37#define MAX_CAP_STREAMS 0 36#define MAX_CAP_STREAMS 0
38#define BYTES_PER_WORD 0x4 37#define BYTES_PER_WORD 0x4
@@ -112,6 +111,8 @@ struct snd_intelhad {
112 struct snd_pcm_chmap *chmap; 111 struct snd_pcm_chmap *chmap;
113 int tmds_clock_speed; 112 int tmds_clock_speed;
114 int link_rate; 113 int link_rate;
114 int port; /* fixed */
115 int pipe; /* can change dynamically */
115 116
116 /* ring buffer (BD) position index */ 117 /* ring buffer (BD) position index */
117 unsigned int bd_head; 118 unsigned int bd_head;
@@ -123,7 +124,6 @@ struct snd_intelhad {
123 unsigned int period_bytes; /* PCM period size in bytes */ 124 unsigned int period_bytes; /* PCM period size in bytes */
124 125
125 /* internal stuff */ 126 /* internal stuff */
126 unsigned int had_config_offset;
127 union aud_cfg aud_config; /* AUD_CONFIG reg value cache */ 127 union aud_cfg aud_config; /* AUD_CONFIG reg value cache */
128 struct work_struct hdmi_audio_wq; 128 struct work_struct hdmi_audio_wq;
129 struct mutex mutex; /* for protecting chmap and eld */ 129 struct mutex mutex; /* for protecting chmap and eld */
@@ -138,8 +138,9 @@ struct snd_intelhad_card {
138 /* internal stuff */ 138 /* internal stuff */
139 int irq; 139 int irq;
140 void __iomem *mmio_start; 140 void __iomem *mmio_start;
141 int num_pipes;
141 int num_ports; 142 int num_ports;
142 struct snd_intelhad pcm_ctx[3]; 143 struct snd_intelhad pcm_ctx[3]; /* one for each port */
143}; 144};
144 145
145#endif /* _INTEL_HDMI_AUDIO_ */ 146#endif /* _INTEL_HDMI_AUDIO_ */