diff options
Diffstat (limited to 'sound/soc/intel/skylake/skl-pcm.c')
-rw-r--r-- | sound/soc/intel/skylake/skl-pcm.c | 161 |
1 files changed, 143 insertions, 18 deletions
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b89ae6f7c096..dab0900eef26 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -25,6 +25,8 @@ #include <sound/soc.h> #include "skl.h" #include "skl-topology.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" #define HDA_MONO 1 #define HDA_STEREO 2 @@ -36,6 +38,7 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ SNDRV_PCM_INFO_HAS_LINK_ATIME | @@ -203,6 +206,23 @@ static int skl_get_format(struct snd_pcm_substream *substream, return format_val; } +static int skl_be_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct skl *skl = get_skl_ctx(dai->dev); + struct skl_sst *ctx = skl->skl_sst; + struct skl_module_cfg *mconfig; + + if ((dai->playback_active > 1) || (dai->capture_active > 1)) + return 0; + + mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); + if (mconfig == NULL) + return -EINVAL; + + return skl_dsp_set_dma_control(ctx, mconfig); +} + static int skl_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -272,6 +292,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; + struct skl *skl = ebus_to_skl(ebus); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -285,6 +306,16 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, NULL); skl_set_suspend_active(substream, dai, false); + /* + * check if close is for "Reference Pin" and set back the + * CGCTL.MISCBDCGE if disabled by driver + */ + if (!strncmp(dai->name, "Reference Pin", 13) && + skl->skl_sst->miscbdcg_disabled) { + skl->skl_sst->enable_miscbdcge(dai->dev, true); + skl->skl_sst->miscbdcg_disabled = false; + } + kfree(dma_params); } @@ -380,6 +411,15 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: skl_pcm_prepare(substream, dai); + /* + * enable DMA Resume enable bit for the stream, set the dpib + * & lpib position to resune before starting the DMA + */ + snd_hdac_ext_stream_drsm_enable(ebus, true, + hdac_stream(stream)->index); + snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); + snd_hdac_ext_stream_set_lpib(stream, stream->lpib); + case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* @@ -408,8 +448,17 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, return ret; ret = skl_decoupled_trigger(substream, cmd); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) { + /* save the dpib and lpib positions */ + stream->dpib = readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(stream)->index)); + + stream->lpib = snd_hdac_stream_get_pos_lpib( + hdac_stream(stream)); snd_hdac_ext_stream_decouple(ebus, stream, false); + } break; default: @@ -426,7 +475,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct hdac_ext_stream *link_dev; struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct skl_dma_params *dma_params; + struct hdac_ext_dma_params *dma_params; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct skl_pipe_params p_params = {0}; @@ -438,11 +487,9 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); /* set the stream tag in the codec dai dma params */ - dma_params = (struct skl_dma_params *) - snd_soc_dai_get_dma_data(codec_dai, substream); + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; - snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params); p_params.s_fmt = snd_pcm_format_width(params_format(params)); p_params.ch = params_channels(params); @@ -465,11 +512,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct hdac_ext_link *link; - if (link_dev->link_prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } - dma_params = (struct skl_dma_params *) snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -477,14 +519,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - snd_hdac_ext_link_stream_reset(link_dev); - - snd_hdac_ext_link_stream_setup(link_dev, format_val); - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); if (!link) return -EINVAL; + snd_hdac_ext_bus_link_power_up(link); + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); link_dev->link_prepared = 1; @@ -496,12 +539,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; @@ -509,6 +556,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(ebus, stream, false); break; default: @@ -554,6 +603,7 @@ static struct snd_soc_dai_ops skl_dmic_dai_ops = { static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { .hw_params = skl_be_hw_params, + .prepare = skl_be_prepare, }; static struct snd_soc_dai_ops skl_link_dai_ops = { @@ -626,6 +676,51 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "HDMI1 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI1 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "HDMI2 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI2 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, +{ + .name = "HDMI3 Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "HDMI3 Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | + SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}, /* BE CPU Dais */ { @@ -665,14 +760,41 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { - .name = "iDisp Pin", + .name = "iDisp1 Pin", .ops = &skl_link_dai_ops, .playback = { - .stream_name = "iDisp Tx", + .stream_name = "iDisp1 Tx", .channels_min = HDA_STEREO, .channels_max = HDA_STEREO, .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "iDisp2 Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp2 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "iDisp3 Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp3 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| + SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, }, }, { @@ -830,6 +952,9 @@ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, delay += hstream->bufsize; } + if (hstream->bufsize == delay) + delay = 0; + if (delay >= hstream->period_bytes) { dev_info(bus->dev, "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", |