aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sof/intel/hda.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2022-10-03 16:30:42 +0200
committerTakashi Iwai <tiwai@suse.de>2022-10-03 16:30:42 +0200
commit86a4d29e75540e20f991e72f17aa51d0e775a397 (patch)
tree87d99ee3855d97da60074fdc9c0cdd63dd2da66b /sound/soc/sof/intel/hda.c
parentMerge branch 'for-next' into for-linus (diff)
parentASoC: rockchip: i2s: use regmap_read_poll_timeout_atomic to poll I2S_CLR (diff)
downloadlinux-dev-86a4d29e75540e20f991e72f17aa51d0e775a397.tar.xz
linux-dev-86a4d29e75540e20f991e72f17aa51d0e775a397.zip
Merge tag 'asoc-v6.1' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.1 This has been a very quiet release for the core but quite a busy one for drivers with a big crop of new drivers and lots of feature additions and fixes to existing ones: - A new string helper parse_int_array_user(). - Improvements to the SOF IPC4 code, especially around trace. - Support for AMD Rembrant DSPs, AMD Pink Sardine ACP 6.2, Apple Silcon systems, Everest ES8326, Intel Sky Lake and Kaby Lake, MediaTek MT8186 support, NXP i.MX8ULP DSPs, Qualcomm SC8280XP, SM8250 and SM8450 and Texas Instruments SRC4392 There is a conflict with the conversion of I2C remove functions to void in the cs42l42 driver which is fairly straightforward to resolve but should be highlighted to Linus.
Diffstat (limited to 'sound/soc/sof/intel/hda.c')
-rw-r--r--sound/soc/sof/intel/hda.c95
1 files changed, 87 insertions, 8 deletions
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 6d4ecbe14adf..1188ec51816b 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -31,6 +31,9 @@
#include "../ops.h"
#include "hda.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/sof_intel.h>
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
#include <sound/soc-acpi-intel-match.h>
#endif
@@ -376,6 +379,10 @@ static int dmic_num_override = -1;
module_param_named(dmic_num, dmic_num_override, int, 0444);
MODULE_PARM_DESC(dmic_num, "SOF HDA DMIC number");
+static int mclk_id_override = -1;
+module_param_named(mclk_id, mclk_id_override, int, 0444);
+MODULE_PARM_DESC(mclk_id, "SOF SSP mclk_id");
+
#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);
@@ -591,7 +598,8 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
/* print ROM/FW status */
hda_dsp_get_state(sdev, level);
- if (flags & SOF_DBG_DUMP_REGS) {
+ /* The firmware register dump only available with IPC3 */
+ if (flags & SOF_DBG_DUMP_REGS && sdev->pdata->ipc_type == SOF_IPC) {
u32 status = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_STATUS);
u32 panic = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_SRAM_REG_FW_TRACEP);
@@ -655,6 +663,24 @@ void hda_ipc_dump(struct snd_sof_dev *sdev)
hipcie, hipct, hipcctl);
}
+void hda_ipc4_dump(struct snd_sof_dev *sdev)
+{
+ u32 hipci, hipcie, hipct, hipcte, hipcctl;
+
+ hda_ipc_irq_dump(sdev);
+
+ hipci = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCI);
+ hipcie = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCIE);
+ hipct = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCT);
+ hipcte = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCTE);
+ hipcctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, HDA_DSP_REG_HIPCCTL);
+
+ /* dump the IPC regs */
+ /* TODO: parse the raw msg */
+ dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n",
+ hipci, hipcie, hipct, hipcte, hipcctl);
+}
+
static int hda_init(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus;
@@ -749,6 +775,18 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
return ssp_mask;
}
+static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
+{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+ struct nhlt_acpi_table *nhlt;
+
+ nhlt = hdev->nhlt;
+ if (!nhlt)
+ return 0;
+
+ return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
+}
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
@@ -938,17 +976,25 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
/* deal with streams and controller first */
- if (hda_dsp_check_stream_irq(sdev))
+ if (hda_dsp_check_stream_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "stream");
hda_dsp_stream_threaded_handler(irq, sdev);
+ }
- if (hda_check_ipc_irq(sdev))
+ if (hda_check_ipc_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "ipc");
sof_ops(sdev)->irq_thread(irq, sdev);
+ }
- if (hda_dsp_check_sdw_irq(sdev))
+ if (hda_dsp_check_sdw_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "sdw");
hda_dsp_sdw_thread(irq, hdev->sdw);
+ }
- if (hda_sdw_check_wakeen_irq(sdev))
+ if (hda_sdw_check_wakeen_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "wakeen");
hda_sdw_process_wakeen(sdev);
+ }
hda_check_for_state_change(sdev);
@@ -1109,6 +1155,8 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
INIT_DELAYED_WORK(&hdev->d0i3_work, hda_dsp_d0i3_work);
+ init_waitqueue_head(&hdev->waitq);
+
hdev->nhlt = intel_nhlt_init(sdev->dev);
return 0;
@@ -1162,9 +1210,9 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, SOF_HDA_INTCTL,
SOF_HDA_INT_CTRL_EN | SOF_HDA_INT_GLOBAL_EN, 0);
- /* disable cores */
- if (chip)
- hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+ /* no need to check for error as the DSP will be disabled anyway */
+ if (chip && chip->power_down_dsp)
+ chip->power_down_dsp(sdev);
/* disable DSP */
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
@@ -1190,6 +1238,14 @@ int hda_dsp_remove(struct snd_sof_dev *sdev)
return 0;
}
+int hda_power_down_dsp(struct snd_sof_dev *sdev)
+{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ const struct sof_intel_dsp_desc *chip = hda->desc;
+
+ return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
+}
+
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
static void hda_generic_machine_select(struct snd_sof_dev *sdev,
struct snd_soc_acpi_mach **mach)
@@ -1529,6 +1585,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
mach->mach_params.i2s_link_mask) {
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);
int ssp_num;
+ int mclk_mask;
if (hweight_long(mach->mach_params.i2s_link_mask) > 1 &&
!(mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_MSB))
@@ -1553,6 +1610,21 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
sof_pdata->tplg_filename = tplg_filename;
add_extension = true;
+
+ mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num);
+
+ if (mclk_mask < 0) {
+ dev_err(sdev->dev, "Invalid MCLK configuration\n");
+ return NULL;
+ }
+
+ dev_dbg(sdev->dev, "MCLK mask %#x found in NHLT\n", mclk_mask);
+
+ if (mclk_mask) {
+ dev_info(sdev->dev, "Overriding topology with MCLK mask %#x from NHLT\n", mclk_mask);
+ sdev->mclk_id_override = true;
+ sdev->mclk_id_quirk = (mclk_mask & BIT(0)) ? 0 : 1;
+ }
}
if (tplg_fixup && add_extension) {
@@ -1565,6 +1637,13 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
sof_pdata->tplg_filename = tplg_filename;
}
+
+ /* check if mclk_id should be modified from topology defaults */
+ if (mclk_id_override >= 0) {
+ dev_info(sdev->dev, "Overriding topology with MCLK %d from kernel_parameter\n", mclk_id_override);
+ sdev->mclk_id_override = true;
+ sdev->mclk_id_quirk = mclk_id_override;
+ }
}
/*