summaryrefslogtreecommitdiff
path: root/sound/soc/sof/intel
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sof/intel')
-rw-r--r--sound/soc/sof/intel/hda-common-ops.c1
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c51
-rw-r--r--sound/soc/sof/intel/hda-dai.c48
-rw-r--r--sound/soc/sof/intel/hda-dsp.c5
-rw-r--r--sound/soc/sof/intel/hda-stream.c9
-rw-r--r--sound/soc/sof/intel/hda.c80
-rw-r--r--sound/soc/sof/intel/hda.h5
-rw-r--r--sound/soc/sof/intel/lnl.c57
-rw-r--r--sound/soc/sof/intel/lnl.h15
-rw-r--r--sound/soc/sof/intel/mtl.c42
-rw-r--r--sound/soc/sof/intel/mtl.h4
11 files changed, 263 insertions, 54 deletions
diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c
index 88c236b9a045..d71bb66b9991 100644
--- a/sound/soc/sof/intel/hda-common-ops.c
+++ b/sound/soc/sof/intel/hda-common-ops.c
@@ -86,6 +86,7 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
/* DAI drivers */
.drv = skl_dai,
.num_drv = SOF_SKL_NUM_DAIS,
+ .is_chain_dma_supported = hda_is_chain_dma_supported,
/* PM */
.suspend = hda_dsp_suspend,
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index 92ec5db4677d..b073720b4cf4 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -533,6 +533,17 @@ static const struct hda_dai_widget_dma_ops hda_ipc4_chain_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
+ .get_hext_stream = hda_get_hext_stream,
+ .assign_hext_stream = hda_assign_hext_stream,
+ .release_hext_stream = hda_release_hext_stream,
+ .setup_hext_stream = hda_setup_hext_stream,
+ .reset_hext_stream = hda_reset_hext_stream,
+ .trigger = hda_trigger,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
@@ -607,6 +618,13 @@ static const struct hda_dai_widget_dma_ops hda_dspless_dma_ops = {
.get_hlink = hda_get_hlink,
};
+static const struct hda_dai_widget_dma_ops sdw_dspless_dma_ops = {
+ .get_hext_stream = hda_dspless_get_hext_stream,
+ .setup_hext_stream = hda_dspless_setup_hext_stream,
+ .calc_stream_format = generic_calc_stream_format,
+ .get_hlink = sdw_get_hlink,
+};
+
#endif
const struct hda_dai_widget_dma_ops *
@@ -614,12 +632,24 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
{
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
struct snd_sof_dai *sdai;
+ const struct sof_intel_dsp_desc *chip;
- if (sdev->dspless_mode_selected)
- return &hda_dspless_dma_ops;
-
+ chip = get_chip_info(sdev->pdata);
sdai = swidget->private;
+ if (sdev->dspless_mode_selected) {
+ switch (sdai->type) {
+ case SOF_DAI_INTEL_HDA:
+ return &hda_dspless_dma_ops;
+ case SOF_DAI_INTEL_ALH:
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
+ return &sdw_dspless_dma_ops;
+ default:
+ return NULL;
+ }
+ }
+
switch (sdev->pdata->ipc_type) {
case SOF_IPC_TYPE_3:
{
@@ -631,22 +661,15 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
}
case SOF_IPC_TYPE_4:
{
- struct sof_ipc4_copier *ipc4_copier = sdai->private;
- const struct sof_intel_dsp_desc *chip;
-
- chip = get_chip_info(sdev->pdata);
+ struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
+ struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
- switch (ipc4_copier->dai_type) {
+ switch (sdai->type) {
case SOF_DAI_INTEL_HDA:
- {
- struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
- struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
-
if (pipeline->use_chain_dma)
return &hda_ipc4_chain_dma_ops;
return &hda_ipc4_dma_ops;
- }
case SOF_DAI_INTEL_SSP:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
@@ -658,6 +681,8 @@ hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidg
case SOF_DAI_INTEL_ALH:
if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
return NULL;
+ if (pipeline->use_chain_dma)
+ return &sdw_ipc4_chain_dma_ops;
return &sdw_ipc4_dma_ops;
default:
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index f4cbc0ad5de3..6a39ca632f55 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -83,12 +83,13 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
sdev = widget_to_sdev(w);
- /*
- * The swidget parameter of hda_select_dai_widget_ops() is ignored in
- * case of DSPless mode
- */
+ if (!swidget) {
+ dev_err(sdev->dev, "%s: swidget is NULL\n", __func__);
+ return NULL;
+ }
+
if (sdev->dspless_mode_selected)
- return hda_select_dai_widget_ops(sdev, NULL);
+ return hda_select_dai_widget_ops(sdev, swidget);
sdai = swidget->private;
@@ -368,8 +369,11 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- /* get stream_id */
sdev = widget_to_sdev(w);
+ if (sdev->dspless_mode_selected)
+ goto skip_tlv;
+
+ /* get stream_id */
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
if (!hext_stream) {
@@ -402,6 +406,7 @@ static int non_hda_dai_hw_params(struct snd_pcm_substream *substream,
dma_config->dma_stream_channel_map.device_count = 0; /* mapping not used */
dma_config->dma_priv_config_size = 0;
+skip_tlv:
return 0;
}
@@ -434,10 +439,17 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int link_id)
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
const struct hda_dai_widget_dma_ops *ops;
+ struct snd_soc_dai_link_ch_map *ch_maps;
struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dai *dai;
struct snd_sof_dev *sdev;
+ bool cpu_dai_found = false;
+ int cpu_dai_id;
+ int ch_mask;
int ret;
+ int j;
ret = non_hda_dai_hw_params(substream, params, cpu_dai);
if (ret < 0) {
@@ -452,9 +464,29 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
if (!hext_stream)
return -ENODEV;
- /* in the case of SoundWire we need to program the PCMSyCM registers */
+ /*
+ * in the case of SoundWire we need to program the PCMSyCM registers. In case
+ * of aggregated devices, we need to define the channel mask for each sublink
+ * by reconstructing the split done in soc-pcm.c
+ */
+ for_each_rtd_cpu_dais(rtd, cpu_dai_id, dai) {
+ if (dai == cpu_dai) {
+ cpu_dai_found = true;
+ break;
+ }
+ }
+
+ if (!cpu_dai_found)
+ return -ENODEV;
+
+ ch_mask = 0;
+ for_each_link_ch_maps(rtd->dai_link, j, ch_maps) {
+ if (ch_maps->cpu == cpu_dai_id)
+ ch_mask |= ch_maps->ch_mask;
+ }
+
ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
- GENMASK(params_channels(params) - 1, 0),
+ ch_mask,
hdac_stream(hext_stream)->stream_tag,
substream->stream);
if (ret < 0) {
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 1506982a56c3..ef5c915db8ff 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -758,6 +758,7 @@ skip_dsp:
static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
{
+ const struct sof_intel_dsp_desc *chip;
int ret;
/* display codec must be powered before link reset */
@@ -790,6 +791,10 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
hda_dsp_ctrl_ppcap_int_enable(sdev, true);
}
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
+ hda_sdw_int_enable(sdev, true);
+
cleanup:
/* display codec can powered off after controller init */
hda_codec_i915_display_power(sdev, false);
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index c603aaf0ca77..0c189d3b19c1 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -21,6 +21,7 @@
#include <trace/events/sof_intel.h>
#include "../ops.h"
#include "../sof-audio.h"
+#include "../ipc4-priv.h"
#include "hda.h"
#define HDA_LTRP_GB_VALUE_US 95
@@ -937,6 +938,14 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
/* store total stream count (playback + capture) from GCAP */
sof_hda->stream_max = num_total;
+ /* store stream count from GCAP required for CHAIN_DMA */
+ if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+
+ ipc4_data->num_playback_streams = num_playback;
+ ipc4_data->num_capture_streams = num_capture;
+ }
+
return 0;
}
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index fe4ae349dad5..7fe72b065451 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -46,44 +46,83 @@
#define EXCEPT_MAX_HDR_SIZE 0x400
#define HDA_EXT_ROM_STATUS_SIZE 8
-static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
+static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask)
{
const struct sof_intel_dsp_desc *chip;
- u32 interface_mask[2] = { 0 };
chip = get_chip_info(sdev->pdata);
switch (chip->hw_ip_version) {
case SOF_INTEL_TANGIER:
case SOF_INTEL_BAYTRAIL:
case SOF_INTEL_BROADWELL:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP);
+ interface_mask[SOF_DAI_DSP_ACCESS] = BIT(SOF_DAI_INTEL_SSP);
break;
case SOF_INTEL_CAVS_1_5:
case SOF_INTEL_CAVS_1_5_PLUS:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
- BIT(SOF_DAI_INTEL_HDA);
- interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) | BIT(SOF_DAI_INTEL_HDA);
+ interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_CAVS_1_8:
case SOF_INTEL_CAVS_2_0:
case SOF_INTEL_CAVS_2_5:
case SOF_INTEL_ACE_1_0:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
- BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
- interface_mask[1] = BIT(SOF_DAI_INTEL_HDA);
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+ BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+ interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_ACE_2_0:
- interface_mask[0] = BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
- BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
- interface_mask[1] = interface_mask[0]; /* all interfaces accessible without DSP */
+ interface_mask[SOF_DAI_DSP_ACCESS] =
+ BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC) |
+ BIT(SOF_DAI_INTEL_HDA) | BIT(SOF_DAI_INTEL_ALH);
+ /* all interfaces accessible without DSP */
+ interface_mask[SOF_DAI_HOST_ACCESS] =
+ interface_mask[SOF_DAI_DSP_ACCESS];
break;
default:
break;
}
+}
+
+static u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
+{
+ u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
+
+ hda_get_interfaces(sdev, interface_mask);
return interface_mask[sdev->dspless_mode_selected];
}
+bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
+{
+ u32 interface_mask[SOF_DAI_ACCESS_NUM] = { 0 };
+ const struct sof_intel_dsp_desc *chip;
+
+ if (sdev->dspless_mode_selected)
+ return false;
+
+ hda_get_interfaces(sdev, interface_mask);
+
+ if (!(interface_mask[SOF_DAI_DSP_ACCESS] & BIT(dai_type)))
+ return false;
+
+ if (dai_type == SOF_DAI_INTEL_HDA)
+ return true;
+
+ switch (dai_type) {
+ case SOF_DAI_INTEL_SSP:
+ case SOF_DAI_INTEL_DMIC:
+ case SOF_DAI_INTEL_ALH:
+ chip = get_chip_info(sdev->pdata);
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return false;
+ return true;
+ default:
+ return false;
+ }
+}
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
/*
@@ -1192,6 +1231,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
{
struct pci_dev *pci = to_pci_dev(sdev->dev);
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip;
int ret = 0;
hdev->dmic_dev = platform_device_register_data(sdev->dev, "dmic-codec",
@@ -1305,12 +1345,28 @@ skip_dsp_setup:
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
}
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0) {
+ ret = hda_sdw_startup(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "could not startup SoundWire links\n");
+ goto disable_pp_cap;
+ }
+
+ hda_sdw_int_enable(sdev, true);
+ }
+
init_waitqueue_head(&hdev->waitq);
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0;
+disable_pp_cap:
+ if (!sdev->dspless_mode_selected) {
+ hda_dsp_ctrl_ppcap_int_enable(sdev, false);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
+ }
free_ipc_irq:
free_irq(sdev->ipc_irq, sdev);
free_irq_vector:
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index efb42117df79..81a1d4606d3c 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -574,6 +574,11 @@ struct sof_intel_hda_stream {
#define SOF_STREAM_SD_OFFSET_CRST 0x1
/*
+ * DAI support
+ */
+bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type);
+
+/*
* DSP Core services.
*/
int hda_dsp_probe_early(struct snd_sof_dev *sdev);
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
index 555a51c688dc..6055a33bb4bf 100644
--- a/sound/soc/sof/intel/lnl.c
+++ b/sound/soc/sof/intel/lnl.c
@@ -16,6 +16,7 @@
#include "hda-ipc.h"
#include "../sof-audio.h"
#include "mtl.h"
+#include "lnl.h"
#include <sound/hda-mlink.h>
/* LunarLake ops */
@@ -29,15 +30,17 @@ static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
};
/* this helps allows the DSP to setup DMIC/SSP */
-static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus)
+static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable)
{
int ret;
- ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_SSP, true);
+ ret = hdac_bus_eml_enable_offload(bus, true,
+ AZX_REG_ML_LEPTR_ID_INTEL_SSP, enable);
if (ret < 0)
return ret;
- ret = hdac_bus_eml_enable_offload(bus, true, AZX_REG_ML_LEPTR_ID_INTEL_DMIC, true);
+ ret = hdac_bus_eml_enable_offload(bus, true,
+ AZX_REG_ML_LEPTR_ID_INTEL_DMIC, enable);
if (ret < 0)
return ret;
@@ -52,7 +55,19 @@ static int lnl_hda_dsp_probe(struct snd_sof_dev *sdev)
if (ret < 0)
return ret;
- return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
+}
+
+static void lnl_hda_dsp_remove(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ ret = hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), false);
+ if (ret < 0)
+ dev_warn(sdev->dev,
+ "Failed to disable offload for DMIC/SSP: %d\n", ret);
+
+ hda_dsp_remove(sdev);
}
static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
@@ -63,7 +78,7 @@ static int lnl_hda_dsp_resume(struct snd_sof_dev *sdev)
if (ret < 0)
return ret;
- return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
}
static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
@@ -74,7 +89,20 @@ static int lnl_hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
if (ret < 0)
return ret;
- return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev));
+ return hdac_bus_offload_dmic_ssp(sof_to_bus(sdev), true);
+}
+
+static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+{
+ if (sdev->first_boot) {
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+
+ /* Check if IMR boot is usable */
+ if (!sof_debug_check_flag(SOF_DBG_IGNORE_D3_PERSISTENT))
+ hda->imrboot_supported = true;
+ }
+
+ return 0;
}
int sof_lnl_ops_init(struct snd_sof_dev *sdev)
@@ -84,8 +112,11 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
/* common defaults */
memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
- /* probe */
- sof_lnl_ops.probe = lnl_hda_dsp_probe;
+ /* probe/remove */
+ if (!sdev->dspless_mode_selected) {
+ sof_lnl_ops.probe = lnl_hda_dsp_probe;
+ sof_lnl_ops.remove = lnl_hda_dsp_remove;
+ }
/* shutdown */
sof_lnl_ops.shutdown = hda_dsp_shutdown;
@@ -106,7 +137,7 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
/* pre/post fw run */
sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
- sof_lnl_ops.post_fw_run = mtl_dsp_post_fw_run;
+ sof_lnl_ops.post_fw_run = lnl_dsp_post_fw_run;
/* parse platform specific extended manifest */
sof_lnl_ops.parse_platform_ext_manifest = NULL;
@@ -115,8 +146,10 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
/* TODO: add core_get and core_put */
/* PM */
- sof_lnl_ops.resume = lnl_hda_dsp_resume;
- sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
+ if (!sdev->dspless_mode_selected) {
+ sof_lnl_ops.resume = lnl_hda_dsp_resume;
+ sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
+ }
/* dsp core get/put */
sof_lnl_ops.core_get = mtl_dsp_core_get;
@@ -176,7 +209,7 @@ const struct sof_intel_dsp_desc lnl_chip_info = {
.ipc_ack = MTL_DSP_REG_HFIPCXIDA,
.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
- .rom_status_reg = MTL_DSP_ROM_STS,
+ .rom_status_reg = LNL_DSP_REG_HFDSC,
.rom_init_timeout = 300,
.ssp_count = MTL_SSP_COUNT,
.d0i3_offset = MTL_HDA_VS_D0I3C,
diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h
new file mode 100644
index 000000000000..4f4734fe7e08
--- /dev/null
+++ b/sound/soc/sof/intel/lnl.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
+/*
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * Copyright(c) 2024 Intel Corporation. All rights reserved.
+ */
+
+#ifndef __SOF_INTEL_LNL_H
+#define __SOF_INTEL_LNL_H
+
+#define LNL_DSP_REG_HFDSC 0x160200 /* DSP core0 status */
+#define LNL_DSP_REG_HFDEC 0x160204 /* DSP core0 error */
+
+#endif /* __SOF_INTEL_LNL_H */
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 060c34988e90..05023763080d 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -439,7 +439,7 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
- unsigned int status;
+ unsigned int status, target_status;
u32 ipc_hdr, flags;
char *dump_msg;
int ret;
@@ -485,13 +485,40 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
mtl_enable_ipc_interrupts(sdev);
+ if (chip->rom_status_reg == MTL_DSP_ROM_STS) {
+ /*
+ * Workaround: when the ROM status register is pointing to
+ * the SRAM window (MTL_DSP_ROM_STS) the platform cannot catch
+ * ROM_INIT_DONE because of a very short timing window.
+ * Follow the recommendations and skip target state waiting.
+ */
+ return 0;
+ }
+
/*
- * ACE workaround: don't wait for ROM INIT.
- * The platform cannot catch ROM_INIT_DONE because of a very short
- * timing window. Follow the recommendations and skip this part.
+ * step 7:
+ * - Cold/Full boot: wait for ROM init to proceed to download the firmware
+ * - IMR boot: wait for ROM firmware entered (firmware booted up from IMR)
*/
+ if (imr_boot)
+ target_status = FSR_STATE_FW_ENTERED;
+ else
+ target_status = FSR_STATE_INIT_DONE;
- return 0;
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
+ chip->rom_status_reg, status,
+ (FSR_TO_STATE_CODE(status) == target_status),
+ HDA_DSP_REG_POLL_INTERVAL_US,
+ chip->rom_init_timeout *
+ USEC_PER_MSEC);
+
+ if (!ret)
+ return 0;
+
+ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+ dev_err(sdev->dev,
+ "%s: timeout with rom_status_reg (%#x) read\n",
+ __func__, chip->rom_status_reg);
err:
flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
@@ -503,6 +530,7 @@ err:
dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
+ mtl_enable_interrupts(sdev, false);
mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
kfree(dump_msg);
@@ -727,7 +755,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.ipc_ack = MTL_DSP_REG_HFIPCXIDA,
.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
- .rom_status_reg = MTL_DSP_ROM_STS,
+ .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,
.rom_init_timeout = 300,
.ssp_count = MTL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
@@ -755,7 +783,7 @@ const struct sof_intel_dsp_desc arl_s_chip_info = {
.ipc_ack = MTL_DSP_REG_HFIPCXIDA,
.ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
.ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
- .rom_status_reg = MTL_DSP_ROM_STS,
+ .rom_status_reg = MTL_DSP_REG_HFFLGPXQWY,
.rom_init_timeout = 300,
.ssp_count = MTL_SSP_COUNT,
.ssp_base_offset = CNL_SSP_BASE_OFFSET,
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index ea8c1b83f712..3c56427a966b 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -70,8 +70,8 @@
#define MTL_DSP_ROM_STS MTL_SRAM_WINDOW_OFFSET(0) /* ROM status */
#define MTL_DSP_ROM_ERROR (MTL_SRAM_WINDOW_OFFSET(0) + 0x4) /* ROM error code */
-#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* ROM debug status */
-#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* ROM debug error code */
+#define MTL_DSP_REG_HFFLGPXQWY 0x163200 /* DSP core0 status */
+#define MTL_DSP_REG_HFFLGPXQWY_ERROR 0x163204 /* DSP core0 error */
#define MTL_DSP_REG_HfIMRIS1 0x162088
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)