summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel
diff options
context:
space:
mode:
authorMark Brown <broonie@kernel.org>2026-08-03 13:18:29 +0100
committerMark Brown <broonie@kernel.org>2026-08-03 13:18:29 +0100
commitd58fe9eabc01543b79decfccfedd50d4c49351ff (patch)
tree0ea477298e1838a42a46b527cb9e744c486cade0 /sound/soc/sof/intel
parentee145d35e44fd5d72eca19221bb65a26b9097c09 (diff)
parent69ddd29d8f078f440256534dcafce463ab1c2d24 (diff)
Merge remote-tracking branch 'asoc/for-7.3' into asoc-next
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c19
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c76
-rw-r--r--sound/soc/sof/intel/hda-dai.c2
-rw-r--r--sound/soc/sof/intel/hda-dsp.c6
-rw-r--r--sound/soc/sof/intel/hda-loader.c11
-rw-r--r--sound/soc/sof/intel/hda-mlink.c35
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c2
-rw-r--r--sound/soc/sof/intel/hda-stream.c18
-rw-r--r--sound/soc/sof/intel/hda.c18
-rw-r--r--sound/soc/sof/intel/hda.h31
-rw-r--r--sound/soc/sof/intel/icl.c10
-rw-r--r--sound/soc/sof/intel/mtl.c23
12 files changed, 206 insertions, 45 deletions
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index 8332d4bda558..aeb34310eebd 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -186,6 +186,7 @@ EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, "SND_SOC_SOF_INTEL_HDA_COMMON"
int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
{
struct hdac_bus *bus = sof_to_bus(sdev);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct hdac_stream *stream;
int sd_offset, ret = 0;
u32 gctl;
@@ -193,6 +194,16 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
if (bus->chip_init)
return 0;
+ /*
+ * The controller reset clears the ACE2+ link DMA stream allocation
+ * constraints; reset the masks to reflect this.
+ */
+ memset(sof_hda->link_dma_active_sdw_mask, 0,
+ sizeof(sof_hda->link_dma_active_sdw_mask));
+ memset(sof_hda->link_dma_active_multi_mask, 0,
+ sizeof(sof_hda->link_dma_active_multi_mask));
+ sof_hda->link_dma_out_hda_used_mask = 0;
+
hda_codec_set_codec_wakeup(sdev, true);
hda_dsp_ctrl_misc_clock_gating(sdev, false);
@@ -223,6 +234,14 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
/* Accept unsolicited responses */
snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+ /* Perform a one-time enumeration of the Multi-Link capability */
+ ret = hda_bus_ml_init(bus);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: failed to enumerate multi-links\n",
+ __func__);
+ goto err;
+ }
+
if (detect_codec)
hda_codec_detect_mask(sdev);
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index b2c559559962..f0be42048db3 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -20,7 +20,7 @@
/* These ops are only applicable for the HDA DAI's in their current form */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
/*
- * This function checks if the host dma channel corresponding
+ * This function checks if the host DMA stream corresponding
* to the link DMA stream_tag argument is assigned to one
* of the FEs connected to the BE DAI.
*/
@@ -42,23 +42,53 @@ static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
}
static struct hdac_ext_stream *
-hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream)
+hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream,
+ enum hda_bus_ml_link_type link_type)
{
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct sof_intel_hda_dev *sof_hda = bus_to_sof_hda(bus);
struct sof_intel_hda_stream *hda_stream;
const struct sof_intel_dsp_desc *chip;
struct snd_sof_dev *sdev;
struct hdac_ext_stream *res = NULL;
struct hdac_stream *hstream = NULL;
-
int stream_dir = substream->stream;
+ bool is_multi = link_type == HDA_BUS_ML_LINK_HDA || link_type == HDA_BUS_ML_LINK_UAOL;
+ bool is_play = stream_dir == SNDRV_PCM_STREAM_PLAYBACK;
+ bool is_sdw = link_type == HDA_BUS_ML_LINK_SDW;
+ bool is_hda = link_type == HDA_BUS_ML_LINK_HDA;
+ u32 concur_block_mask = 0;
+ u32 seq_block_mask = 0;
+ unsigned int stream_idx;
if (!bus->ppcap) {
dev_err(bus->dev, "stream type not supported\n");
return NULL;
}
+ /*
+ * On ACE2+ the link DMA stream allocator must avoid two HW errata,
+ * see the comment on struct sof_intel_hda_dev.
+ *
+ * - Concurrent cross-direction: SoundWire conflicts with HDA, iDisp
+ * and UAOL on the same physical stream index; SSP and DMIC are safe.
+ * - Sequential playback: a stream index previously used by an HDA/iDisp
+ * link cannot drive any non-HDA/iDisp link in the same direction
+ * until the next controller reset.
+ *
+ * The masks are protected by bus->reg_lock; sample them inside the
+ * lock together with the stream walk to keep the decision atomic
+ * with concurrent allocations and releases.
+ */
guard(spinlock_irq)(&bus->reg_lock);
+
+ if (is_sdw)
+ concur_block_mask = sof_hda->link_dma_active_multi_mask[!stream_dir];
+ else if (is_multi)
+ concur_block_mask = sof_hda->link_dma_active_sdw_mask[!stream_dir];
+ if (is_play && !is_hda)
+ seq_block_mask = sof_hda->link_dma_out_hda_used_mask;
+
list_for_each_entry(hstream, &bus->stream_list, list) {
struct hdac_ext_stream *hext_stream =
stream_to_hdac_ext_stream(hstream);
@@ -69,6 +99,12 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
sdev = hda_stream->sdev;
chip = get_chip_info(sdev->pdata);
+ stream_idx = hstream->stream_tag - 1;
+
+ /* skip streams blocked by the ACE2+ allocator constraints */
+ if ((concur_block_mask | seq_block_mask) & BIT(stream_idx))
+ continue;
+
/* check if link is available */
if (!hext_stream->link_locked) {
/*
@@ -95,7 +131,7 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
/*
* This must be a hostless stream.
- * So reserve the host DMA channel.
+ * So reserve the host DMA stream.
*/
hda_stream->host_reserved = 1;
break;
@@ -109,6 +145,16 @@ hda_link_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream
res->link_locked = 1;
res->link_substream = substream;
+
+ stream_idx = res->hstream.stream_tag - 1;
+ if (is_sdw)
+ sof_hda->link_dma_active_sdw_mask[stream_dir] |= BIT(stream_idx);
+ else if (is_multi)
+ sof_hda->link_dma_active_multi_mask[stream_dir] |= BIT(stream_idx);
+
+ /* persistent OUT HDA/iDisp shadow, cleared only on CRST# */
+ if (is_hda && is_play)
+ sof_hda->link_dma_out_hda_used_mask |= BIT(stream_idx);
}
return res;
@@ -143,11 +189,13 @@ static struct hdac_ext_stream *hda_ipc4_get_hext_stream(struct snd_sof_dev *sdev
static struct hdac_ext_stream *hda_assign_hext_stream(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream)
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink)
{
struct hdac_ext_stream *hext_stream;
+ enum hda_bus_ml_link_type link_type = hda_bus_ml_link_get_type(hlink);
- hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream);
+ hext_stream = hda_link_stream_assign(sof_to_bus(sdev), substream, link_type);
if (!hext_stream)
return NULL;
@@ -160,6 +208,22 @@ static void hda_release_hext_stream(struct snd_sof_dev *sdev, struct snd_soc_dai
struct snd_pcm_substream *substream)
{
struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
+ struct sof_intel_hda_dev *sof_hda = sdev->pdata->hw_pdata;
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ int dir = substream->stream;
+ unsigned int stream_idx = hext_stream->hstream.stream_tag - 1;
+
+ /*
+ * Drop the stream index from the per-direction active concurrency masks.
+ * The two masks are mutually exclusive for a given stream/direction
+ * (and a stream of the SSP/DMIC kind appears in neither), so a blind
+ * clear of both is safe and lets us avoid having to remember the
+ * link type at allocation time.
+ */
+ scoped_guard(spinlock_irq, &bus->reg_lock) {
+ sof_hda->link_dma_active_sdw_mask[dir] &= ~BIT(stream_idx);
+ sof_hda->link_dma_active_multi_mask[dir] &= ~BIT(stream_idx);
+ }
snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 15faedeec16d..bb44d4f8a4da 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -188,7 +188,7 @@ static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream) {
if (ops->assign_hext_stream)
- hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
+ hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream, hlink);
}
if (!hext_stream)
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index e9f092f082a1..b9b2bdff4ccb 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -1114,11 +1114,7 @@ static int hda_dsp_s5_quirk(struct snd_sof_dev *sdev)
usleep_range(500, 1000);
/* Restore state for shutdown, back to reset */
- ret = hda_dsp_ctrl_link_reset(sdev, true);
- if (ret < 0)
- return ret;
-
- return ret;
+ return hda_dsp_ctrl_link_reset(sdev, true);
}
int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev)
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 2b3abcf75d55..4347e71337f9 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -216,9 +216,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax)
{
- return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream, false);
+ return hda_data_stream_cleanup(dev, dmab, persistent_buffer, hext_stream,
+ is_iccmax, false);
}
EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
@@ -302,7 +303,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
- persistent_cl_buffer, iccmax_stream);
+ persistent_cl_buffer, iccmax_stream, true);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -458,7 +459,7 @@ cleanup:
* If the cleanup also fails, we return the initial error
*/
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
- persistent_cl_buffer, hext_stream);
+ persistent_cl_buffer, hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -587,7 +588,7 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
cleanup:
/* clean up even in case of error and return the first error */
ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
- hext_stream);
+ hext_stream, false);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index 92314e3b568a..6f02fb5b70ce 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -432,6 +432,10 @@ int hda_bus_ml_init(struct hdac_bus *bus)
if (!bus->mlcap)
return 0;
+ /* Enumeration is a one time operation, skip if already done */
+ if (!list_empty(&bus->hlink_list))
+ return 0;
+
link_count = readl(bus->mlcap + AZX_REG_ML_MLCD) + 1;
dev_dbg(bus->dev, "HDAudio Multi-Link count: %d\n", link_count);
@@ -880,19 +884,6 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
return 0;
} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, "SND_SOC_SOF_HDA_MLINK");
-void hda_bus_ml_put_all(struct hdac_bus *bus)
-{
- struct hdac_ext_link *hlink;
-
- list_for_each_entry(hlink, &bus->hlink_list, list) {
- struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
-
- if (!h2link->alt)
- snd_hdac_ext_bus_link_put(bus, hlink);
- }
-}
-EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK");
-
void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
@@ -903,6 +894,24 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
}
EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK");
+enum hda_bus_ml_link_type hda_bus_ml_link_get_type(struct hdac_ext_link *hlink)
+{
+ struct hdac_ext2_link *h2link = hdac_ext_link_to_ext2(hlink);
+
+ if (!h2link->alt)
+ return HDA_BUS_ML_LINK_HDA;
+
+ switch (h2link->elid) {
+ case AZX_REG_ML_LEPTR_ID_SDW:
+ return HDA_BUS_ML_LINK_SDW;
+ case AZX_REG_ML_LEPTR_ID_INTEL_UAOL:
+ return HDA_BUS_ML_LINK_UAOL;
+ default:
+ return HDA_BUS_ML_LINK_OTHER;
+ }
+}
+EXPORT_SYMBOL_NS(hda_bus_ml_link_get_type, "SND_SOC_SOF_HDA_MLINK");
+
int hda_bus_ml_resume(struct hdac_bus *bus)
{
struct hdac_ext_link *hlink;
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
index 7351a0870725..ba9fbd662b85 100644
--- a/sound/soc/sof/intel/hda-sdw-bpt.c
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -163,7 +163,7 @@ static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream
u32 mask;
int ret;
- ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, true);
+ ret = hda_data_stream_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream, false, true);
if (ret < 0) {
dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n",
__func__);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 5c1f3b427cdb..c95230487a1b 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -198,13 +198,18 @@ int hda_dsp_stream_spib_config(struct snd_sof_dev *sdev,
mask = (1 << hstream->index);
+ /* Reset the spib_addr before disabling SPIB */
+ if (!enable)
+ sof_io_write(sdev, hstream->spib_addr, 0);
+
/* enable/disable SPIB for the stream */
snd_sof_dsp_update_bits(sdev, HDA_DSP_SPIB_BAR,
SOF_HDA_ADSP_REG_CL_SPBFIFO_SPBFCCTL, mask,
enable << hstream->index);
/* set the SPIB value */
- sof_io_write(sdev, hstream->spib_addr, size);
+ if (enable)
+ sof_io_write(sdev, hstream->spib_addr, size);
return 0;
}
@@ -608,6 +613,9 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return ret;
}
+ /* Host DMA is not running */
+ hstream->running = false;
+
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR,
sd_offset + SOF_HDA_ADSP_REG_SD_STS,
SOF_HDA_CL_DMA_SD_INT_MASK,
@@ -1323,16 +1331,18 @@ out_put:
EXPORT_SYMBOL_NS(hda_data_stream_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = hdac_stream(hext_stream);
int sd_offset = SOF_STREAM_SD_OFFSET(hstream);
int ret = 0;
- if (hstream->direction == SNDRV_PCM_STREAM_PLAYBACK)
+ if (!is_iccmax)
ret = hda_dsp_stream_spib_config(sdev, hext_stream, HDA_DSP_SPIB_DISABLE, 0);
- else
+
+ if (hstream->direction == SNDRV_PCM_STREAM_CAPTURE)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_SD_CTL_DMA_START, 0);
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index dc85903b8d46..4dbba9186b29 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -421,6 +421,20 @@ static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { }
/* pre fw run operations */
int hda_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+ int ret;
+
+ /* Power down DSP if left enabled to ensure a clean boot state. */
+ if (hda_dsp_core_is_enabled(sdev, chip->host_managed_cores_mask)) {
+ dev_dbg(sdev->dev, "DSP core enabled, power down DSP first\n");
+
+ ret = chip->power_down_dsp(sdev);
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ }
+
/* disable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, false);
}
@@ -625,8 +639,6 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
return ret;
}
- hda_bus_ml_init(bus);
-
/* Skip SoundWire if it is not supported */
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
@@ -670,8 +682,6 @@ skip_soundwire:
if (!HDA_IDISP_CODEC(bus->codec_mask))
hda_codec_i915_display_power(sdev, false);
- hda_bus_ml_put_all(bus);
-
return 0;
}
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3f0966477ace..1609589929a1 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -523,6 +523,29 @@ struct sof_intel_hda_dev {
/* the maximum number of streams (playback + capture) supported */
u32 stream_max;
+ /*
+ * ACE2+ link DMA stream allocation constraints (stream index =
+ * stream_tag - 1, shared between input and output directions). All
+ * masks are cleared by hda_dsp_ctrl_init_chip() on controller reset
+ * (CRST#).
+ *
+ * - Concurrent (cross-direction) constraint: a SoundWire stream and
+ * a HDA/iDisp/UAOL stream cannot share a physical stream index
+ * across directions, the resulting LLP/timestamp values are wrong.
+ * link_dma_active_sdw_mask and link_dma_active_multi_mask
+ * (indexed by SNDRV_PCM_STREAM_*) track currently allocated
+ * streams per direction in each of the conflicting groups; SSP
+ * and DMIC do not participate. Bits are cleared on stream release.
+ *
+ * - Sequential (playback only) constraint: once a HDA/iDisp link
+ * has used a playback stream index, that index cannot drive a
+ * non-HDA/iDisp link in the same direction until the next CRST#.
+ * link_dma_out_hda_used_mask records this.
+ */
+ u32 link_dma_active_sdw_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_active_multi_mask[SNDRV_PCM_STREAM_LAST + 1];
+ u32 link_dma_out_hda_used_mask;
+
/* PM related */
bool l1_disabled;/* is DMI link L1 disabled? */
@@ -739,7 +762,7 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd);
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool is_iccmax);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
@@ -911,7 +934,8 @@ hda_data_stream_prepare(struct device *dev, unsigned int format, unsigned int si
bool is_iccmax, bool pair);
int hda_data_stream_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- bool persistent_buffer, struct hdac_ext_stream *hext_stream, bool pair);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream,
+ bool is_iccmax, bool pair);
/* common dai driver */
extern struct snd_soc_dai_driver skl_dai[];
@@ -1030,7 +1054,8 @@ struct hda_dai_widget_dma_ops {
struct snd_pcm_substream *substream);
struct hdac_ext_stream *(*assign_hext_stream)(struct snd_sof_dev *sdev,
struct snd_soc_dai *cpu_dai,
- struct snd_pcm_substream *substream);
+ struct snd_pcm_substream *substream,
+ struct hdac_ext_link *hlink);
void (*release_hext_stream)(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream);
void (*setup_hext_stream)(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream,
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index c1018893750c..549bb4ca73e1 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -9,10 +9,14 @@
* Hardware interface for audio DSP on IceLake.
*/
-#include <linux/kernel.h>
-#include <linux/kconfig.h>
-#include <linux/export.h>
+#include <linux/array_size.h>
#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
#include "../ipc4-priv.h"
#include "../ops.h"
#include "hda.h"
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 9503d00e6002..3d67d6777f1b 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -236,6 +236,17 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
}
EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
+static bool mtl_dsp_is_enabled(struct snd_sof_dev *sdev)
+{
+ int val;
+
+ val = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_HFDSSCS);
+ if (val & MTL_HFDSSCS_CPA_MASK)
+ return true;
+
+ return false;
+}
+
/* pre fw run operations */
static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
@@ -249,6 +260,18 @@ static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
u32 dsppwrsts;
const struct sof_intel_dsp_desc *chip;
+ /* Power down the DSP if it is left enabled to ensure clean boot state */
+ if (mtl_dsp_is_enabled(sdev)) {
+ dev_dbg(sdev->dev, "powering down DSP first\n");
+
+ ret = mtl_power_down_dsp(sdev);
+ if (ret < 0) {
+ dev_warn(sdev->dev,
+ "%s: failed to power down already-enabled DSP\n", __func__);
+ /* Continue anyway to attempt recovery */
+ }
+ }
+
chip = get_chip_info(sdev->pdata);
if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {
dsppwrctl = PTL_HFPWRCTL2;