From 0864aef7c5ed4e20b71d2367e1381b1e5b3ff530 Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 31 May 2019 11:17:54 +0800 Subject: [PATCH 1/2] ASoC: SOF: Intel: hda: make sure DMA is start/stop by read the RUN bit As per the HW recommendation, after setting the RUN bit (start as 1, stop as 0), software must read the bit back to make sure the bit is set right, before modifying related control registers/re-starting the DMA engine. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-stream.c | 22 ++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index ddfd80b44e6e8c..74f086056cae6d 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -217,6 +217,9 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, { struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); + u32 dma_start = SOF_HDA_SD_CTL_DMA_START; + int ret; + u32 run; /* cmd must be for audio stream */ switch (cmd) { @@ -234,6 +237,16 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK); + ret = snd_sof_dsp_read_poll_timeout(sdev, + HDA_DSP_HDA_BAR, + sd_offset, run, + ((run & dma_start) == dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + hstream->running = true; break; case SNDRV_PCM_TRIGGER_SUSPEND: @@ -244,6 +257,15 @@ int hda_dsp_stream_trigger(struct snd_sof_dev *sdev, SOF_HDA_SD_CTL_DMA_START | SOF_HDA_CL_DMA_SD_INT_MASK, 0x0); + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK); diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index 430e84e6c8c608..21a7e7782d73cf 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -158,6 +158,12 @@ #define HDA_DSP_MBOX_UPLINK_OFFSET 0x81000 #define HDA_DSP_STREAM_RESET_TIMEOUT 300 +/* + * Timeout in us, for setting the stream RUN bit, during + * start/stop the stream. The timeout expires if new RUN bit + * value cannot be read back within the specified time. + */ +#define HDA_DSP_STREAM_RUN_TIMEOUT 300 #define HDA_DSP_CL_TRIGGER_TIMEOUT 300 #define HDA_DSP_SPIB_ENABLE 1 From 16dc2ab8d67b979cf4a0cceb312eaf841b8b34bb Mon Sep 17 00:00:00 2001 From: Zhu Yingjiang Date: Fri, 31 May 2019 11:21:03 +0800 Subject: [PATCH 2/2] ASoC: SOF: Intel: hda: make sure RUN bit setting to 0 during clear stream status Beforing clearing stream statuses, ensure RUN bit update has taken effect by reading the value back. Signed-off-by: Zhu Yingjiang --- sound/soc/sof/intel/hda-stream.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c index 74f086056cae6d..0d2815eefd3cdc 100644 --- a/sound/soc/sof/intel/hda-stream.c +++ b/sound/soc/sof/intel/hda-stream.c @@ -295,7 +295,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_stream *hstream = &stream->hstream; int sd_offset = SOF_STREAM_SD_OFFSET(hstream); int ret, timeout = HDA_DSP_STREAM_RESET_TIMEOUT; + u32 dma_start = SOF_HDA_SD_CTL_DMA_START; u32 val, mask; + u32 run; if (!stream) { dev_err(sdev->dev, "error: no stream available\n"); @@ -316,6 +318,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK, @@ -368,6 +380,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_SD_CTL_DMA_START, 0); + + ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_HDA_BAR, + sd_offset, run, + !(run & dma_start), + HDA_DSP_REG_POLL_INTERVAL_US, + HDA_DSP_STREAM_RUN_TIMEOUT); + + if (ret) + return ret; + snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset + SOF_HDA_ADSP_REG_CL_SD_STS, SOF_HDA_CL_DMA_SD_INT_MASK,