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);
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;
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;
}
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);
}
#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)++)
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)
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);
}
/*
return;
}
+ /* Disable Audio */
+ had_enable_audio(intelhaddata, false);
+
intelhaddata->connected = true;
dev_dbg(intelhaddata->dev,
"%s @ %d:DEBUG PLUG/UNPLUG : HAD_DRV_CONNECTED\n",
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;
/*
* 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 */
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));
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);
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];
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;