clear-pkgs-linux-iot-lts2018/0247-ASoC-Intel-Skylake-add...

142 lines
5.0 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ramesh Babu <ramesh.babu@intel.com>
Date: Mon, 23 May 2016 11:39:19 +0530
Subject: [PATCH] ASoC: Intel: Skylake: add support for spib mode
Skylake audio controller sports SPIB capability, which can be
used to inform position of appl pointer to host DMA controller.
When SPIB mode is enabled, driver could write the appl pointer
position in SPIB register. Host DMA will make sure it won't
read/write beyond bytes specified in SPIB register.
SPIB mode will be useful in low power use cases, where DSP could
pre-fetch large buffers to avoid frequent wakes due to
interrupts.
Skylake driver makes use of no_rewind flag and appl_ptr_update
callback to enable and update SPIB register respectively.
Signed-off-by: Ramesh Babu <ramesh.babu@intel.com>
Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
---
sound/soc/intel/skylake/skl-pcm.c | 46 +++++++++++++++++++++++++++++--
1 file changed, 44 insertions(+), 2 deletions(-)
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c
index c82ab7071c15..97617b9ab5a0 100644
--- a/sound/soc/intel/skylake/skl-pcm.c
+++ b/sound/soc/intel/skylake/skl-pcm.c
@@ -46,7 +46,8 @@ static const struct snd_pcm_hardware azx_pcm_hw = {
SNDRV_PCM_INFO_SYNC_START |
SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */
SNDRV_PCM_INFO_HAS_LINK_ATIME |
- SNDRV_PCM_INFO_NO_PERIOD_WAKEUP),
+ SNDRV_PCM_INFO_NO_PERIOD_WAKEUP |
+ SNDRV_PCM_INFO_NO_STATUS_MMAP),
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S32_LE |
SNDRV_PCM_FMTBIT_S24_LE,
@@ -154,6 +155,7 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
unsigned int format_val;
struct hdac_stream *hstream;
struct hdac_ext_stream *stream;
+ struct snd_pcm_runtime *runtime;
int err;
hstream = snd_hdac_get_stream(bus, params->stream,
@@ -179,6 +181,11 @@ int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params)
if (err < 0)
return err;
+ runtime = hdac_stream(stream)->substream->runtime;
+ /* enable SPIB if no_rewinds flag is set */
+ if (runtime->no_rewinds)
+ snd_hdac_ext_stream_spbcap_enable(ebus, 1, hstream->index);
+
hdac_stream(stream)->prepared = 1;
return 0;
@@ -394,6 +401,8 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
{
struct hdac_bus *bus = dev_get_drvdata(dai->dev);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct hdac_stream *hstream = hdac_stream(stream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct skl *skl = get_skl_ctx(dai->dev);
struct skl_module_cfg *mconfig;
int ret;
@@ -402,6 +411,10 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream,
mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream);
+ if (runtime->no_rewinds) {
+ snd_hdac_ext_stream_set_spib(ebus, stream, 0);
+ snd_hdac_ext_stream_spbcap_enable(ebus, 0, hstream->index);
+ }
if (mconfig) {
ret = skl_reset_pipe(skl->skl_sst, mconfig->pipe);
if (ret < 0)
@@ -483,6 +496,7 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
struct skl_module_cfg *mconfig;
struct hdac_bus *bus = get_bus_ctx(substream);
struct hdac_ext_stream *stream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_dapm_widget *w;
int ret;
@@ -508,8 +522,10 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
snd_hdac_ext_stream_set_dpibr(bus, stream,
stream->lpib);
snd_hdac_ext_stream_set_lpib(stream, stream->lpib);
+ if (runtime->no_rewinds)
+ snd_hdac_ext_stream_set_spib(ebus,
+ stream, stream->spib);
}
-
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
/*
@@ -1501,6 +1517,31 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream,
return 0;
}
+/* update SPIB register with appl position */
+static int skl_platform_ack(struct snd_pcm_substream *substream)
+{
+ struct hdac_ext_bus *ebus = get_bus_ctx(substream);
+ struct hdac_ext_stream *estream = get_hdac_ext_stream(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ ssize_t appl_pos, buf_size;
+ u32 spib;
+
+ /* Use spib mode only if no_rewind mode is set */
+ if (runtime->no_rewinds == 0)
+ return 0;
+
+ appl_pos = frames_to_bytes(runtime, runtime->control->appl_ptr);
+ buf_size = frames_to_bytes(runtime, runtime->buffer_size);
+
+ spib = appl_pos % buf_size;
+
+ /* Allowable value for SPIB is 1 byte to max buffer size */
+ spib = (spib == 0) ? buf_size : spib;
+ snd_hdac_ext_stream_set_spib(ebus, estream, spib);
+
+ return 0;
+}
+
static snd_pcm_uframes_t skl_platform_pcm_pointer
(struct snd_pcm_substream *substream)
{
@@ -1608,6 +1649,7 @@ static const struct snd_pcm_ops skl_platform_ops = {
.get_time_info = skl_get_time_info,
.mmap = snd_pcm_lib_default_mmap,
.page = snd_pcm_sgbuf_ops_page,
+ .ack = skl_platform_ack,
};
static void skl_pcm_free(struct snd_pcm *pcm)
--
https://clearlinux.org