summaryrefslogtreecommitdiffstats
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-compress.c4
-rw-r--r--sound/soc/sof/intel/hda-dsp.c24
-rw-r--r--sound/soc/sof/intel/hda-loader.c17
-rw-r--r--sound/soc/sof/intel/hda-pcm.c18
-rw-r--r--sound/soc/sof/intel/hda-stream.c38
-rw-r--r--sound/soc/sof/intel/hda-trace.c8
-rw-r--r--sound/soc/sof/intel/hda.c277
-rw-r--r--sound/soc/sof/intel/hda.h7
-rw-r--r--sound/soc/sof/intel/tgl.c3
9 files changed, 221 insertions, 175 deletions
diff --git a/sound/soc/sof/intel/hda-compress.c b/sound/soc/sof/intel/hda-compress.c
index 53c08034fa22..fe2f3f7d236b 100644
--- a/sound/soc/sof/intel/hda-compress.c
+++ b/sound/soc/sof/intel/hda-compress.c
@@ -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;
@@ -82,7 +82,7 @@ int hda_probe_compr_set_params(struct snd_sof_dev *sdev,
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
if (ret < 0) {
- dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+ dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
return ret;
}
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 1c5e05b88a90..5788fe356960 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -624,7 +624,7 @@ static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend)
#endif
/* power down DSP */
- ret = hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+ ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to power down core during suspend\n");
@@ -732,7 +732,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
ret = snd_hdac_ext_bus_link_power_up(hlink);
if (ret < 0) {
dev_dbg(sdev->dev,
- "error %x in %s: failed to power up links",
+ "error %d in %s: failed to power up links",
ret, __func__);
return ret;
}
@@ -802,11 +802,15 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_dsp_power_state target_state = {
.state = SOF_DSP_PM_D3,
};
int ret;
+ /* cancel any attempt for DSP D0I3 */
+ cancel_delayed_work_sync(&hda->d0i3_work);
+
/* stop hda controller and power dsp off */
ret = hda_suspend(sdev, true);
if (ret < 0)
@@ -930,19 +934,15 @@ void hda_dsp_d0i3_work(struct work_struct *work)
d0i3_work.work);
struct hdac_bus *bus = &hdev->hbus.core;
struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
- struct sof_dsp_power_state target_state;
+ struct sof_dsp_power_state target_state = {
+ .state = SOF_DSP_PM_D0,
+ .substate = SOF_HDA_DSP_PM_D0I3,
+ };
int ret;
- target_state.state = SOF_DSP_PM_D0;
-
/* DSP can enter D0I3 iff only D0I3-compatible streams are active */
- if (snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
- target_state.substate = SOF_HDA_DSP_PM_D0I3;
- else
- target_state.substate = SOF_HDA_DSP_PM_D0I0;
-
- /* remain in D0I0 */
- if (target_state.substate == SOF_HDA_DSP_PM_D0I0)
+ if (!snd_sof_dsp_only_d0i3_compatible_stream_active(sdev))
+ /* remain in D0I0 */
return;
/* This can fail but error cannot be propagated */
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index ed773696b495..fc25ee8f68dc 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -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");
@@ -47,7 +47,7 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
/* allocate DMA buffer */
ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, &pci->dev, size, dmab);
if (ret < 0) {
- dev_err(sdev->dev, "error: memory alloc failed: %x\n", ret);
+ dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
goto error;
}
@@ -58,13 +58,13 @@ static struct hdac_ext_stream *cl_stream_prepare(struct snd_sof_dev *sdev, unsig
if (direction == SNDRV_PCM_STREAM_CAPTURE) {
ret = hda_dsp_iccmax_stream_hw_params(sdev, dsp_stream, dmab, NULL);
if (ret < 0) {
- dev_err(sdev->dev, "error: iccmax stream prepare failed: %x\n", ret);
+ dev_err(sdev->dev, "error: iccmax stream prepare failed: %d\n", ret);
goto error;
}
} else {
ret = hda_dsp_stream_hw_params(sdev, dsp_stream, dmab, NULL);
if (ret < 0) {
- dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+ dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
goto error;
}
hda_dsp_stream_spib_config(sdev, dsp_stream, HDA_DSP_SPIB_ENABLE, size);
@@ -93,7 +93,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
int i;
/* step 1: power up corex */
- ret = hda_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
+ ret = snd_sof_dsp_core_power_up(sdev, chip->host_managed_cores_mask);
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev, "error: dsp core 0/1 power up failed\n");
@@ -147,8 +147,9 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag)
chip->ipc_ack_mask,
chip->ipc_ack_mask);
- /* step 5: power down corex */
- ret = hda_dsp_core_power_down(sdev, chip->host_managed_cores_mask & ~(BIT(0)));
+ /* step 5: power down cores that are no longer needed */
+ ret = snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask &
+ ~(chip->init_core_mask));
if (ret < 0) {
if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
dev_err(sdev->dev,
@@ -183,7 +184,7 @@ err:
flags |= SOF_DBG_DUMP_FORCE_ERR_LEVEL;
hda_dsp_dump(sdev, flags);
- hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+ snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
return ret;
}
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index 5d35bb18660a..df00db8369c7 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -111,7 +111,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, params);
if (ret < 0) {
- dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+ dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
return ret;
}
@@ -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;
+
+ 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;
+ }
- dsp_stream = hda_dsp_stream_get(sdev, direction);
+ /* 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;
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 0e09ede922c7..40a3993ae2cb 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -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);
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
index 1eb746d5adeb..29e3da3c63db 100644
--- a/sound/soc/sof/intel/hda-trace.c
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -32,7 +32,7 @@ static int hda_dsp_trace_prepare(struct snd_sof_dev *sdev)
ret = hda_dsp_stream_hw_params(sdev, stream, dmab, NULL);
if (ret < 0)
- dev_err(sdev->dev, "error: hdac prepare failed: %x\n", ret);
+ dev_err(sdev->dev, "error: hdac prepare failed: %d\n", ret);
return ret;
}
@@ -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,
@@ -59,7 +59,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, u32 *stream_tag)
*/
ret = hda_dsp_trace_prepare(sdev);
if (ret < 0) {
- dev_err(sdev->dev, "error: hdac trace init failed: %x\n", ret);
+ dev_err(sdev->dev, "error: hdac trace init failed: %d\n", ret);
hda_dsp_stream_put(sdev, SNDRV_PCM_STREAM_CAPTURE, *stream_tag);
hda->dtrace_stream = NULL;
*stream_tag = 0;
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 509a9b256423..0dc3a8c0f5e3 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -285,11 +285,13 @@ static char *hda_model;
module_param(hda_model, charp, 0444);
MODULE_PARM_DESC(hda_model, "Use the given HDA board model.");
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static int hda_dmic_num = -1;
module_param_named(dmic_num, hda_dmic_num, int, 0444);
MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
+#endif
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static bool hda_codec_use_common_hdmi = IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI);
module_param_named(use_common_hdmi, hda_codec_use_common_hdmi, bool, 0444);
MODULE_PARM_DESC(use_common_hdmi, "SOF HDA use common HDMI codec driver");
@@ -317,26 +319,6 @@ static const struct hda_dsp_msg_code hda_dsp_rom_msg[] = {
{HDA_DSP_ROM_NULL_FW_ENTRY, "error: null FW entry point"},
};
-static void hda_dsp_get_status_skl(struct snd_sof_dev *sdev)
-{
- u32 status;
- int i;
-
- status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
- HDA_ADSP_FW_STATUS_SKL);
-
- for (i = 0; i < ARRAY_SIZE(hda_dsp_rom_msg); i++) {
- if (status == hda_dsp_rom_msg[i].code) {
- dev_err(sdev->dev, "%s - code %8.8x\n",
- hda_dsp_rom_msg[i].msg, status);
- return;
- }
- }
-
- /* not for us, must be generic sof message */
- dev_dbg(sdev->dev, "unknown ROM status value %8.8x\n", status);
-}
-
static void hda_dsp_get_status(struct snd_sof_dev *sdev)
{
u32 status;
@@ -385,36 +367,6 @@ static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
stack_words * sizeof(u32));
}
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags)
-{
- struct sof_ipc_dsp_oops_xtensa xoops;
- struct sof_ipc_panic_info panic_info;
- u32 stack[HDA_DSP_STACK_DUMP_SIZE];
- u32 status, panic;
-
- /* try APL specific status message types first */
- hda_dsp_get_status_skl(sdev);
-
- /* now try generic SOF status messages */
- status = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
- HDA_ADSP_ERROR_CODE_SKL);
-
- /*TODO: Check: there is no define in spec, but it is used in the code*/
- panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
- HDA_ADSP_ERROR_CODE_SKL + 0x4);
-
- if (sdev->fw_state == SOF_FW_BOOT_COMPLETE) {
- hda_dsp_get_registers(sdev, &xoops, &panic_info, stack,
- HDA_DSP_STACK_DUMP_SIZE);
- snd_sof_get_status(sdev, status, panic, &xoops, &panic_info,
- stack, HDA_DSP_STACK_DUMP_SIZE);
- } else {
- dev_err(sdev->dev, "error: status = 0x%8.8x panic = 0x%8.8x\n",
- status, panic);
- hda_dsp_get_status_skl(sdev);
- }
-}
-
/* dump the first 8 dwords representing the extended ROM status */
static void hda_dsp_dump_ext_rom_status(struct snd_sof_dev *sdev, u32 flags)
{
@@ -555,7 +507,7 @@ static int hda_init(struct snd_sof_dev *sdev)
return ret;
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
+#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static int check_nhlt_dmic(struct snd_sof_dev *sdev)
{
@@ -579,25 +531,76 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *dmic_str)
{
const char *tplg_filename = NULL;
- char *filename;
- char *split_ext;
+ char *filename, *tmp;
+ const char *split_ext;
- filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
+ filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
if (!filename)
return NULL;
/* this assumes a .tplg extension */
- split_ext = strsep(&filename, ".");
- if (split_ext) {
+ tmp = filename;
+ split_ext = strsep(&tmp, ".");
+ if (split_ext)
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%s.tplg",
split_ext, idisp_str, dmic_str);
- if (!tplg_filename)
- return NULL;
- }
+ kfree(filename);
+
return tplg_filename;
}
+static int dmic_topology_fixup(struct snd_sof_dev *sdev,
+ const char **tplg_filename,
+ const char *idisp_str,
+ int *dmic_found)
+{
+ const char *default_tplg_filename = *tplg_filename;
+ const char *fixed_tplg_filename;
+ const char *dmic_str;
+ int dmic_num;
+
+ /* first check NHLT for DMICs */
+ dmic_num = check_nhlt_dmic(sdev);
+
+ /* allow for module parameter override */
+ if (hda_dmic_num != -1) {
+ dev_dbg(sdev->dev,
+ "overriding DMICs detected in NHLT tables %d by kernel param %d\n",
+ dmic_num, hda_dmic_num);
+ dmic_num = hda_dmic_num;
+ }
+
+ switch (dmic_num) {
+ case 1:
+ dmic_str = "-1ch";
+ break;
+ case 2:
+ dmic_str = "-2ch";
+ break;
+ case 3:
+ dmic_str = "-3ch";
+ break;
+ case 4:
+ dmic_str = "-4ch";
+ break;
+ default:
+ dmic_num = 0;
+ dmic_str = "";
+ break;
+ }
+
+ fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
+ idisp_str, dmic_str);
+ if (!fixed_tplg_filename)
+ return -ENOMEM;
+
+ dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
+ *dmic_found = dmic_num;
+ *tplg_filename = fixed_tplg_filename;
+
+ return 0;
+}
#endif
static int hda_init_caps(struct snd_sof_dev *sdev)
@@ -809,13 +812,9 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
sdev->mailbox_bar = HDA_DSP_BAR;
/* allow 64bit DMA address if supported by H/W */
- if (!dma_set_mask(&pci->dev, DMA_BIT_MASK(64))) {
- dev_dbg(sdev->dev, "DMA mask is 64 bit\n");
- dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(64));
- } else {
+ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(64))) {
dev_dbg(sdev->dev, "DMA mask is 32 bit\n");
- dma_set_mask(&pci->dev, DMA_BIT_MASK(32));
- dma_set_coherent_mask(&pci->dev, DMA_BIT_MASK(32));
+ dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32));
}
/* init streams */
@@ -932,7 +931,7 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
/* disable cores */
if (chip)
- hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+ snd_sof_dsp_core_power_down(sdev, chip->host_managed_cores_mask);
/* disable DSP */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
@@ -967,9 +966,9 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
struct snd_sof_pdata *pdata = sdev->pdata;
const char *tplg_filename;
const char *idisp_str;
- const char *dmic_str;
int dmic_num = 0;
int codec_num = 0;
+ int ret;
int i;
/* codec detection */
@@ -994,10 +993,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
if (!pdata->machine && codec_num <= 2) {
hda_mach = snd_soc_acpi_intel_hda_machines;
- /* topology: use the info from hda_machines */
- pdata->tplg_filename =
- hda_mach->sof_tplg_filename;
-
dev_info(bus->dev, "using HDA machine driver %s now\n",
hda_mach->drv_name);
@@ -1006,42 +1001,13 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
else
idisp_str = "";
- /* first check NHLT for DMICs */
- dmic_num = check_nhlt_dmic(sdev);
-
- /* allow for module parameter override */
- if (hda_dmic_num != -1)
- dmic_num = hda_dmic_num;
-
- switch (dmic_num) {
- case 1:
- dmic_str = "-1ch";
- break;
- case 2:
- dmic_str = "-2ch";
- break;
- case 3:
- dmic_str = "-3ch";
- break;
- case 4:
- dmic_str = "-4ch";
- break;
- default:
- dmic_num = 0;
- dmic_str = "";
- break;
- }
-
- tplg_filename = pdata->tplg_filename;
- tplg_filename = fixup_tplg_name(sdev, tplg_filename,
- idisp_str, dmic_str);
- if (!tplg_filename)
- return -EINVAL;
-
- dev_info(bus->dev,
- "DMICs detected in NHLT tables: %d\n",
- dmic_num);
+ /* topology: use the info from hda_machines */
+ tplg_filename = hda_mach->sof_tplg_filename;
+ ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
+ if (ret < 0)
+ return ret;
+ hda_mach->mach_params.dmic_num = dmic_num;
pdata->machine = hda_mach;
pdata->tplg_filename = tplg_filename;
}
@@ -1053,7 +1019,6 @@ static int hda_generic_machine_select(struct snd_sof_dev *sdev)
&pdata->machine->mach_params;
mach_params->codec_mask = bus->codec_mask;
mach_params->common_hdmi_codec_drv = hda_codec_use_common_hdmi;
- mach_params->dmic_num = dmic_num;
}
return 0;
@@ -1075,32 +1040,63 @@ static bool link_slaves_found(struct snd_sof_dev *sdev,
struct sdw_intel_slave_id *ids = sdw->ids;
int num_slaves = sdw->num_slaves;
unsigned int part_id, link_id, unique_id, mfg_id;
- int i, j;
+ int i, j, k;
for (i = 0; i < link->num_adr; i++) {
u64 adr = link->adr_d[i].adr;
+ int reported_part_count = 0;
mfg_id = SDW_MFG_ID(adr);
part_id = SDW_PART_ID(adr);
link_id = SDW_DISCO_LINK_ID(adr);
+
+ for (j = 0; j < num_slaves; j++) {
+ /* find out how many identical parts were reported on that link */
+ if (ids[j].link_id == link_id &&
+ ids[j].id.part_id == part_id &&
+ ids[j].id.mfg_id == mfg_id)
+ reported_part_count++;
+ }
+
for (j = 0; j < num_slaves; j++) {
+ int expected_part_count = 0;
+
if (ids[j].link_id != link_id ||
ids[j].id.part_id != part_id ||
ids[j].id.mfg_id != mfg_id)
continue;
- /*
- * we have to check unique id
- * if there is more than one
- * Slave on the link
- */
- unique_id = SDW_UNIQUE_ID(adr);
- if (link->num_adr == 1 ||
- ids[j].id.unique_id == SDW_IGNORED_UNIQUE_ID ||
- ids[j].id.unique_id == unique_id) {
- dev_dbg(bus->dev,
- "found %x at link %d\n",
- part_id, link_id);
- break;
+
+ /* find out how many identical parts are expected */
+ for (k = 0; k < link->num_adr; k++) {
+ u64 adr2 = link->adr_d[i].adr;
+ unsigned int part_id2, link_id2, mfg_id2;
+
+ mfg_id2 = SDW_MFG_ID(adr2);
+ part_id2 = SDW_PART_ID(adr2);
+ link_id2 = SDW_DISCO_LINK_ID(adr2);
+
+ if (link_id2 == link_id &&
+ part_id2 == part_id &&
+ mfg_id2 == mfg_id)
+ expected_part_count++;
+ }
+
+ if (reported_part_count == expected_part_count) {
+ /*
+ * we have to check unique id
+ * if there is more than one
+ * Slave on the link
+ */
+ unique_id = SDW_UNIQUE_ID(adr);
+ if (reported_part_count == 1 ||
+ ids[j].id.unique_id == unique_id) {
+ dev_dbg(bus->dev, "found %x at link %d\n",
+ part_id, link_id);
+ break;
+ }
+ } else {
+ dev_dbg(bus->dev, "part %x reported %d expected %d on link %d, skipping\n",
+ part_id, reported_part_count, expected_part_count, link_id);
}
}
if (j == num_slaves) {
@@ -1117,7 +1113,6 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct snd_soc_acpi_link_adr *link;
- struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
u32 link_mask;
@@ -1165,16 +1160,42 @@ static int hda_sdw_machine_select(struct snd_sof_dev *sdev)
break;
}
if (mach && mach->link_mask) {
- dev_dbg(bus->dev,
- "SoundWire machine driver %s topology %s\n",
- mach->drv_name,
- mach->sof_tplg_filename);
+ int dmic_num = 0;
+
pdata->machine = mach;
mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev);
- pdata->fw_filename = mach->sof_fw_filename;
+ if (mach->sof_fw_filename)
+ pdata->fw_filename = mach->sof_fw_filename;
+ else
+ pdata->fw_filename = pdata->desc->default_fw_filename;
pdata->tplg_filename = mach->sof_tplg_filename;
+
+ /*
+ * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
+ * link 2 and 3, thus we only try to enable dmics if all conditions
+ * are true:
+ * a) link 2 and 3 are not used by SoundWire
+ * b) the NHLT table reports the presence of microphones
+ */
+ if (!(mach->link_mask & GENMASK(3, 2))) {
+ const char *tplg_filename = mach->sof_tplg_filename;
+ int ret;
+
+ ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
+
+ if (ret < 0)
+ return ret;
+
+ pdata->tplg_filename = tplg_filename;
+ }
+ mach->mach_params.dmic_num = dmic_num;
+
+ dev_dbg(sdev->dev,
+ "SoundWire machine driver %s topology %s\n",
+ mach->drv_name,
+ pdata->tplg_filename);
} else {
dev_info(sdev->dev,
"No SoundWire machine driver found\n");
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 1d9b38e6ed40..d1c38c37bc9d 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -403,6 +403,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.
@@ -472,6 +475,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) \
@@ -514,7 +518,6 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev);
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev);
int hda_dsp_runtime_idle(struct snd_sof_dev *sdev);
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev);
-void hda_dsp_dump_skl(struct snd_sof_dev *sdev, u32 flags);
void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
void hda_ipc_dump(struct snd_sof_dev *sdev);
void hda_ipc_irq_dump(struct snd_sof_dev *sdev);
@@ -563,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,
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index 2252ca38ff4b..419f05ba1920 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -22,9 +22,10 @@ static const struct snd_sof_debugfs_map tgl_dsp_debugfs[] = {
/* Tigerlake ops */
const struct snd_sof_dsp_ops sof_tgl_ops = {
- /* probe and remove */
+ /* probe/remove/shutdown */
.probe = hda_dsp_probe,
.remove = hda_dsp_remove,
+ .shutdown = hda_dsp_remove,
/* Register IO */
.write = sof_io_write,