Merge series "ASoC: SOF: Intel: hda: Enable DMI L1 for power savings" from Ranjani Sridharan <ranjani.sridharan@linux.intel.com>:
This series includes 2 patches that enable DMI L1 for D0I3-compatible streams and trace DMA stream to maximise power savings on Intel HDA platforms. v2 changes: FIx compilation error when probes feature is enabled in SOF Kconfig. Ranjani Sridharan (2): ASoC: SOF: Intel: hda: enable DMI L1 for D0i3-compatible streams ASoC: SOF: Intel: hda: Enable DMI L1 for trace sound/soc/sof/intel/hda-compress.c | 2 +- sound/soc/sof/intel/hda-loader.c | 2 +- sound/soc/sof/intel/hda-pcm.c | 16 ++++++++++++- sound/soc/sof/intel/hda-stream.c | 38 +++++++++++++++++------------- sound/soc/sof/intel/hda-trace.c | 4 ++-- sound/soc/sof/intel/hda.h | 6 ++++- 6 files changed, 46 insertions(+), 22 deletions(-) -- 2.25.1
This commit is contained in:
commit
4c87f71565
|
@ -25,7 +25,7 @@ int hda_probe_compr_assign(struct snd_sof_dev *sdev,
|
|||
{
|
||||
struct hdac_ext_stream *stream;
|
||||
|
||||
stream = hda_dsp_stream_get(sdev, cstream->direction);
|
||||
stream = hda_dsp_stream_get(sdev, cstream->direction, 0);
|
||||
if (!stream)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
|
|||
struct pci_dev *pci = to_pci_dev(sdev->dev);
|
||||
int ret;
|
||||
|
||||
dsp_stream = hda_dsp_stream_get(sdev, direction);
|
||||
dsp_stream = hda_dsp_stream_get(sdev, direction, 0);
|
||||
|
||||
if (!dsp_stream) {
|
||||
dev_err(sdev->dev, "error: no stream available\n");
|
||||
|
|
|
@ -215,11 +215,25 @@ found:
|
|||
int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
|
||||
struct snd_soc_component *scomp = sdev->component;
|
||||
struct hdac_ext_stream *dsp_stream;
|
||||
struct snd_sof_pcm *spcm;
|
||||
int direction = substream->stream;
|
||||
u32 flags = 0;
|
||||
|
||||
dsp_stream = hda_dsp_stream_get(sdev, direction);
|
||||
spcm = snd_sof_find_spcm_dai(scomp, rtd);
|
||||
if (!spcm) {
|
||||
dev_err(sdev->dev, "error: can't find PCM with DAI ID %d\n", rtd->dai_link->id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* All playback and D0i3 compatible streams are DMI L1 capable */
|
||||
if (direction == SNDRV_PCM_STREAM_PLAYBACK ||
|
||||
spcm->stream[substream->stream].d0i3_compatible)
|
||||
flags |= SOF_HDA_STREAM_DMI_L1_COMPATIBLE;
|
||||
|
||||
dsp_stream = hda_dsp_stream_get(sdev, direction, flags);
|
||||
if (!dsp_stream) {
|
||||
dev_err(sdev->dev, "error: no stream available\n");
|
||||
return -ENODEV;
|
||||
|
|
|
@ -155,7 +155,7 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
|
|||
|
||||
/* get next unused stream */
|
||||
struct hdac_ext_stream *
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
struct sof_intel_hda_stream *hda_stream;
|
||||
|
@ -183,18 +183,22 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
|
|||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
/* stream found ? */
|
||||
if (!stream)
|
||||
if (!stream) {
|
||||
dev_err(sdev->dev, "error: no free %s streams\n",
|
||||
direction == SNDRV_PCM_STREAM_PLAYBACK ?
|
||||
"playback" : "capture");
|
||||
return stream;
|
||||
}
|
||||
|
||||
hda_stream->flags = flags;
|
||||
|
||||
/*
|
||||
* Disable DMI Link L1 entry when capture stream is opened.
|
||||
* Prevent DMI Link L1 entry for streams that don't support it.
|
||||
* Workaround to address a known issue with host DMA that results
|
||||
* in xruns during pause/release in capture scenarios.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
|
||||
if (stream && direction == SNDRV_PCM_STREAM_CAPTURE)
|
||||
if (stream && !(flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE))
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
HDA_VS_INTEL_EM2,
|
||||
HDA_VS_INTEL_EM2_L1SEN, 0);
|
||||
|
@ -206,37 +210,39 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction)
|
|||
int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag)
|
||||
{
|
||||
struct hdac_bus *bus = sof_to_bus(sdev);
|
||||
struct sof_intel_hda_stream *hda_stream;
|
||||
struct hdac_ext_stream *stream;
|
||||
struct hdac_stream *s;
|
||||
bool active_capture_stream = false;
|
||||
bool dmi_l1_enable = true;
|
||||
bool found = false;
|
||||
|
||||
spin_lock_irq(&bus->reg_lock);
|
||||
|
||||
/*
|
||||
* close stream matching the stream tag
|
||||
* and check if there are any open capture streams.
|
||||
* close stream matching the stream tag and check if there are any open streams
|
||||
* that are DMI L1 incompatible.
|
||||
*/
|
||||
list_for_each_entry(s, &bus->stream_list, list) {
|
||||
stream = stream_to_hdac_ext_stream(s);
|
||||
hda_stream = container_of(stream, struct sof_intel_hda_stream, hda_stream);
|
||||
|
||||
if (!s->opened)
|
||||
continue;
|
||||
|
||||
if (s->direction == direction && s->stream_tag == stream_tag) {
|
||||
s->opened = false;
|
||||
found = true;
|
||||
} else if (s->direction == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
active_capture_stream = true;
|
||||
} else if (!(hda_stream->flags & SOF_HDA_STREAM_DMI_L1_COMPATIBLE)) {
|
||||
dmi_l1_enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irq(&bus->reg_lock);
|
||||
|
||||
/* Enable DMI L1 entry if there are no capture streams open */
|
||||
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1))
|
||||
if (!active_capture_stream)
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
|
||||
HDA_VS_INTEL_EM2,
|
||||
HDA_VS_INTEL_EM2_L1SEN,
|
||||
HDA_VS_INTEL_EM2_L1SEN);
|
||||
/* Enable DMI L1 if permitted */
|
||||
if (!IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_ALWAYS_ENABLE_DMI_L1) && dmi_l1_enable)
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, HDA_VS_INTEL_EM2,
|
||||
HDA_VS_INTEL_EM2_L1SEN, HDA_VS_INTEL_EM2_L1SEN);
|
||||
|
||||
if (!found) {
|
||||
dev_dbg(sdev->dev, "stream_tag %d not opened!\n", stream_tag);
|
||||
|
|
|
@ -42,8 +42,8 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
|
|||
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
|
||||
int ret;
|
||||
|
||||
hda->dtrace_stream = hda_dsp_stream_get(sdev,
|
||||
SNDRV_PCM_STREAM_CAPTURE);
|
||||
hda->dtrace_stream = hda_dsp_stream_get(sdev, SNDRV_PCM_STREAM_CAPTURE,
|
||||
SOF_HDA_STREAM_DMI_L1_COMPATIBLE);
|
||||
|
||||
if (!hda->dtrace_stream) {
|
||||
dev_err(sdev->dev,
|
||||
|
|
|
@ -402,6 +402,9 @@ struct sof_intel_dsp_bdl {
|
|||
#define SOF_HDA_PLAYBACK 0
|
||||
#define SOF_HDA_CAPTURE 1
|
||||
|
||||
/* stream flags */
|
||||
#define SOF_HDA_STREAM_DMI_L1_COMPATIBLE 1
|
||||
|
||||
/*
|
||||
* Time in ms for opportunistic D0I3 entry delay.
|
||||
* This has been deliberately chosen to be long to avoid race conditions.
|
||||
|
@ -471,6 +474,7 @@ struct sof_intel_hda_stream {
|
|||
struct hdac_ext_stream hda_stream;
|
||||
struct sof_intel_stream stream;
|
||||
int host_reserved; /* reserve host DMA channel */
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
#define hstream_to_sof_hda_stream(hstream) \
|
||||
|
@ -562,7 +566,7 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
|
|||
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
|
||||
|
||||
struct hdac_ext_stream *
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction);
|
||||
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);
|
||||
int hda_dsp_stream_put(struct snd_sof_dev *sdev, int direction, int stream_tag);
|
||||
int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
|
||||
struct hdac_ext_stream *stream,
|
||||
|
|
Loading…
Reference in New Issue