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/Kconfig44
-rw-r--r--sound/soc/sof/intel/Makefile8
-rw-r--r--sound/soc/sof/intel/apl.c1
-rw-r--r--sound/soc/sof/intel/atom.c38
-rw-r--r--sound/soc/sof/intel/bdw.c28
-rw-r--r--sound/soc/sof/intel/byt.c14
-rw-r--r--sound/soc/sof/intel/cnl.c22
-rw-r--r--sound/soc/sof/intel/hda-bus.c6
-rw-r--r--sound/soc/sof/intel/hda-codec.c36
-rw-r--r--sound/soc/sof/intel/hda-common-ops.c2
-rw-r--r--sound/soc/sof/intel/hda-ctrl.c24
-rw-r--r--sound/soc/sof/intel/hda-dai-ops.c23
-rw-r--r--sound/soc/sof/intel/hda-dai.c92
-rw-r--r--sound/soc/sof/intel/hda-dsp.c79
-rw-r--r--sound/soc/sof/intel/hda-ipc.c36
-rw-r--r--sound/soc/sof/intel/hda-loader.c138
-rw-r--r--sound/soc/sof/intel/hda-mlink.c211
-rw-r--r--sound/soc/sof/intel/hda-pcm.c56
-rw-r--r--sound/soc/sof/intel/hda-probes.c8
-rw-r--r--sound/soc/sof/intel/hda-sdw-bpt.c445
-rw-r--r--sound/soc/sof/intel/hda-stream.c85
-rw-r--r--sound/soc/sof/intel/hda-trace.c6
-rw-r--r--sound/soc/sof/intel/hda.c636
-rw-r--r--sound/soc/sof/intel/hda.h33
-rw-r--r--sound/soc/sof/intel/icl.c1
-rw-r--r--sound/soc/sof/intel/lnl.c103
-rw-r--r--sound/soc/sof/intel/lnl.h6
-rw-r--r--sound/soc/sof/intel/mtl.c109
-rw-r--r--sound/soc/sof/intel/mtl.h17
-rw-r--r--sound/soc/sof/intel/nvl.c55
-rw-r--r--sound/soc/sof/intel/nvl.h14
-rw-r--r--sound/soc/sof/intel/pci-apl.c8
-rw-r--r--sound/soc/sof/intel/pci-cnl.c8
-rw-r--r--sound/soc/sof/intel/pci-icl.c10
-rw-r--r--sound/soc/sof/intel/pci-lnl.c20
-rw-r--r--sound/soc/sof/intel/pci-mtl.c16
-rw-r--r--sound/soc/sof/intel/pci-nvl.c82
-rw-r--r--sound/soc/sof/intel/pci-ptl.c113
-rw-r--r--sound/soc/sof/intel/pci-skl.c8
-rw-r--r--sound/soc/sof/intel/pci-tgl.c14
-rw-r--r--sound/soc/sof/intel/pci-tng.c9
-rw-r--r--sound/soc/sof/intel/ptl.c158
-rw-r--r--sound/soc/sof/intel/ptl.h19
-rw-r--r--sound/soc/sof/intel/shim.h5
-rw-r--r--sound/soc/sof/intel/skl.c7
-rw-r--r--sound/soc/sof/intel/telemetry.c2
-rw-r--r--sound/soc/sof/intel/tgl.c4
47 files changed, 2158 insertions, 701 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig
index 3396bd46b778..54cd3807f8c6 100644
--- a/sound/soc/sof/intel/Kconfig
+++ b/sound/soc/sof/intel/Kconfig
@@ -266,8 +266,10 @@ config SND_SOC_SOF_METEORLAKE
config SND_SOC_SOF_INTEL_LNL
tristate
+ select SOUNDWIRE_INTEL if SND_SOC_SOF_INTEL_SOUNDWIRE != n
select SND_SOC_SOF_HDA_GENERIC
select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOF_SOF_HDA_SDW_BPT if SND_SOC_SOF_INTEL_SOUNDWIRE != n
select SND_SOC_SOF_IPC4
select SND_SOC_SOF_INTEL_MTL
@@ -281,6 +283,40 @@ config SND_SOC_SOF_LUNARLAKE
Say Y if you have such a device.
If unsure select "N".
+config SND_SOC_SOF_INTEL_PTL
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_LNL
+
+config SND_SOC_SOF_PANTHERLAKE
+ tristate "SOF support for Pantherlake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_PTL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Pantherlake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
+config SND_SOC_SOF_INTEL_NVL
+ tristate
+ select SND_SOC_SOF_HDA_COMMON
+ select SND_SOC_SOF_INTEL_SOUNDWIRE_LINK_BASELINE
+ select SND_SOC_SOF_IPC4
+ select SND_SOC_SOF_INTEL_PTL
+
+config SND_SOC_SOF_NOVALAKE
+ tristate "SOF support for Novalake"
+ default SND_SOC_SOF_PCI
+ select SND_SOC_SOF_INTEL_NVL
+ help
+ This adds support for Sound Open Firmware for Intel(R) platforms
+ using the Novalake processors.
+ Say Y if you have such a device.
+ If unsure select "N".
+
config SND_SOC_SOF_HDA_COMMON
tristate
@@ -292,6 +328,7 @@ config SND_SOC_SOF_HDA_GENERIC
select SND_INTEL_DSP_CONFIG
select SND_SOC_SOF_HDA_LINK_BASELINE
select SND_SOC_SOF_HDA_PROBES
+ select SND_SOC_SDW_UTILS if SND_SOC_SOF_INTEL_SOUNDWIRE
select SND_SOC_SOF_HDA_MLINK if SND_SOC_SOF_HDA_LINK
help
This option is not user-selectable but automagically handled by
@@ -325,6 +362,13 @@ config SND_SOC_SOF_HDA_AUDIO_CODEC
endif ## SND_SOC_SOF_HDA_GENERIC
+config SND_SOF_SOF_HDA_SDW_BPT
+ tristate
+ select SND_HDA_EXT_CORE
+ help
+ This option is not user-selectable but automagically handled by
+ 'select' statements at a higher level.
+
config SND_SOC_SOF_HDA_LINK_BASELINE
tristate
select SND_SOC_SOF_HDA if SND_SOC_SOF_HDA_LINK
diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile
index b56fa5530b8b..cc9783e933f8 100644
--- a/sound/soc/sof/intel/Makefile
+++ b/sound/soc/sof/intel/Makefile
@@ -12,6 +12,8 @@ snd-sof-intel-hda-generic-y := hda.o hda-common-ops.o
snd-sof-intel-hda-mlink-y := hda-mlink.o
+snd-sof-intel-hda-sdw-bpt-objs := hda-sdw-bpt.o
+
snd-sof-intel-hda-common-$(CONFIG_SND_SOC_SOF_HDA_PROBES) += hda-probes.o
snd-sof-intel-hda-y := hda-codec.o
@@ -26,6 +28,8 @@ obj-$(CONFIG_SND_SOC_SOF_HDA_GENERIC) += snd-sof-intel-hda-generic.o
obj-$(CONFIG_SND_SOC_SOF_HDA_MLINK) += snd-sof-intel-hda-mlink.o
obj-$(CONFIG_SND_SOC_SOF_HDA) += snd-sof-intel-hda.o
+obj-$(CONFIG_SND_SOF_SOF_HDA_SDW_BPT) += snd-sof-intel-hda-sdw-bpt.o
+
snd-sof-pci-intel-tng-y := pci-tng.o
snd-sof-pci-intel-skl-y := pci-skl.o skl.o hda-loader-skl.o
snd-sof-pci-intel-apl-y := pci-apl.o apl.o
@@ -34,6 +38,8 @@ snd-sof-pci-intel-icl-y := pci-icl.o icl.o
snd-sof-pci-intel-tgl-y := pci-tgl.o tgl.o
snd-sof-pci-intel-mtl-y := pci-mtl.o mtl.o
snd-sof-pci-intel-lnl-y := pci-lnl.o lnl.o
+snd-sof-pci-intel-ptl-y := pci-ptl.o ptl.o
+snd-sof-pci-intel-nvl-y := pci-nvl.o nvl.o
obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o
@@ -43,3 +49,5 @@ obj-$(CONFIG_SND_SOC_SOF_INTEL_ICL) += snd-sof-pci-intel-icl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_TGL) += snd-sof-pci-intel-tgl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_MTL) += snd-sof-pci-intel-mtl.o
obj-$(CONFIG_SND_SOC_SOF_INTEL_LNL) += snd-sof-pci-intel-lnl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_PTL) += snd-sof-pci-intel-ptl.o
+obj-$(CONFIG_SND_SOC_SOF_INTEL_NVL) += snd-sof-pci-intel-nvl.o
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 76a92eaa1359..0c68ae41a8a8 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -118,4 +118,5 @@ const struct sof_intel_dsp_desc apl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5_PLUS,
+ .platform = "apl",
};
diff --git a/sound/soc/sof/intel/atom.c b/sound/soc/sof/intel/atom.c
index 3505ac3a1b14..0d364bcdcfa9 100644
--- a/sound/soc/sof/intel/atom.c
+++ b/sound/soc/sof/intel/atom.c
@@ -78,23 +78,23 @@ void atom_dump(struct snd_sof_dev *sdev, u32 flags)
imrd = snd_sof_dsp_read64(sdev, DSP_BAR, SHIM_IMRD);
dev_err(sdev->dev,
"error: ipc host -> DSP: pending %s complete %s raw 0x%llx\n",
- (panic & SHIM_IPCX_BUSY) ? "yes" : "no",
- (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic);
+ str_yes_no(panic & SHIM_IPCX_BUSY),
+ str_yes_no(panic & SHIM_IPCX_DONE), panic);
dev_err(sdev->dev,
"error: mask host: pending %s complete %s raw 0x%llx\n",
- (imrx & SHIM_IMRX_BUSY) ? "yes" : "no",
- (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx);
+ str_yes_no(imrx & SHIM_IMRX_BUSY),
+ str_yes_no(imrx & SHIM_IMRX_DONE), imrx);
dev_err(sdev->dev,
"error: ipc DSP -> host: pending %s complete %s raw 0x%llx\n",
- (status & SHIM_IPCD_BUSY) ? "yes" : "no",
- (status & SHIM_IPCD_DONE) ? "yes" : "no", status);
+ str_yes_no(status & SHIM_IPCD_BUSY),
+ str_yes_no(status & SHIM_IPCD_DONE), status);
dev_err(sdev->dev,
"error: mask DSP: pending %s complete %s raw 0x%llx\n",
- (imrd & SHIM_IMRD_BUSY) ? "yes" : "no",
- (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd);
+ str_yes_no(imrd & SHIM_IMRD_BUSY),
+ str_yes_no(imrd & SHIM_IMRD_DONE), imrd);
}
-EXPORT_SYMBOL_NS(atom_dump, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_dump, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
/*
* IPC Doorbell IRQ handler and thread.
@@ -131,7 +131,7 @@ irqreturn_t atom_irq_handler(int irq, void *context)
return ret;
}
-EXPORT_SYMBOL_NS(atom_irq_handler, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_irq_handler, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
irqreturn_t atom_irq_thread(int irq, void *context)
{
@@ -176,7 +176,7 @@ irqreturn_t atom_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(atom_irq_thread, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_irq_thread, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -191,19 +191,19 @@ int atom_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(atom_send_msg, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_send_msg, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MBOX_OFFSET;
}
-EXPORT_SYMBOL_NS(atom_get_mailbox_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_get_mailbox_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MBOX_OFFSET;
}
-EXPORT_SYMBOL_NS(atom_get_window_offset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_get_window_offset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
static void atom_host_done(struct snd_sof_dev *sdev)
{
@@ -248,7 +248,7 @@ int atom_run(struct snd_sof_dev *sdev)
/* return init core mask */
return 1;
}
-EXPORT_SYMBOL_NS(atom_run, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_run, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
int atom_reset(struct snd_sof_dev *sdev)
{
@@ -267,7 +267,7 @@ int atom_reset(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(atom_reset, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_reset, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *sof_tplg_filename,
@@ -330,7 +330,7 @@ struct snd_soc_acpi_mach *atom_machine_select(struct snd_sof_dev *sdev)
return mach;
}
-EXPORT_SYMBOL_NS(atom_machine_select, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_machine_select, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
/* Atom DAIs */
struct snd_soc_dai_driver atom_dai[] = {
@@ -401,7 +401,7 @@ struct snd_soc_dai_driver atom_dai[] = {
},
},
};
-EXPORT_SYMBOL_NS(atom_dai, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_dai, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
void atom_set_mach_params(struct snd_soc_acpi_mach *mach,
struct snd_sof_dev *sdev)
@@ -415,7 +415,7 @@ void atom_set_mach_params(struct snd_soc_acpi_mach *mach,
mach_params->num_dai_drivers = desc->ops->num_drv;
mach_params->dai_drivers = desc->ops->drv;
}
-EXPORT_SYMBOL_NS(atom_set_mach_params, SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+EXPORT_SYMBOL_NS(atom_set_mach_params, "SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Atom platforms");
diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c
index 7f18080e4e19..f1287d509835 100644
--- a/sound/soc/sof/intel/bdw.c
+++ b/sound/soc/sof/intel/bdw.c
@@ -266,20 +266,20 @@ static void bdw_dump(struct snd_sof_dev *sdev, u32 flags)
imrd = snd_sof_dsp_read(sdev, BDW_DSP_BAR, SHIM_IMRD);
dev_err(sdev->dev,
"error: ipc host -> DSP: pending %s complete %s raw 0x%8.8x\n",
- (panic & SHIM_IPCX_BUSY) ? "yes" : "no",
- (panic & SHIM_IPCX_DONE) ? "yes" : "no", panic);
+ str_yes_no(panic & SHIM_IPCX_BUSY),
+ str_yes_no(panic & SHIM_IPCX_DONE), panic);
dev_err(sdev->dev,
"error: mask host: pending %s complete %s raw 0x%8.8x\n",
- (imrx & SHIM_IMRX_BUSY) ? "yes" : "no",
- (imrx & SHIM_IMRX_DONE) ? "yes" : "no", imrx);
+ str_yes_no(imrx & SHIM_IMRX_BUSY),
+ str_yes_no(imrx & SHIM_IMRX_DONE), imrx);
dev_err(sdev->dev,
"error: ipc DSP -> host: pending %s complete %s raw 0x%8.8x\n",
- (status & SHIM_IPCD_BUSY) ? "yes" : "no",
- (status & SHIM_IPCD_DONE) ? "yes" : "no", status);
+ str_yes_no(status & SHIM_IPCD_BUSY),
+ str_yes_no(status & SHIM_IPCD_DONE), status);
dev_err(sdev->dev,
"error: mask DSP: pending %s complete %s raw 0x%8.8x\n",
- (imrd & SHIM_IMRD_BUSY) ? "yes" : "no",
- (imrd & SHIM_IMRD_DONE) ? "yes" : "no", imrd);
+ str_yes_no(imrd & SHIM_IMRD_BUSY),
+ str_yes_no(imrd & SHIM_IMRD_DONE), imrd);
}
/*
@@ -410,8 +410,7 @@ static int bdw_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
const struct sof_intel_dsp_desc *chip;
struct resource *mmio;
u32 base, size;
@@ -684,10 +683,10 @@ static int sof_broadwell_probe(struct platform_device *pdev)
/* acpi_driver definition */
static struct platform_driver snd_sof_acpi_intel_bdw_driver = {
.probe = sof_broadwell_probe,
- .remove_new = sof_acpi_remove,
+ .remove = sof_acpi_remove,
.driver = {
.name = "sof-audio-acpi-intel-bdw",
- .pm = &sof_acpi_pm,
+ .pm = pm_ptr(&sof_acpi_pm),
.acpi_match_table = sof_broadwell_match,
},
};
@@ -695,6 +694,5 @@ module_platform_driver(snd_sof_acpi_intel_bdw_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Broadwell platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV");
diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c
index 7a57e162fb1c..18208f77b84d 100644
--- a/sound/soc/sof/intel/byt.c
+++ b/sound/soc/sof/intel/byt.c
@@ -109,8 +109,7 @@ static int byt_acpi_probe(struct snd_sof_dev *sdev)
{
struct snd_sof_pdata *pdata = sdev->pdata;
const struct sof_dev_desc *desc = pdata->desc;
- struct platform_device *pdev =
- container_of(sdev->dev, struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(sdev->dev);
const struct sof_intel_dsp_desc *chip;
struct resource *mmio;
u32 base, size;
@@ -465,10 +464,10 @@ static int sof_baytrail_probe(struct platform_device *pdev)
/* acpi_driver definition */
static struct platform_driver snd_sof_acpi_intel_byt_driver = {
.probe = sof_baytrail_probe,
- .remove_new = sof_acpi_remove,
+ .remove = sof_acpi_remove,
.driver = {
.name = "sof-audio-acpi-intel-byt",
- .pm = &sof_acpi_pm,
+ .pm = pm_ptr(&sof_acpi_pm),
.acpi_match_table = sof_baytrail_match,
},
};
@@ -476,7 +475,6 @@ module_platform_driver(snd_sof_acpi_intel_byt_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_IMPORT_NS(SND_SOC_SOF_ACPI_DEV);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 6a8c7a108ef0..0cc5725515e7 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -110,7 +110,7 @@ irqreturn_t cnl_ipc4_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc4_irq_thread, "SND_SOC_SOF_INTEL_CNL");
irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
{
@@ -203,7 +203,7 @@ irqreturn_t cnl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(cnl_ipc_irq_thread, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc_irq_thread, "SND_SOC_SOF_INTEL_CNL");
static void cnl_ipc_host_done(struct snd_sof_dev *sdev)
{
@@ -286,7 +286,7 @@ int cnl_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(cnl_ipc4_send_msg, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc4_send_msg, "SND_SOC_SOF_INTEL_CNL");
int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -329,12 +329,12 @@ int cnl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
* CTX_SAVE IPC, which is sent before the DSP enters D3.
*/
if (hdr->cmd != (SOF_IPC_GLB_PM_MSG | SOF_IPC_PM_CTX_SAVE))
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
return 0;
}
-EXPORT_SYMBOL_NS(cnl_ipc_send_msg, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc_send_msg, "SND_SOC_SOF_INTEL_CNL");
void cnl_ipc_dump(struct snd_sof_dev *sdev)
{
@@ -355,7 +355,7 @@ void cnl_ipc_dump(struct snd_sof_dev *sdev)
"error: host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
hipcida, hipctdr, hipcctl);
}
-EXPORT_SYMBOL_NS(cnl_ipc_dump, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc_dump, "SND_SOC_SOF_INTEL_CNL");
void cnl_ipc4_dump(struct snd_sof_dev *sdev)
{
@@ -377,11 +377,11 @@ void cnl_ipc4_dump(struct snd_sof_dev *sdev)
"Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n",
hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl);
}
-EXPORT_SYMBOL_NS(cnl_ipc4_dump, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(cnl_ipc4_dump, "SND_SOC_SOF_INTEL_CNL");
/* cannonlake ops */
struct snd_sof_dsp_ops sof_cnl_ops;
-EXPORT_SYMBOL_NS(sof_cnl_ops, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(sof_cnl_ops, "SND_SOC_SOF_INTEL_CNL");
int sof_cnl_ops_init(struct snd_sof_dev *sdev)
{
@@ -450,7 +450,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_cnl_ops_init, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(sof_cnl_ops_init, "SND_SOC_SOF_INTEL_CNL");
const struct sof_intel_dsp_desc cnl_chip_info = {
/* Cannonlake */
@@ -479,6 +479,7 @@ const struct sof_intel_dsp_desc cnl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_8,
+ .platform = "cnl",
};
/*
@@ -515,5 +516,6 @@ const struct sof_intel_dsp_desc jsl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "jsl",
};
-EXPORT_SYMBOL_NS(jsl_chip_info, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(jsl_chip_info, "SND_SOC_SOF_INTEL_CNL");
diff --git a/sound/soc/sof/intel/hda-bus.c b/sound/soc/sof/intel/hda-bus.c
index 1989147aa6a4..6492e1cefbfb 100644
--- a/sound/soc/sof/intel/hda-bus.c
+++ b/sound/soc/sof/intel/hda-bus.c
@@ -76,7 +76,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);
- if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0)
+ if (chip && chip->hw_ip_version >= SOF_INTEL_ACE_2_0)
bus->use_pio_for_commands = true;
#else
snd_hdac_ext_bus_init(bus, dev, NULL, NULL);
@@ -99,7 +99,7 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)
spin_lock_init(&bus->reg_lock);
#endif /* CONFIG_SND_SOC_SOF_HDA_LINK */
}
-EXPORT_SYMBOL_NS(sof_hda_bus_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_hda_bus_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
void sof_hda_bus_exit(struct snd_sof_dev *sdev)
{
@@ -109,4 +109,4 @@ void sof_hda_bus_exit(struct snd_sof_dev *sdev)
snd_hdac_ext_bus_exit(bus);
#endif
}
-EXPORT_SYMBOL_NS(sof_hda_bus_exit, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_hda_bus_exit, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c
index dc46888faa0d..37674ea452d6 100644
--- a/sound/soc/sof/intel/hda-codec.c
+++ b/sound/soc/sof/intel/hda-codec.c
@@ -101,7 +101,7 @@ void hda_codec_jack_wake_enable(struct snd_sof_dev *sdev, bool enable)
snd_hdac_chip_updatew(bus, WAKEEN, mask & STATESTS_INT_MASK, val);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_wake_enable, "SND_SOC_SOF_HDA_AUDIO_CODEC");
/* check jack status after resuming from suspend mode */
void hda_codec_jack_check(struct snd_sof_dev *sdev)
@@ -121,7 +121,7 @@ void hda_codec_jack_check(struct snd_sof_dev *sdev)
if (codec->jacktbl.used)
pm_request_resume(&codec->core.dev);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_jack_check, "SND_SOC_SOF_HDA_AUDIO_CODEC");
#if IS_ENABLED(CONFIG_SND_HDA_GENERIC)
#define is_generic_config(bus) \
@@ -237,7 +237,7 @@ void hda_codec_probe_bus(struct snd_sof_dev *sdev)
}
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_probe_bus, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
{
@@ -250,7 +250,7 @@ void hda_codec_check_for_state_change(struct snd_sof_dev *sdev)
snd_hdac_chip_writew(bus, STATESTS, codec_mask);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_for_state_change, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_detect_mask(struct snd_sof_dev *sdev)
{
@@ -260,9 +260,6 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev)
sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
return;
- /* Accept unsolicited responses */
- snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
-
/* detect codecs */
if (!bus->codec_mask) {
bus->codec_mask = snd_hdac_chip_readw(bus, STATESTS);
@@ -275,7 +272,7 @@ void hda_codec_detect_mask(struct snd_sof_dev *sdev)
bus->codec_mask);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_detect_mask, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
{
@@ -288,7 +285,7 @@ void hda_codec_init_cmd_io(struct snd_sof_dev *sdev)
/* initialize the codec command I/O */
snd_hdac_bus_init_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_init_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
{
@@ -302,7 +299,7 @@ void hda_codec_resume_cmd_io(struct snd_sof_dev *sdev)
if (bus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_resume_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
{
@@ -315,7 +312,7 @@ void hda_codec_stop_cmd_io(struct snd_sof_dev *sdev)
/* initialize the codec command I/O */
snd_hdac_bus_stop_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_stop_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
{
@@ -330,7 +327,7 @@ void hda_codec_suspend_cmd_io(struct snd_sof_dev *sdev)
snd_hdac_bus_stop_cmd_io(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_suspend_cmd_io, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
{
@@ -343,7 +340,7 @@ void hda_codec_rirb_status_clear(struct snd_sof_dev *sdev)
/* clear rirb status */
snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_rirb_status_clear, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
{
@@ -354,7 +351,7 @@ void hda_codec_set_codec_wakeup(struct snd_sof_dev *sdev, bool status)
snd_hdac_set_codec_wakeup(bus, status);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_set_codec_wakeup, "SND_SOC_SOF_HDA_AUDIO_CODEC");
bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
{
@@ -381,7 +378,7 @@ bool hda_codec_check_rirb_status(struct snd_sof_dev *sdev)
}
return active;
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_check_rirb_status, "SND_SOC_SOF_HDA_AUDIO_CODEC");
void hda_codec_device_remove(struct snd_sof_dev *sdev)
{
@@ -394,7 +391,7 @@ void hda_codec_device_remove(struct snd_sof_dev *sdev)
/* codec removal, invoke bus_device_remove */
snd_hdac_ext_bus_device_remove(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, SND_SOC_SOF_HDA_AUDIO_CODEC);
+EXPORT_SYMBOL_NS_GPL(hda_codec_device_remove, "SND_SOC_SOF_HDA_AUDIO_CODEC");
#endif /* CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC */
@@ -413,7 +410,7 @@ void hda_codec_i915_display_power(struct snd_sof_dev *sdev, bool enable)
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, enable);
}
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_display_power, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
int hda_codec_i915_init(struct snd_sof_dev *sdev)
{
@@ -434,7 +431,7 @@ int hda_codec_i915_init(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_init, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
int hda_codec_i915_exit(struct snd_sof_dev *sdev)
{
@@ -452,8 +449,9 @@ int hda_codec_i915_exit(struct snd_sof_dev *sdev)
return snd_hdac_i915_exit(bus);
}
-EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+EXPORT_SYMBOL_NS_GPL(hda_codec_i915_exit, "SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
+MODULE_SOFTDEP("pre: snd-hda-codec-hdmi");
#endif
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/intel/hda-common-ops.c b/sound/soc/sof/intel/hda-common-ops.c
index 5fc28039a8e8..746b426b1329 100644
--- a/sound/soc/sof/intel/hda-common-ops.c
+++ b/sound/soc/sof/intel/hda-common-ops.c
@@ -105,4 +105,4 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = {
.dsp_arch_ops = &sof_xtensa_arch_ops,
};
-EXPORT_SYMBOL_NS(sof_hda_common_ops, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(sof_hda_common_ops, "SND_SOC_SOF_INTEL_HDA_GENERIC");
diff --git a/sound/soc/sof/intel/hda-ctrl.c b/sound/soc/sof/intel/hda-ctrl.c
index b9a02750ce61..8332d4bda558 100644
--- a/sound/soc/sof/intel/hda-ctrl.c
+++ b/sound/soc/sof/intel/hda-ctrl.c
@@ -128,7 +128,7 @@ int hda_dsp_ctrl_get_caps(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_ctrl_get_caps, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_get_caps, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
{
@@ -137,7 +137,7 @@ void hda_dsp_ctrl_ppcap_enable(struct snd_sof_dev *sdev, bool enable)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_GPROCEN, val);
}
-EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_enable, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
{
@@ -146,7 +146,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable)
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
SOF_HDA_PPCTL_PIE, val);
}
-EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_ppcap_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable)
{
@@ -181,9 +181,9 @@ int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_ctrl_clock_power_gating, SND_SOC_SOF_INTEL_HDA_COMMON);
+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)
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec)
{
struct hdac_bus *bus = sof_to_bus(sdev);
struct hdac_stream *stream;
@@ -220,7 +220,11 @@ int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev)
}
usleep_range(1000, 1200);
- hda_codec_detect_mask(sdev);
+ /* Accept unsolicited responses */
+ snd_hdac_chip_updatel(bus, GCTL, AZX_GCTL_UNSOL, AZX_GCTL_UNSOL);
+
+ if (detect_codec)
+ hda_codec_detect_mask(sdev);
/* clear stream status */
list_for_each_entry(stream, &bus->stream_list, list) {
@@ -266,7 +270,7 @@ err:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_ctrl_init_chip, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ctrl_init_chip, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
{
@@ -329,6 +333,6 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF helpers for HDaudio platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
diff --git a/sound/soc/sof/intel/hda-dai-ops.c b/sound/soc/sof/intel/hda-dai-ops.c
index 484c76147885..92681ca7f24d 100644
--- a/sound/soc/sof/intel/hda-dai-ops.c
+++ b/sound/soc/sof/intel/hda-dai-ops.c
@@ -346,20 +346,21 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
snd_hdac_ext_stream_start(hext_stream);
break;
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_hdac_ext_stream_clear(hext_stream);
-
/*
- * Save the LLP registers in case the stream is
- * restarting due PAUSE_RELEASE, or START without a pcm
- * close/open since in this case the LLP register is not reset
- * to 0 and the delay calculation will return with invalid
- * results.
+ * Save the LLP registers since in case of PAUSE the LLP
+ * register are not reset to 0, the delay calculation will use
+ * the saved offsets for compensating the delay calculation.
*/
hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
+ snd_hdac_ext_stream_clear(hext_stream);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_STOP:
+ hext_stream->pplcllpl = 0;
+ hext_stream->pplcllpu = 0;
+ snd_hdac_ext_stream_clear(hext_stream);
break;
default:
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
@@ -512,7 +513,6 @@ static const struct hda_dai_widget_dma_ops sdw_ipc4_chain_dma_ops = {
static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
struct snd_pcm_substream *substream, int cmd)
{
- struct hdac_ext_stream *hext_stream = hda_get_hext_stream(sdev, cpu_dai, substream);
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
switch (cmd) {
@@ -527,9 +527,6 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
if (ret < 0)
return ret;
- if (cmd == SNDRV_PCM_TRIGGER_STOP)
- return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
-
break;
}
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index 1c823f9eea57..883d0d3bae9e 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -54,7 +54,7 @@ int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
return 0;
}
-EXPORT_SYMBOL_NS(hda_dai_config, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dai_config, "SND_SOC_SOF_INTEL_HDA_COMMON");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
@@ -103,8 +103,10 @@ hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai
return sdai->platform_private;
}
-int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
- struct snd_soc_dai *cpu_dai)
+static int
+hda_link_dma_cleanup(struct snd_pcm_substream *substream,
+ struct hdac_ext_stream *hext_stream,
+ struct snd_soc_dai *cpu_dai, bool release)
{
const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
struct sof_intel_hda_stream *hda_stream;
@@ -128,6 +130,17 @@ int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_st
snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
}
+ if (!release) {
+ /*
+ * Force stream reconfiguration without releasing the channel on
+ * subsequent stream restart (without free), including LinkDMA
+ * reset.
+ * The stream is released via hda_dai_hw_free()
+ */
+ hext_stream->link_prepared = 0;
+ return 0;
+ }
+
if (ops->release_hext_stream)
ops->release_hext_stream(sdev, cpu_dai, substream);
@@ -211,7 +224,7 @@ static int __maybe_unused hda_dai_hw_free(struct snd_pcm_substream *substream,
if (!hext_stream)
return 0;
- return hda_link_dma_cleanup(substream, hext_stream, cpu_dai);
+ return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, true);
}
static int __maybe_unused hda_dai_hw_params_data(struct snd_pcm_substream *substream,
@@ -302,8 +315,10 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i
}
switch (cmd) {
+ case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
- ret = hda_link_dma_cleanup(substream, hext_stream, dai);
+ ret = hda_link_dma_cleanup(substream, hext_stream, dai,
+ cmd != SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
return ret;
@@ -370,6 +385,13 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
return -EINVAL;
}
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
/* use HDaudio stream handling */
ret = hda_dai_hw_params_data(substream, params, cpu_dai, data, flags);
if (ret < 0) {
@@ -377,7 +399,6 @@ static int non_hda_dai_hw_params_data(struct snd_pcm_substream *substream,
return ret;
}
- sdev = widget_to_sdev(w);
if (sdev->dspless_mode_selected)
return 0;
@@ -482,6 +503,37 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
int ret;
int i;
+ if (!w) {
+ dev_err(cpu_dai->dev, "%s widget not found, check amp link num in the topology\n",
+ cpu_dai->name);
+ return -EINVAL;
+ }
+
+ ops = hda_dai_get_ops(substream, cpu_dai);
+ if (!ops) {
+ dev_err(cpu_dai->dev, "DAI widget ops not set\n");
+ return -EINVAL;
+ }
+
+ sdev = widget_to_sdev(w);
+ hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
+
+ /* nothing more to do if the link is already prepared */
+ if (hext_stream && hext_stream->link_prepared)
+ return 0;
+
+ /*
+ * reset the PCMSyCM registers to handle a prepare callback when the PCM is restarted
+ * due to xruns or after a call to snd_pcm_drain/drop()
+ */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id, cpu_dai->id,
+ 0, 0, substream->stream);
+ if (ret < 0) {
+ dev_err(cpu_dai->dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed %d\n",
+ __func__, ret);
+ return ret;
+ }
+
data.dai_index = (link_id << 8) | cpu_dai->id;
data.dai_node_id = intel_alh_id;
ret = non_hda_dai_hw_params_data(substream, params, cpu_dai, &data, flags);
@@ -490,10 +542,7 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- ops = hda_dai_get_ops(substream, cpu_dai);
- sdev = widget_to_sdev(w);
hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
-
if (!hext_stream)
return -ENODEV;
@@ -539,13 +588,19 @@ int sdw_hda_dai_hw_params(struct snd_pcm_substream *substream,
*/
for_each_rtd_cpu_dais(rtd, i, dai) {
w = snd_soc_dai_get_widget(dai, substream->stream);
+ if (!w) {
+ dev_err(cpu_dai->dev,
+ "%s widget not found, check amp link num in the topology\n",
+ dai->name);
+ return -EINVAL;
+ }
ipc4_copier = widget_to_copier(w);
memcpy(&ipc4_copier->dma_config_tlv[cpu_dai_id], dma_config_tlv,
sizeof(*dma_config_tlv));
}
return 0;
}
-EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sdw_hda_dai_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai,
@@ -574,14 +629,14 @@ int sdw_hda_dai_hw_free(struct snd_pcm_substream *substream,
return 0;
}
-EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sdw_hda_dai_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
int sdw_hda_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_dai *cpu_dai)
{
return hda_dai_trigger(substream, cmd, cpu_dai);
}
-EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sdw_hda_dai_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
static int hda_dai_suspend(struct hdac_bus *bus)
{
@@ -617,6 +672,10 @@ static int hda_dai_suspend(struct hdac_bus *bus)
sdai = swidget->private;
ops = sdai->platform_private;
+ if (rtd->dpcm[hext_stream->link_substream->stream].state !=
+ SND_SOC_DPCM_STATE_PAUSED)
+ continue;
+
/* for consistency with TRIGGER_SUSPEND */
if (ops->post_trigger) {
ret = ops->post_trigger(sdev, cpu_dai,
@@ -627,8 +686,7 @@ static int hda_dai_suspend(struct hdac_bus *bus)
}
ret = hda_link_dma_cleanup(hext_stream->link_substream,
- hext_stream,
- cpu_dai);
+ hext_stream, cpu_dai, true);
if (ret < 0)
return ret;
}
@@ -696,7 +754,7 @@ void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
}
}
-EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_set_dai_drv_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ops_free(struct snd_sof_dev *sdev)
{
@@ -710,7 +768,7 @@ void hda_ops_free(struct snd_sof_dev *sdev)
sdev->private = NULL;
}
}
-EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ops_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* common dai driver for skl+ platforms.
@@ -862,7 +920,7 @@ struct snd_soc_dai_driver skl_dai[] = {
},
#endif
};
-EXPORT_SYMBOL_NS(skl_dai, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(skl_dai, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
{
diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c
index 1315f5bc3e31..e9f092f082a1 100644
--- a/sound/soc/sof/intel/hda-dsp.c
+++ b/sound/soc/sof/intel/hda-dsp.c
@@ -69,6 +69,8 @@ static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask)
interface_mask[SOF_DAI_HOST_ACCESS] = BIT(SOF_DAI_INTEL_HDA);
break;
case SOF_INTEL_ACE_2_0:
+ case SOF_INTEL_ACE_3_0:
+ case SOF_INTEL_ACE_4_0:
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);
@@ -89,7 +91,7 @@ u32 hda_get_interface_mask(struct snd_sof_dev *sdev)
return interface_mask[sdev->dspless_mode_selected];
}
-EXPORT_SYMBOL_NS(hda_get_interface_mask, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_get_interface_mask, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
{
@@ -119,7 +121,7 @@ bool hda_is_chain_dma_supported(struct snd_sof_dev *sdev, u32 dai_type)
return false;
}
}
-EXPORT_SYMBOL_NS(hda_is_chain_dma_supported, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_is_chain_dma_supported, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* DSP Core control.
@@ -215,7 +217,7 @@ int hda_dsp_core_stall_reset(struct snd_sof_dev *sdev, unsigned int core_mask)
/* set reset state */
return hda_dsp_core_reset_enter(sdev, core_mask);
}
-EXPORT_SYMBOL_NS(hda_dsp_core_stall_reset, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_stall_reset, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -241,7 +243,7 @@ bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev, unsigned int core_mask)
return is_enable;
}
-EXPORT_SYMBOL_NS(hda_dsp_core_is_enabled, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_is_enabled, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -269,7 +271,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_core_run, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_run, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* Power Management.
@@ -321,7 +323,7 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_core_power_up, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_power_up, "SND_SOC_SOF_INTEL_HDA_COMMON");
static int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask)
{
@@ -369,7 +371,7 @@ int hda_dsp_enable_core(struct snd_sof_dev *sdev, unsigned int core_mask)
return hda_dsp_core_run(sdev, core_mask);
}
-EXPORT_SYMBOL_NS(hda_dsp_enable_core, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_enable_core, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
unsigned int core_mask)
@@ -410,7 +412,7 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev,
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_core_reset_power_down, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_reset_power_down, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
{
@@ -429,7 +431,7 @@ void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, HDA_DSP_REG_ADSPIC,
HDA_DSP_ADSPIC_IPC, HDA_DSP_ADSPIC_IPC);
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
{
@@ -447,7 +449,7 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0);
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_int_disable, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_int_disable, "SND_SOC_SOF_INTEL_HDA_COMMON");
static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev)
{
@@ -731,7 +733,7 @@ int hda_dsp_set_power_state_ipc3(struct snd_sof_dev *sdev,
return hda_dsp_set_power_state(sdev, target_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc3, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc3, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
const struct sof_dsp_power_state *target_state)
@@ -743,7 +745,7 @@ int hda_dsp_set_power_state_ipc4(struct snd_sof_dev *sdev,
return hda_dsp_set_power_state(sdev, target_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc4, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_set_power_state_ipc4, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* Audio DSP states may transform as below:-
@@ -857,7 +859,6 @@ 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 */
@@ -870,7 +871,7 @@ static int hda_resume(struct snd_sof_dev *sdev, bool runtime_resume)
snd_sof_pci_update_bits(sdev, PCI_TCSEL, 0x07, 0);
/* reset and start hda controller */
- ret = hda_dsp_ctrl_init_chip(sdev);
+ ret = hda_dsp_ctrl_init_chip(sdev, false);
if (ret < 0) {
dev_err(sdev->dev,
"error: failed to start controller after resume\n");
@@ -890,10 +891,6 @@ 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);
@@ -952,7 +949,7 @@ int hda_dsp_resume(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_resume, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
{
@@ -968,7 +965,7 @@ int hda_dsp_runtime_resume(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_runtime_resume, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_runtime_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
{
@@ -982,7 +979,7 @@ int hda_dsp_runtime_idle(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_runtime_idle, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_runtime_idle, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
{
@@ -995,6 +992,10 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
+
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
}
/* stop hda controller and power dsp off */
@@ -1004,7 +1005,7 @@ int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev)
return snd_sof_dsp_set_power_state(sdev, &target_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_runtime_suspend, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_runtime_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
{
@@ -1021,6 +1022,10 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
if (!sdev->dspless_mode_selected) {
/* cancel any attempt for DSP D0I3 */
cancel_delayed_work_sync(&hda->d0i3_work);
+
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
}
if (target_state == SOF_DSP_PM_D0) {
@@ -1065,7 +1070,7 @@ int hda_dsp_suspend(struct snd_sof_dev *sdev, u32 target_state)
return snd_sof_dsp_set_power_state(sdev, &target_dsp_state);
}
-EXPORT_SYMBOL_NS(hda_dsp_suspend, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_suspend, "SND_SOC_SOF_INTEL_HDA_COMMON");
static unsigned int hda_dsp_check_for_dma_streams(struct snd_sof_dev *sdev)
{
@@ -1138,14 +1143,14 @@ int hda_dsp_shutdown_dma_flush(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_shutdown_dma_flush, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_shutdown_dma_flush, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_shutdown(struct snd_sof_dev *sdev)
{
sdev->system_suspend_target = SOF_SUSPEND_S3;
return snd_sof_suspend(sdev->dev);
}
-EXPORT_SYMBOL_NS(hda_dsp_shutdown, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_shutdown, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
{
@@ -1158,7 +1163,7 @@ int hda_dsp_set_hw_params_upon_resume(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_set_hw_params_upon_resume, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_set_hw_params_upon_resume, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_d0i3_work(struct work_struct *work)
{
@@ -1185,7 +1190,7 @@ void hda_dsp_d0i3_work(struct work_struct *work)
"error: failed to set DSP state %d substate %d\n",
target_state.state, target_state.substate);
}
-EXPORT_SYMBOL_NS(hda_dsp_d0i3_work, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
@@ -1226,7 +1231,7 @@ power_down:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_core_get, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_core_get, "SND_SOC_SOF_INTEL_HDA_COMMON");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
@@ -1242,7 +1247,7 @@ void hda_common_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_ADSPIC2_SNDW,
enable ? HDA_DSP_REG_ADSPIC2_SNDW : 0);
}
-EXPORT_SYMBOL_NS(hda_common_enable_sdw_irq, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_common_enable_sdw_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
{
@@ -1256,7 +1261,7 @@ void hda_sdw_int_enable(struct snd_sof_dev *sdev, bool enable)
if (chip && chip->enable_sdw_irq)
chip->enable_sdw_irq(sdev, enable);
}
-EXPORT_SYMBOL_NS(hda_sdw_int_enable, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_sdw_int_enable, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
{
@@ -1280,7 +1285,7 @@ int hda_sdw_check_lcount_common(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_sdw_check_lcount_common, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount_common, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
{
@@ -1306,7 +1311,7 @@ int hda_sdw_check_lcount_ext(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_sdw_check_lcount_ext, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount_ext, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
{
@@ -1318,7 +1323,7 @@ int hda_sdw_check_lcount(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_sdw_check_lcount, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_sdw_check_lcount, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
{
@@ -1332,7 +1337,7 @@ void hda_sdw_process_wakeen(struct snd_sof_dev *sdev)
if (chip && chip->sdw_process_wakeen)
chip->sdw_process_wakeen(sdev);
}
-EXPORT_SYMBOL_NS(hda_sdw_process_wakeen, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_sdw_process_wakeen, "SND_SOC_SOF_INTEL_HDA_COMMON");
#endif
@@ -1343,7 +1348,7 @@ int hda_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_disable_interrupts, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_HDA_COMMON");
static const struct hda_dsp_msg_code hda_dsp_rom_fw_error_texts[] = {
{HDA_DSP_ROM_CSE_ERROR, "error: cse error"},
@@ -1554,7 +1559,7 @@ void hda_dsp_get_state(struct snd_sof_dev *sdev, const char *level)
dev_printk(level, sdev->dev, "error code: %#x (%s)\n", error_code,
error_text);
}
-EXPORT_SYMBOL_NS(hda_dsp_get_state, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_get_state, "SND_SOC_SOF_INTEL_HDA_COMMON");
static void hda_dsp_get_registers(struct snd_sof_dev *sdev,
struct sof_ipc_dsp_oops_xtensa *xoops,
@@ -1627,4 +1632,4 @@ void hda_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
hda_dsp_dump_ext_rom_status(sdev, level, flags);
}
}
-EXPORT_SYMBOL_NS(hda_dsp_dump, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-ipc.c b/sound/soc/sof/intel/hda-ipc.c
index 9feaaa2d166a..94425c510861 100644
--- a/sound/soc/sof/intel/hda-ipc.c
+++ b/sound/soc/sof/intel/hda-ipc.c
@@ -72,7 +72,7 @@ int hda_dsp_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_send_msg, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON");
static inline bool hda_dsp_ipc4_pm_msg(u32 primary)
{
@@ -96,10 +96,10 @@ void hda_dsp_ipc4_schedule_d0i3_work(struct sof_intel_hda_dev *hdev,
if (hda_dsp_ipc4_pm_msg(msg_data->primary))
return;
- mod_delayed_work(system_wq, &hdev->d0i3_work,
+ mod_delayed_work(system_dfl_wq, &hdev->d0i3_work,
msecs_to_jiffies(SOF_HDA_D0I3_WORK_DELAY_MS));
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_schedule_d0i3_work, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
@@ -126,7 +126,7 @@ int hda_dsp_ipc4_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_send_msg, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
{
@@ -162,7 +162,7 @@ void hda_dsp_ipc_get_reply(struct snd_sof_dev *sdev)
snd_sof_ipc_get_reply(sdev);
}
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_get_reply, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_reply, "SND_SOC_SOF_INTEL_HDA_COMMON");
irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
{
@@ -245,7 +245,7 @@ irqreturn_t hda_dsp_ipc4_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* IPC handler thread */
irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
@@ -358,7 +358,7 @@ irqreturn_t hda_dsp_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_irq_thread, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_irq_thread, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* Check if an IPC IRQ occurred */
bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
@@ -392,19 +392,19 @@ bool hda_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
out:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_check_ipc_irq, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return HDA_DSP_MBOX_UPLINK_OFFSET;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return SRAM_WINDOW_OFFSET(id);
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_ipc_msg_data(struct snd_sof_dev *sdev,
struct snd_sof_pcm_stream *sps,
@@ -430,7 +430,7 @@ int hda_ipc_msg_data(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_ipc_msg_data, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc_msg_data, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_set_stream_data_offset(struct snd_sof_dev *sdev,
struct snd_sof_pcm_stream *sps,
@@ -455,7 +455,7 @@ int hda_set_stream_data_offset(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_set_stream_data_offset, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_set_stream_data_offset, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
@@ -469,7 +469,7 @@ void hda_ipc4_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
else
hda_dsp_dump_ext_rom_status(sdev, level, flags);
}
-EXPORT_SYMBOL_NS(hda_ipc4_dsp_dump, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc4_dsp_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
{
@@ -481,7 +481,7 @@ bool hda_check_ipc_irq(struct snd_sof_dev *sdev)
return false;
}
-EXPORT_SYMBOL_NS(hda_check_ipc_irq, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_check_ipc_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
{
@@ -502,7 +502,7 @@ void hda_ipc_irq_dump(struct snd_sof_dev *sdev)
intsts, intctl, rirbsts);
dev_err(sdev->dev, "dsp irq ppsts 0x%8.8x adspis 0x%8.8x\n", ppsts, adspis);
}
-EXPORT_SYMBOL_NS(hda_ipc_irq_dump, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc_irq_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ipc_dump(struct snd_sof_dev *sdev)
{
@@ -522,7 +522,7 @@ void hda_ipc_dump(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "host status 0x%8.8x dsp status 0x%8.8x mask 0x%8.8x\n",
hipcie, hipct, hipcctl);
}
-EXPORT_SYMBOL_NS(hda_ipc_dump, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_ipc4_dump(struct snd_sof_dev *sdev)
{
@@ -541,7 +541,7 @@ void hda_ipc4_dump(struct snd_sof_dev *sdev)
dev_err(sdev->dev, "Host IPC initiator: %#x|%#x, target: %#x|%#x, ctl: %#x\n",
hipci, hipcie, hipct, hipcte, hipcctl);
}
-EXPORT_SYMBOL_NS(hda_ipc4_dump, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc4_dump, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
{
@@ -553,4 +553,4 @@ bool hda_ipc4_tx_is_busy(struct snd_sof_dev *sdev)
return !!(val & chip->ipc_req_mask);
}
-EXPORT_SYMBOL_NS(hda_ipc4_tx_is_busy, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_ipc4_tx_is_busy, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index b8b914eaf7e0..2cc11d8b0f70 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -26,6 +26,11 @@
#include "../sof-priv.h"
#include "hda.h"
+static bool persistent_cl_buffer = true;
+module_param(persistent_cl_buffer, bool, 0444);
+MODULE_PARM_DESC(persistent_cl_buffer, "Persistent Code Loader DMA buffer "
+ "(default = Y, use N to force buffer re-allocation)");
+
static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
@@ -43,9 +48,10 @@ static void hda_ssp_set_cbp_cfp(struct snd_sof_dev *sdev)
}
}
-struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
- unsigned int size, struct snd_dma_buffer *dmab,
- int direction, bool is_iccmax)
+struct hdac_ext_stream*
+hda_cl_prepare(struct device *dev, unsigned int format, unsigned int size,
+ struct snd_dma_buffer *dmab, bool persistent_buffer, int direction,
+ bool is_iccmax)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_ext_stream *hext_stream;
@@ -61,11 +67,19 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
hstream = &hext_stream->hstream;
hstream->substream = NULL;
- /* allocate DMA buffer */
- ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
- if (ret < 0) {
- dev_err(sdev->dev, "error: memory alloc failed: %d\n", ret);
- goto out_put;
+ /*
+ * Allocate DMA buffer if it is temporary or if the buffer is intended
+ * to be persistent but not yet allocated.
+ * We cannot rely solely on !dmab->area as caller might use a struct on
+ * stack (when it is temporary) without clearing it to 0.
+ */
+ if (!persistent_buffer || !dmab->area) {
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, dev, size, dmab);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: memory alloc failed: %d\n",
+ __func__, ret);
+ goto out_put;
+ }
}
hstream->period_bytes = 0;/* initialize period_bytes */
@@ -91,11 +105,15 @@ struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
out_free:
snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+ dmab->bytes = 0;
+ hstream->bufsize = 0;
+ hstream->format_val = 0;
out_put:
hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_NS(hda_cl_prepare, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_cl_prepare, "SND_SOC_SOF_INTEL_HDA_COMMON");
/*
* first boot sequence has some extra steps.
@@ -219,7 +237,7 @@ err:
kfree(dump_msg);
return ret;
}
-EXPORT_SYMBOL_NS(cl_dsp_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(cl_dsp_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int cmd)
{
@@ -252,10 +270,10 @@ int hda_cl_trigger(struct device *dev, struct hdac_ext_stream *hext_stream, int
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
}
-EXPORT_SYMBOL_NS(hda_cl_trigger, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_cl_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
- struct hdac_ext_stream *hext_stream)
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct hdac_stream *hstream = &hext_stream->hstream;
@@ -279,14 +297,18 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab,
sd_offset + SOF_HDA_ADSP_REG_SD_BDLPU, 0);
snd_sof_dsp_write(sdev, HDA_DSP_HDA_BAR, sd_offset, 0);
- snd_dma_free_pages(dmab);
- dmab->area = NULL;
- hstream->bufsize = 0;
- hstream->format_val = 0;
+
+ if (!persistent_buffer) {
+ snd_dma_free_pages(dmab);
+ dmab->area = NULL;
+ dmab->bytes = 0;
+ hstream->bufsize = 0;
+ hstream->format_val = 0;
+ }
return ret;
}
-EXPORT_SYMBOL_NS(hda_cl_cleanup, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_cl_cleanup, "SND_SOC_SOF_INTEL_HDA_COMMON");
#define HDA_CL_DMA_IOC_TIMEOUT_MS 500
@@ -294,14 +316,9 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
- struct sof_intel_hda_stream *hda_stream;
- unsigned long time_left;
unsigned int reg;
int ret, status;
- hda_stream = container_of(hext_stream, struct sof_intel_hda_stream,
- hext_stream);
-
dev_dbg(sdev->dev, "Code loader DMA starting\n");
ret = hda_cl_trigger(sdev->dev, hext_stream, SNDRV_PCM_TRIGGER_START);
@@ -310,15 +327,7 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
return ret;
}
- /* Wait for completion of transfer */
- time_left = wait_for_completion_timeout(&hda_stream->ioc,
- msecs_to_jiffies(HDA_CL_DMA_IOC_TIMEOUT_MS));
-
- if (!time_left) {
- dev_err(sdev->dev, "Code loader DMA did not complete\n");
- return -ETIMEDOUT;
- }
- dev_dbg(sdev->dev, "Code loader DMA done, waiting for FW_ENTERED status\n");
+ dev_dbg(sdev->dev, "waiting for FW_ENTERED status\n");
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
chip->rom_status_reg, reg,
@@ -353,8 +362,8 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
{
+ struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct hdac_ext_stream *iccmax_stream;
- struct snd_dma_buffer dmab_bdl;
int ret, ret1;
u8 original_gb;
@@ -367,7 +376,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* the data, so use a buffer of PAGE_SIZE for receiving.
*/
iccmax_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT, PAGE_SIZE,
- &dmab_bdl, SNDRV_PCM_STREAM_CAPTURE, true);
+ &hda->iccmax_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_CAPTURE, true);
if (IS_ERR(iccmax_stream)) {
dev_err(sdev->dev, "error: dma prepare for ICCMAX stream failed\n");
return PTR_ERR(iccmax_stream);
@@ -379,7 +389,8 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
* Perform iccmax stream cleanup. This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = hda_cl_cleanup(sdev->dev, &dmab_bdl, iccmax_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->iccmax_dmab,
+ persistent_cl_buffer, iccmax_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: ICCMAX stream cleanup failed\n");
@@ -394,7 +405,7 @@ int hda_dsp_cl_boot_firmware_iccmax(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, SND_SOC_SOF_INTEL_CNL);
+EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware_iccmax, "SND_SOC_SOF_INTEL_CNL");
static int hda_dsp_boot_imr(struct snd_sof_dev *sdev)
{
@@ -421,7 +432,6 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
const struct sof_intel_dsp_desc *chip_info;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
- struct snd_dma_buffer dmab;
int ret, ret1, i;
if (hda->imrboot_supported && !sdev->first_boot && !hda->skip_imr_boot) {
@@ -445,23 +455,31 @@ int hda_dsp_cl_boot_firmware(struct snd_sof_dev *sdev)
return -EINVAL;
}
- stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
- stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
-
/* init for booting wait */
init_waitqueue_head(&sdev->boot_wait);
/* prepare DMA for code loader stream */
+ stripped_firmware.size = sdev->basefw.fw->size - sdev->basefw.payload_offset;
hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
- &dmab, SNDRV_PCM_STREAM_PLAYBACK, false);
+ &hda->cl_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "error: dma prepare for fw loading failed\n");
return PTR_ERR(hext_stream);
}
- memcpy(dmab.area, stripped_firmware.data,
- stripped_firmware.size);
+ /*
+ * Copy the payload to the DMA buffer if it is temporary or if the
+ * buffer is persistent but it does not have the basefw payload either
+ * because this is the first boot and the buffer needs to be initialized,
+ * or a library got loaded and it replaced the basefw.
+ */
+ if (!persistent_cl_buffer || !hda->cl_dmab_contains_basefw) {
+ stripped_firmware.data = sdev->basefw.fw->data + sdev->basefw.payload_offset;
+ memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
+ hda->cl_dmab_contains_basefw = true;
+ }
/* try ROM init a few times before giving up */
for (i = 0; i < HDA_FW_BOOT_ATTEMPTS; i++) {
@@ -527,7 +545,8 @@ cleanup:
* This should be done even if firmware loading fails.
* If the cleanup also fails, we return the initial error
*/
- ret1 = hda_cl_cleanup(sdev->dev, &dmab, hext_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab,
+ persistent_cl_buffer, hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "error: Code loader DSP cleanup failed\n");
@@ -548,7 +567,7 @@ cleanup:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_cl_boot_firmware, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload)
@@ -558,27 +577,41 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
struct sof_ipc4_msg msg = {};
- struct snd_dma_buffer dmab;
int ret, ret1;
- /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */
- if (reload && hda->booted_from_imr && ipc4_data->fw_context_save)
+ /*
+ * if IMR booting is enabled and libraries have been restored during fw
+ * boot, skip the loading
+ */
+ if (reload && hda->booted_from_imr && ipc4_data->libraries_restored)
return 0;
/* the fw_lib has been verified during loading, we can trust the validity here */
stripped_firmware.data = fw_lib->sof_fw.fw->data + fw_lib->sof_fw.payload_offset;
stripped_firmware.size = fw_lib->sof_fw.fw->size - fw_lib->sof_fw.payload_offset;
+ /*
+ * force re-allocation of the cl_dmab if the preserved DMA buffer is
+ * smaller than what is needed for the library
+ */
+ if (persistent_cl_buffer && stripped_firmware.size > hda->cl_dmab.bytes) {
+ snd_dma_free_pages(&hda->cl_dmab);
+ hda->cl_dmab.area = NULL;
+ hda->cl_dmab.bytes = 0;
+ }
+
/* prepare DMA for code loader stream */
hext_stream = hda_cl_prepare(sdev->dev, HDA_CL_STREAM_FORMAT,
stripped_firmware.size,
- &dmab, SNDRV_PCM_STREAM_PLAYBACK, false);
+ &hda->cl_dmab, persistent_cl_buffer,
+ SNDRV_PCM_STREAM_PLAYBACK, false);
if (IS_ERR(hext_stream)) {
dev_err(sdev->dev, "%s: DMA prepare failed\n", __func__);
return PTR_ERR(hext_stream);
}
- memcpy(dmab.area, stripped_firmware.data, stripped_firmware.size);
+ memcpy(hda->cl_dmab.area, stripped_firmware.data, stripped_firmware.size);
+ hda->cl_dmab_contains_basefw = false;
/*
* 1st stage: SOF_IPC4_GLB_LOAD_LIBRARY_PREPARE
@@ -641,7 +674,8 @@ 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, &dmab, hext_stream);
+ ret1 = hda_cl_cleanup(sdev->dev, &hda->cl_dmab, persistent_cl_buffer,
+ hext_stream);
if (ret1 < 0) {
dev_err(sdev->dev, "%s: Code loader DSP cleanup failed\n", __func__);
@@ -652,7 +686,7 @@ cleanup:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ipc4_load_library, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
const struct sof_ext_man_elem_header *hdr)
@@ -691,4 +725,4 @@ int hda_dsp_ext_man_get_cavs_config_data(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_ext_man_get_cavs_config_data, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c
index 9a3559c78b62..ce561fe52bd5 100644
--- a/sound/soc/sof/intel/hda-mlink.c
+++ b/sound/soc/sof/intel/hda-mlink.c
@@ -16,6 +16,7 @@
#include <linux/bitfield.h>
#include <linux/module.h>
+#include <linux/string_choices.h>
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK)
@@ -42,6 +43,7 @@
* @shim_offset: offset to SHIM register base
* @ip_offset: offset to IP register base
* @shim_vs_offset: offset to vendor-specific (VS) SHIM base
+ * @mic_privacy_mask: bitmask of sublinks where mic privacy is applied
*/
struct hdac_ext2_link {
struct hdac_ext_link hext_link;
@@ -65,6 +67,8 @@ struct hdac_ext2_link {
u32 shim_offset;
u32 ip_offset;
u32 shim_vs_offset;
+
+ unsigned long mic_privacy_mask;
};
#define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link)
@@ -90,6 +94,13 @@ struct hdac_ext2_link {
#define AZX_REG_INTEL_UAOL_IP_OFFSET 0x100
#define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET 0xC00
+/* Microphone privacy */
+#define AZX_REG_INTEL_VS_SHIM_PVCCS 0x10
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE BIT(0)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG BIT(8)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS BIT(9)
+#define AZX_REG_INTEL_VS_SHIM_PVCCS_FMDIS BIT(10)
+
/* HDAML section - this part follows sequences in the hardware specification,
* including naming conventions and the use of the hdaml_ prefix.
* The code is intentionally minimal with limited dependencies on frameworks or
@@ -434,7 +445,7 @@ int hda_bus_ml_init(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_init, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_init, "SND_SOC_SOF_HDA_MLINK");
void hda_bus_ml_free(struct hdac_bus *bus)
{
@@ -452,7 +463,7 @@ void hda_bus_ml_free(struct hdac_bus *bus)
kfree(h2link);
}
}
-EXPORT_SYMBOL_NS(hda_bus_ml_free, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_free, "SND_SOC_SOF_HDA_MLINK");
static struct hdac_ext2_link *
find_ext2_link(struct hdac_bus *bus, bool alt, int elid)
@@ -479,7 +490,25 @@ int hdac_bus_eml_get_count(struct hdac_bus *bus, bool alt, int elid)
return h2link->slcount;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_count, "SND_SOC_SOF_HDA_MLINK");
+
+void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int elid, bool enable)
+{
+ struct hdac_ext2_link *h2link;
+ struct hdac_ext_link *hlink;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return;
+
+ if (!h2link->intc)
+ return;
+
+ hlink = &h2link->hext_link;
+
+ hdaml_link_enable_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL, enable);
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
@@ -501,7 +530,7 @@ void hdac_bus_eml_enable_interrupt(struct hdac_bus *bus, bool alt, int elid, boo
mutex_unlock(&h2link->eml_lock);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_enable_interrupt, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid)
{
@@ -519,7 +548,7 @@ bool hdac_bus_eml_check_interrupt(struct hdac_bus *bus, bool alt, int elid)
return hdaml_link_check_interrupt(hlink->ml_addr + AZX_REG_ML_LCTL);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_check_interrupt, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid, u32 syncprd)
{
@@ -539,13 +568,13 @@ int hdac_bus_eml_set_syncprd_unlocked(struct hdac_bus *bus, bool alt, int elid,
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_set_syncprd_unlocked(struct hdac_bus *bus, u32 syncprd)
{
return hdac_bus_eml_set_syncprd_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, syncprd);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_syncprd_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -563,13 +592,13 @@ int hdac_bus_eml_wait_syncpu_unlocked(struct hdac_bus *bus, bool alt, int elid)
return hdaml_link_wait_syncpu(hlink->ml_addr + AZX_REG_ML_LSYNC);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_wait_syncpu_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_wait_syncpu_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_wait_syncpu_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
@@ -587,13 +616,13 @@ void hdac_bus_eml_sync_arm_unlocked(struct hdac_bus *bus, bool alt, int elid, in
hdaml_link_sync_arm(hlink->ml_addr + AZX_REG_ML_LSYNC, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK");
void hdac_bus_eml_sdw_sync_arm_unlocked(struct hdac_bus *bus, int sublink)
{
hdac_bus_eml_sync_arm_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_arm_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -613,13 +642,13 @@ int hdac_bus_eml_sync_go_unlocked(struct hdac_bus *bus, bool alt, int elid)
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_sync_go_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_sync_go_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_sync_go_unlocked, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int elid)
{
@@ -642,13 +671,13 @@ bool hdac_bus_eml_check_cmdsync_unlocked(struct hdac_bus *bus, bool alt, int eli
return hdaml_link_check_cmdsync(hlink->ml_addr + AZX_REG_ML_LSYNC,
cmdsync_mask);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK");
bool hdac_bus_eml_sdw_check_cmdsync_unlocked(struct hdac_bus *bus)
{
return hdac_bus_eml_check_cmdsync_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_check_cmdsync_unlocked, "SND_SOC_SOF_HDA_MLINK");
static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
bool eml_lock)
@@ -678,6 +707,20 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
}
ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
+ if ((h2link->mic_privacy_mask & BIT(sublink)) && !ret) {
+ u16 __iomem *pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ sublink * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+ u16 val = readw(pvccs);
+
+ writew(val | AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+
+ if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS)
+ dev_dbg(bus->dev,
+ "sublink %d (%d:%d): Mic privacy is enabled\n",
+ sublink, alt, elid);
+ }
skip_init:
if (eml_lock)
@@ -690,13 +733,13 @@ int hdac_bus_eml_power_up(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, true);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_up, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_power_up_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_up_base(bus, alt, elid, sublink, false);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK");
static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid, int sublink,
bool eml_lock)
@@ -724,6 +767,16 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
if (--h2link->sublink_ref_count[sublink] > 0)
goto skip_shutdown;
}
+
+ if (h2link->mic_privacy_mask & BIT(sublink)) {
+ u16 __iomem *pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ sublink * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ writew(readw(pvccs) & ~AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
+ }
+
ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
skip_shutdown:
@@ -737,25 +790,25 @@ int hdac_bus_eml_power_down(struct hdac_bus *bus, bool alt, int elid, int sublin
{
return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, true);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_down, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_power_down_unlocked(struct hdac_bus *bus, bool alt, int elid, int sublink)
{
return hdac_bus_eml_power_down_base(bus, alt, elid, sublink, false);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_power_up_unlocked(struct hdac_bus *bus, int sublink)
{
return hdac_bus_eml_power_up_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_up_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_power_down_unlocked(struct hdac_bus *bus, int sublink)
{
return hdac_bus_eml_power_down_unlocked(bus, true, AZX_REG_ML_LEPTR_ID_SDW, sublink);
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_power_down_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16 *lsdiid)
{
@@ -771,7 +824,7 @@ int hdac_bus_eml_sdw_get_lsdiid_unlocked(struct hdac_bus *bus, int sublink, u16
*lsdiid = hdaml_link_get_lsdiid(hlink->ml_addr + AZX_REG_ML_LSDIID_OFFSET(sublink));
return 0;
-} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, SND_SOC_SOF_HDA_MLINK);
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_lsdiid_unlocked, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
{
@@ -791,7 +844,7 @@ int hdac_bus_eml_sdw_set_lsdiid(struct hdac_bus *bus, int sublink, int dev_num)
mutex_unlock(&h2link->eml_lock);
return 0;
-} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, SND_SOC_SOF_HDA_MLINK);
+} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_set_lsdiid, "SND_SOC_SOF_HDA_MLINK");
/*
* the 'y' parameter comes from the PCMSyCM hardware register naming. 'y' refers to the
@@ -835,7 +888,7 @@ int hdac_bus_eml_sdw_map_stream_ch(struct hdac_bus *bus, int sublink, int y,
sublink, channel_mask, stream_id, dir, val);
return 0;
-} EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_map_stream_ch, SND_SOC_SOF_HDA_MLINK);
+} 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)
{
@@ -848,7 +901,7 @@ void hda_bus_ml_put_all(struct hdac_bus *bus)
snd_hdac_ext_bus_link_put(bus, hlink);
}
}
-EXPORT_SYMBOL_NS(hda_bus_ml_put_all, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_put_all, "SND_SOC_SOF_HDA_MLINK");
void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
{
@@ -858,7 +911,7 @@ void hda_bus_ml_reset_losidv(struct hdac_bus *bus)
list_for_each_entry(hlink, &bus->hlink_list, list)
writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV);
}
-EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_reset_losidv, "SND_SOC_SOF_HDA_MLINK");
int hda_bus_ml_resume(struct hdac_bus *bus)
{
@@ -877,7 +930,7 @@ int hda_bus_ml_resume(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_resume, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_resume, "SND_SOC_SOF_HDA_MLINK");
int hda_bus_ml_suspend(struct hdac_bus *bus)
{
@@ -895,7 +948,7 @@ int hda_bus_ml_suspend(struct hdac_bus *bus)
}
return 0;
}
-EXPORT_SYMBOL_NS(hda_bus_ml_suspend, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hda_bus_ml_suspend, "SND_SOC_SOF_HDA_MLINK");
struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid)
{
@@ -907,7 +960,7 @@ struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid)
return &h2link->eml_lock;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_mutex, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus)
{
@@ -919,7 +972,7 @@ struct hdac_ext_link *hdac_bus_eml_ssp_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_ssp_get_hlink, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
{
@@ -931,7 +984,7 @@ struct hdac_ext_link *hdac_bus_eml_dmic_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_dmic_get_hlink, "SND_SOC_SOF_HDA_MLINK");
struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
{
@@ -943,7 +996,7 @@ struct hdac_ext_link *hdac_bus_eml_sdw_get_hlink(struct hdac_bus *bus)
return &h2link->hext_link;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_sdw_get_hlink, "SND_SOC_SOF_HDA_MLINK");
int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable)
{
@@ -967,7 +1020,99 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e
return 0;
}
-EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, SND_SOC_SOF_HDA_MLINK);
+EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK");
+
+void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
+ unsigned long mask)
+{
+ struct hdac_ext2_link *h2link;
+
+ if (!mask)
+ return;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return;
+
+ if (__fls(mask) > h2link->slcount) {
+ dev_warn(bus->dev,
+ "%s: invalid sublink mask for %d:%d, slcount %d: %#lx\n",
+ __func__, alt, elid, h2link->slcount, mask);
+ return;
+ }
+
+ dev_dbg(bus->dev, "sublink mask for %d:%d, slcount %d: %#lx\n", alt,
+ elid, h2link->slcount, mask);
+
+ h2link->mic_privacy_mask = mask;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_set_mic_privacy_mask, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
+{
+ struct hdac_ext2_link *h2link;
+ bool changed = false;
+ u16 __iomem *pvccs;
+ int i;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return false;
+
+ /* The change in privacy state needs to be acked for each link */
+ for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+ u16 val;
+
+ if (h2link->sublink_ref_count[i] == 0)
+ continue;
+
+ pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ i * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ val = readw(pvccs);
+ if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG) {
+ writew(val, pvccs);
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_is_mic_privacy_changed, "SND_SOC_SOF_HDA_MLINK");
+
+bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
+{
+ struct hdac_ext2_link *h2link;
+ u16 __iomem *pvccs;
+ bool state;
+ int i;
+
+ h2link = find_ext2_link(bus, alt, elid);
+ if (!h2link)
+ return false;
+
+ for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
+ if (h2link->sublink_ref_count[i] == 0)
+ continue;
+
+ /* Return the privacy state from the first active link */
+ pvccs = h2link->base_ptr +
+ h2link->shim_vs_offset +
+ i * h2link->instance_offset +
+ AZX_REG_INTEL_VS_SHIM_PVCCS;
+
+ state = readw(pvccs) & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS;
+ dev_dbg(bus->dev, "alt: %d, elid: %d: Mic privacy is %s\n", alt,
+ elid, str_enabled_disabled(state));
+
+ return state;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_NS(hdac_bus_eml_get_mic_privacy_state, "SND_SOC_SOF_HDA_MLINK");
#endif
diff --git a/sound/soc/sof/intel/hda-pcm.c b/sound/soc/sof/intel/hda-pcm.c
index f6e24edd7adb..da6c1e7263cd 100644
--- a/sound/soc/sof/intel/hda-pcm.c
+++ b/sound/soc/sof/intel/hda-pcm.c
@@ -29,6 +29,8 @@
#define SDnFMT_BITS(x) ((x) << 4)
#define SDnFMT_CHAN(x) ((x) << 0)
+#define HDA_MAX_PERIOD_TIME_HEADROOM 10
+
static bool hda_always_enable_dmi_l1;
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
@@ -37,6 +39,11 @@ static bool hda_disable_rewinds;
module_param_named(disable_rewinds, hda_disable_rewinds, bool, 0444);
MODULE_PARM_DESC(disable_rewinds, "SOF HDA disable rewinds");
+static int hda_force_pause_support = -1;
+module_param_named(force_pause_support, hda_force_pause_support, int, 0444);
+MODULE_PARM_DESC(force_pause_support,
+ "Pause support: -1: Use default, 0: Disable, 1: Enable (default -1)");
+
u32 hda_dsp_get_mult_div(struct snd_sof_dev *sdev, int rate)
{
switch (rate) {
@@ -142,7 +149,7 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");
/* update SPIB register with appl position */
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
@@ -165,7 +172,7 @@ int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substrea
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_ack, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream, int cmd)
@@ -175,7 +182,7 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -207,7 +214,7 @@ found:
trace_sof_intel_hda_dsp_pcm(sdev, hstream, substream, pos);
return pos;
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -240,6 +247,16 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
if (hda_always_enable_dmi_l1 && direction == SNDRV_PCM_STREAM_CAPTURE)
runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
+ /*
+ * Do not advertise the PAUSE support if it is forced to be disabled via
+ * module parameter or if the pause_supported is false for the PCM
+ * device
+ */
+ if (hda_force_pause_support == 0 ||
+ (hda_force_pause_support == -1 &&
+ !spcm->stream[substream->stream].pause_supported))
+ runtime->hw.info &= ~SNDRV_PCM_INFO_PAUSE;
+
if (hda_always_enable_dmi_l1 ||
direction == SNDRV_PCM_STREAM_PLAYBACK ||
spcm->stream[substream->stream].d0i3_compatible)
@@ -276,19 +293,30 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
* amount of data in one initial burst to fill up the host DMA buffer.
* Consequent DMA burst sizes are shorter and their length can vary.
- * To make sure that userspace allocate large enough ALSA buffer we need
- * to place a constraint on the buffer time.
+ * To avoid immediate xrun by the initial burst we need to place
+ * constraint on the period size (via PERIOD_TIME) to cover the size of
+ * the host buffer.
+ * We need to add headroom of max 10ms as the firmware needs time to
+ * settle to the 1ms pacing and initially it can run faster for few
+ * internal periods.
*
* On capture the DMA will transfer 1ms chunks.
- *
- * Exact dsp_max_burst_size_in_ms constraint is racy, so set the
- * constraint to a minimum of 2x dsp_max_burst_size_in_ms.
*/
- if (spcm->stream[direction].dsp_max_burst_size_in_ms)
+ if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
+ unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
+
+ /*
+ * add headroom over the maximum burst size to cover the time
+ * needed for the DMA pace to settle.
+ * Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
+ */
+ period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
+
snd_pcm_hw_constraint_minmax(substream->runtime,
- SNDRV_PCM_HW_PARAM_BUFFER_TIME,
- spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
+ SNDRV_PCM_HW_PARAM_PERIOD_TIME,
+ period_time * USEC_PER_MSEC,
UINT_MAX);
+ }
/* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream;
@@ -302,7 +330,7 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_open, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
@@ -322,4 +350,4 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
substream->runtime->private_data = NULL;
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_pcm_close, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-probes.c b/sound/soc/sof/intel/hda-probes.c
index 3e33101f0521..b06933cebc45 100644
--- a/sound/soc/sof/intel/hda-probes.c
+++ b/sound/soc/sof/intel/hda-probes.c
@@ -112,7 +112,7 @@ static int hda_probes_compr_trigger(struct sof_client_dev *cdev,
static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream,
- struct snd_compr_tstamp *tstamp,
+ struct snd_compr_tstamp64 *tstamp,
struct snd_soc_dai *dai)
{
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
@@ -139,12 +139,12 @@ int hda_probes_register(struct snd_sof_dev *sdev)
return sof_client_dev_register(sdev, "hda-probes", 0, &hda_probes_ops,
sizeof(hda_probes_ops));
}
-EXPORT_SYMBOL_NS(hda_probes_register, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_probes_register, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_probes_unregister(struct snd_sof_dev *sdev)
{
sof_client_dev_unregister(sdev, "hda-probes", 0);
}
-EXPORT_SYMBOL_NS(hda_probes_unregister, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_probes_unregister, "SND_SOC_SOF_INTEL_HDA_COMMON");
-MODULE_IMPORT_NS(SND_SOC_SOF_CLIENT);
+MODULE_IMPORT_NS("SND_SOC_SOF_CLIENT");
diff --git a/sound/soc/sof/intel/hda-sdw-bpt.c b/sound/soc/sof/intel/hda-sdw-bpt.c
new file mode 100644
index 000000000000..ff5abccf0d88
--- /dev/null
+++ b/sound/soc/sof/intel/hda-sdw-bpt.c
@@ -0,0 +1,445 @@
+// 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) 2025 Intel Corporation.
+//
+
+/*
+ * Hardware interface for SoundWire BPT support with HDA DMA
+ */
+
+#include <sound/hdaudio_ext.h>
+#include <sound/hda-mlink.h>
+#include <sound/hda-sdw-bpt.h>
+#include <sound/sof.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ops.h"
+#include "../sof-priv.h"
+#include "../ipc4-priv.h"
+#include "hda.h"
+
+#define BPT_FREQUENCY 192000 /* The max rate defined in rate_bits[] hdac_device.c */
+#define BPT_MULTIPLIER ((BPT_FREQUENCY / 48000) - 1)
+#define BPT_CHAIN_DMA_FIFO_MS 10
+/*
+ * This routine is directly inspired by sof_ipc4_chain_dma_trigger(),
+ * with major simplifications since there are no pipelines defined
+ * and no dependency on ALSA hw_params
+ */
+static int chain_dma_trigger(struct snd_sof_dev *sdev, unsigned int stream_tag,
+ int direction, int state)
+{
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ bool allocate, enable, set_fifo_size;
+ struct sof_ipc4_msg msg = {{ 0 }};
+ int dma_id;
+
+ if (sdev->pdata->ipc_type != SOF_IPC_TYPE_4)
+ return -EOPNOTSUPP;
+
+ switch (state) {
+ case SOF_IPC4_PIPE_RUNNING: /* Allocate and start the chain */
+ allocate = true;
+ enable = true;
+ set_fifo_size = true;
+ break;
+ case SOF_IPC4_PIPE_PAUSED: /* Stop the chain */
+ allocate = true;
+ enable = false;
+ set_fifo_size = false;
+ break;
+ case SOF_IPC4_PIPE_RESET: /* Deallocate chain resources and remove the chain */
+ allocate = false;
+ enable = false;
+ set_fifo_size = false;
+ break;
+ default:
+ dev_err(sdev->dev, "Unexpected state %d", state);
+ return -EINVAL;
+ }
+
+ msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_CHAIN_DMA);
+ msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+ msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+
+ /* for BPT/BRA we can use the same stream tag for host and link */
+ dma_id = stream_tag - 1;
+ if (direction == SNDRV_PCM_STREAM_CAPTURE)
+ dma_id += ipc4_data->num_playback_streams;
+
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_HOST_ID(dma_id);
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_LINK_ID(dma_id);
+
+ /* For BPT/BRA we use 32 bits so SCS is not set */
+
+ /* CHAIN DMA needs at least 2ms */
+ if (set_fifo_size)
+ msg.extension |= SOF_IPC4_GLB_EXT_CHAIN_DMA_FIFO_SIZE(BPT_FREQUENCY / 1000 *
+ BPT_CHAIN_DMA_FIFO_MS *
+ sizeof(u32));
+
+ if (allocate)
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ALLOCATE_MASK;
+
+ if (enable)
+ msg.primary |= SOF_IPC4_GLB_CHAIN_DMA_ENABLE_MASK;
+
+ return sof_ipc_tx_message_no_reply(sdev->ipc, &msg, 0);
+}
+
+static int hda_sdw_bpt_dma_prepare(struct device *dev, struct hdac_ext_stream **sdw_bpt_stream,
+ struct snd_dma_buffer *dmab_bdl, u32 bpt_num_bytes,
+ unsigned int num_channels, int direction)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct hdac_ext_stream *bpt_stream;
+ unsigned int format = HDA_CL_STREAM_FORMAT;
+
+ /*
+ * the baseline format needs to be adjusted to
+ * bandwidth requirements
+ */
+ format |= (num_channels - 1);
+ format |= BPT_MULTIPLIER << AC_FMT_MULT_SHIFT;
+
+ dev_dbg(dev, "direction %d format_val %#x\n", direction, format);
+
+ bpt_stream = hda_cl_prepare(dev, format, bpt_num_bytes, dmab_bdl, false, direction, false);
+ if (IS_ERR(bpt_stream)) {
+ dev_err(sdev->dev, "%s: SDW BPT DMA prepare failed: dir %d\n",
+ __func__, direction);
+ return PTR_ERR(bpt_stream);
+ }
+ *sdw_bpt_stream = bpt_stream;
+
+ if (!sdev->dspless_mode_selected) {
+ struct hdac_stream *hstream;
+ u32 mask;
+
+ /* decouple host and link DMA if the DSP is used */
+ hstream = &bpt_stream->hstream;
+ mask = BIT(hstream->index);
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, mask);
+
+ snd_hdac_ext_stream_reset(bpt_stream);
+
+ snd_hdac_ext_stream_setup(bpt_stream, format);
+ }
+
+ if (hdac_stream(bpt_stream)->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hdac_ext_link *hlink;
+ int stream_tag;
+
+ stream_tag = hdac_stream(bpt_stream)->stream_tag;
+ hlink = hdac_bus_eml_sdw_get_hlink(bus);
+
+ snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
+ }
+ return 0;
+}
+
+static int hda_sdw_bpt_dma_deprepare(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream,
+ struct snd_dma_buffer *dmab_bdl)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ struct hdac_stream *hstream;
+ u32 mask;
+ int ret;
+
+ ret = hda_cl_cleanup(sdev->dev, dmab_bdl, false, sdw_bpt_stream);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: SDW BPT DMA cleanup failed\n",
+ __func__);
+ return ret;
+ }
+
+ if (hdac_stream(sdw_bpt_stream)->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ struct hdac_bus *bus = sof_to_bus(sdev);
+ struct hdac_ext_link *hlink;
+ int stream_tag;
+
+ stream_tag = hdac_stream(sdw_bpt_stream)->stream_tag;
+ hlink = hdac_bus_eml_sdw_get_hlink(bus);
+
+ snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
+ }
+
+ if (!sdev->dspless_mode_selected) {
+ /* Release CHAIN_DMA resources */
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_RESET);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: chain_dma_trigger PIPE_RESET failed: %d\n",
+ __func__, ret);
+
+ /* couple host and link DMA */
+ hstream = &sdw_bpt_stream->hstream;
+ mask = BIT(hstream->index);
+
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL, mask, 0);
+ }
+
+ return 0;
+}
+
+static int hda_sdw_bpt_dma_enable(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ int ret;
+
+ ret = hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_START);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: SDW BPT DMA trigger start failed\n", __func__);
+
+ if (!sdev->dspless_mode_selected) {
+ /* the chain DMA needs to be programmed before the DMAs */
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_RUNNING);
+ if (ret < 0) {
+ dev_err(sdev->dev, "%s: chain_dma_trigger failed: %d\n",
+ __func__, ret);
+ hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_STOP);
+ return ret;
+ }
+ snd_hdac_ext_stream_start(sdw_bpt_stream);
+ }
+
+ return ret;
+}
+
+static int hda_sdw_bpt_dma_disable(struct device *dev, struct hdac_ext_stream *sdw_bpt_stream)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ int ret;
+
+ if (!sdev->dspless_mode_selected) {
+ snd_hdac_ext_stream_clear(sdw_bpt_stream);
+
+ ret = chain_dma_trigger(sdev, hdac_stream(sdw_bpt_stream)->stream_tag,
+ hdac_stream(sdw_bpt_stream)->direction,
+ SOF_IPC4_PIPE_PAUSED);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: chain_dma_trigger PIPE_PAUSED failed: %d\n",
+ __func__, ret);
+ }
+
+ ret = hda_cl_trigger(sdev->dev, sdw_bpt_stream, SNDRV_PCM_TRIGGER_STOP);
+ if (ret < 0)
+ dev_err(sdev->dev, "%s: SDW BPT DMA trigger stop failed\n", __func__);
+
+ return ret;
+}
+
+int hda_sdw_bpt_open(struct device *dev, int link_id, struct hdac_ext_stream **bpt_tx_stream,
+ struct snd_dma_buffer *dmab_tx_bdl, u32 bpt_tx_num_bytes,
+ u32 tx_dma_bandwidth, struct hdac_ext_stream **bpt_rx_stream,
+ struct snd_dma_buffer *dmab_rx_bdl, u32 bpt_rx_num_bytes,
+ u32 rx_dma_bandwidth)
+{
+ struct snd_sof_dev *sdev = dev_get_drvdata(dev);
+ unsigned int num_channels_tx;
+ unsigned int num_channels_rx;
+ int ret1;
+ int ret;
+
+ num_channels_tx = DIV_ROUND_UP(tx_dma_bandwidth, BPT_FREQUENCY * 32);
+
+ ret = hda_sdw_bpt_dma_prepare(dev, bpt_tx_stream, dmab_tx_bdl, bpt_tx_num_bytes,
+ num_channels_tx, SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_prepare failed for TX: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ num_channels_rx = DIV_ROUND_UP(rx_dma_bandwidth, BPT_FREQUENCY * 32);
+
+ ret = hda_sdw_bpt_dma_prepare(dev, bpt_rx_stream, dmab_rx_bdl, bpt_rx_num_bytes,
+ num_channels_rx, SNDRV_PCM_STREAM_CAPTURE);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_prepare failed for RX: %d\n",
+ __func__, ret);
+
+ ret1 = hda_sdw_bpt_dma_deprepare(dev, *bpt_tx_stream, dmab_tx_bdl);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_dma_deprepare failed for TX: %d\n",
+ __func__, ret1);
+ return ret;
+ }
+
+ /* we need to map the channels in PCMSyCM registers */
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id,
+ 0, /* cpu_dai->id -> PDI0 */
+ GENMASK(num_channels_tx - 1, 0),
+ hdac_stream(*bpt_tx_stream)->stream_tag,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret < 0) {
+ dev_err(dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed for TX: %d\n",
+ __func__, ret);
+ goto close;
+ }
+
+ ret = hdac_bus_eml_sdw_map_stream_ch(sof_to_bus(sdev), link_id,
+ 1, /* cpu_dai->id -> PDI1 */
+ GENMASK(num_channels_rx - 1, 0),
+ hdac_stream(*bpt_rx_stream)->stream_tag,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (!ret)
+ return 0;
+
+ dev_err(dev, "%s: hdac_bus_eml_sdw_map_stream_ch failed for RX: %d\n",
+ __func__, ret);
+
+close:
+ ret1 = hda_sdw_bpt_close(dev, *bpt_tx_stream, dmab_tx_bdl, *bpt_rx_stream, dmab_rx_bdl);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_close failed: %d\n",
+ __func__, ret1);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_open, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+int hda_sdw_bpt_send_async(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct hdac_ext_stream *bpt_rx_stream)
+{
+ int ret1;
+ int ret;
+
+ ret = hda_sdw_bpt_dma_enable(dev, bpt_tx_stream);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_enable failed for TX: %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ ret = hda_sdw_bpt_dma_enable(dev, bpt_rx_stream);
+ if (ret < 0) {
+ dev_err(dev, "%s: hda_sdw_bpt_dma_enable failed for RX: %d\n",
+ __func__, ret);
+
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_tx_stream);
+ if (ret1 < 0)
+ dev_err(dev, "%s: hda_sdw_bpt_dma_disable failed for TX: %d\n",
+ __func__, ret1);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_send_async, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+/*
+ * 3s is several orders of magnitude larger than what is needed for a
+ * typical firmware download.
+ */
+#define HDA_BPT_IOC_TIMEOUT_MS 3000
+
+int hda_sdw_bpt_wait(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct hdac_ext_stream *bpt_rx_stream)
+{
+ struct sof_intel_hda_stream *hda_tx_stream;
+ struct sof_intel_hda_stream *hda_rx_stream;
+ snd_pcm_uframes_t tx_position;
+ snd_pcm_uframes_t rx_position;
+ unsigned long time_tx_left;
+ unsigned long time_rx_left;
+ int ret = 0;
+ int ret1;
+ int i;
+
+ hda_tx_stream = container_of(bpt_tx_stream, struct sof_intel_hda_stream, hext_stream);
+ hda_rx_stream = container_of(bpt_rx_stream, struct sof_intel_hda_stream, hext_stream);
+
+ time_tx_left = wait_for_completion_timeout(&hda_tx_stream->ioc,
+ msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS));
+ if (!time_tx_left) {
+ tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
+ SNDRV_PCM_STREAM_PLAYBACK, false);
+ dev_err(dev, "%s: SDW BPT TX DMA did not complete: %ld\n",
+ __func__, tx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* Make sure the DMA is flushed */
+ i = 0;
+ do {
+ tx_position = hda_dsp_stream_get_position(hdac_stream(bpt_tx_stream),
+ SNDRV_PCM_STREAM_PLAYBACK, false);
+ usleep_range(1000, 1010);
+ i++;
+ } while (tx_position && i < HDA_BPT_IOC_TIMEOUT_MS);
+ if (tx_position) {
+ dev_err(dev, "%s: SDW BPT TX DMA position %ld was not cleared\n",
+ __func__, tx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* the wait should be minimal here */
+ time_rx_left = wait_for_completion_timeout(&hda_rx_stream->ioc,
+ msecs_to_jiffies(HDA_BPT_IOC_TIMEOUT_MS));
+ if (!time_rx_left) {
+ rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
+ SNDRV_PCM_STREAM_CAPTURE, false);
+ dev_err(dev, "%s: SDW BPT RX DMA did not complete: %ld\n",
+ __func__, rx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+ /* Make sure the DMA is flushed */
+ i = 0;
+ do {
+ rx_position = hda_dsp_stream_get_position(hdac_stream(bpt_rx_stream),
+ SNDRV_PCM_STREAM_CAPTURE, false);
+ usleep_range(1000, 1010);
+ i++;
+ } while (rx_position && i < HDA_BPT_IOC_TIMEOUT_MS);
+ if (rx_position) {
+ dev_err(dev, "%s: SDW BPT RX DMA position %ld was not cleared\n",
+ __func__, rx_position);
+ ret = -ETIMEDOUT;
+ goto dma_disable;
+ }
+
+dma_disable:
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_rx_stream);
+ if (!ret)
+ ret = ret1;
+
+ ret1 = hda_sdw_bpt_dma_disable(dev, bpt_tx_stream);
+ if (!ret)
+ ret = ret1;
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_wait, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+int hda_sdw_bpt_close(struct device *dev, struct hdac_ext_stream *bpt_tx_stream,
+ struct snd_dma_buffer *dmab_tx_bdl, struct hdac_ext_stream *bpt_rx_stream,
+ struct snd_dma_buffer *dmab_rx_bdl)
+{
+ int ret;
+ int ret1;
+
+ ret = hda_sdw_bpt_dma_deprepare(dev, bpt_rx_stream, dmab_rx_bdl);
+
+ ret1 = hda_sdw_bpt_dma_deprepare(dev, bpt_tx_stream, dmab_tx_bdl);
+ if (!ret)
+ ret = ret1;
+
+ return ret;
+}
+EXPORT_SYMBOL_NS(hda_sdw_bpt_close, "SND_SOC_SOF_INTEL_HDA_SDW_BPT");
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF helpers for HDaudio SoundWire BPT");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/hda-stream.c b/sound/soc/sof/intel/hda-stream.c
index 8213debde497..9c3b3a9aaf83 100644
--- a/sound/soc/sof/intel/hda-stream.c
+++ b/sound/soc/sof/intel/hda-stream.c
@@ -27,7 +27,7 @@
int sof_hda_position_quirk = SOF_HDA_POSITION_QUIRK_USE_DPIB_REGISTERS;
module_param_named(position_quirk, sof_hda_position_quirk, int, 0444);
MODULE_PARM_DESC(position_quirk, "SOF HDaudio position quirk");
-EXPORT_SYMBOL_NS(sof_hda_position_quirk, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_hda_position_quirk, "SND_SOC_SOF_INTEL_HDA_COMMON");
#define HDA_LTRP_GB_VALUE_US 95
@@ -119,13 +119,39 @@ int hda_dsp_stream_setup_bdl(struct snd_sof_dev *sdev,
int remain, ioc;
period_bytes = hstream->period_bytes;
- dev_dbg(sdev->dev, "period_bytes:0x%x\n", period_bytes);
- if (!period_bytes)
+ dev_dbg(sdev->dev, "period_bytes: %#x, bufsize: %#x\n", period_bytes,
+ hstream->bufsize);
+
+ if (!period_bytes) {
+ unsigned int chunk_size;
+
+ chunk_size = snd_sgbuf_get_chunk_size(dmab, 0, hstream->bufsize);
+
period_bytes = hstream->bufsize;
+ /*
+ * HDA spec demands that the LVI value must be at least one
+ * before the DMA operation can begin. This means that there
+ * must be at least two BDLE present for the transfer.
+ *
+ * If the buffer is not a single continuous area then the
+ * hda_setup_bdle() will create multiple BDLEs for each segment.
+ * If the memory is a single continuous area, force it to be
+ * split into two 'periods', otherwise the transfer will be
+ * split to multiple BDLE for each chunk in hda_setup_bdle()
+ *
+ * Note: period_bytes == 0 can only happen for firmware or
+ * library loading. The data size is 4K aligned, which ensures
+ * that the second chunk's start address will be 128-byte
+ * aligned.
+ */
+ if (chunk_size == hstream->bufsize)
+ period_bytes /= 2;
+ }
+
periods = hstream->bufsize / period_bytes;
- dev_dbg(sdev->dev, "periods:%d\n", periods);
+ dev_dbg(sdev->dev, "periods: %d\n", periods);
remain = hstream->bufsize % period_bytes;
if (remain)
@@ -216,9 +242,7 @@ hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags)
/* stream found ? */
if (!hext_stream) {
- dev_err(sdev->dev, "error: no free %s streams\n",
- direction == SNDRV_PCM_STREAM_PLAYBACK ?
- "playback" : "capture");
+ dev_err(sdev->dev, "error: no free %s streams\n", snd_pcm_direction_name(direction));
return hext_stream;
}
@@ -714,7 +738,7 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
@@ -737,7 +761,7 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_check_stream_irq, "SND_SOC_SOF_INTEL_HDA_COMMON");
static void
hda_dsp_compr_bytes_transferred(struct hdac_stream *hstream, int direction)
@@ -834,7 +858,7 @@ irqreturn_t hda_dsp_stream_threaded_handler(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_stream_threaded_handler, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_stream_init(struct snd_sof_dev *sdev)
{
@@ -866,7 +890,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
if (num_capture >= SOF_HDA_CAPTURE_STREAMS) {
dev_err(sdev->dev, "error: too many capture streams %d\n",
- num_playback);
+ num_capture);
return -EINVAL;
}
@@ -972,7 +996,7 @@ int hda_dsp_stream_init(struct snd_sof_dev *sdev)
return 0;
}
-EXPORT_SYMBOL_NS(hda_dsp_stream_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_stream_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
void hda_dsp_stream_free(struct snd_sof_dev *sdev)
{
@@ -1002,7 +1026,7 @@ void hda_dsp_stream_free(struct snd_sof_dev *sdev)
devm_kfree(sdev->dev, hda_stream);
}
}
-EXPORT_SYMBOL_NS(hda_dsp_stream_free, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_stream_free, "SND_SOC_SOF_INTEL_HDA_COMMON");
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
int direction, bool can_sleep)
@@ -1089,7 +1113,7 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
return pos;
}
-EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, "SND_SOC_SOF_INTEL_HDA_COMMON");
#define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l))
@@ -1105,11 +1129,36 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
- struct hdac_stream *hstream = substream->runtime->private_data;
- struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
+ struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
+ struct snd_soc_pcm_runtime *be_rtd = NULL;
+ struct hdac_ext_stream *hext_stream;
+ struct snd_soc_dai *cpu_dai;
+ struct snd_soc_dpcm *dpcm;
u32 llp_l, llp_u;
/*
+ * The LLP needs to be read from the Link DMA used for this FE as it is
+ * allowed to use any combination of Link and Host channels
+ */
+ for_each_dpcm_be(rtd, substream->stream, dpcm) {
+ if (dpcm->fe != rtd)
+ continue;
+
+ be_rtd = dpcm->be;
+ }
+
+ if (!be_rtd)
+ return 0;
+
+ cpu_dai = snd_soc_rtd_to_cpu(be_rtd, 0);
+ if (!cpu_dai)
+ return 0;
+
+ hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
+ if (!hext_stream)
+ return 0;
+
+ /*
* The pplc_addr have been calculated during probe in
* hda_dsp_stream_init():
* pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
@@ -1129,7 +1178,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
return merge_u64(llp_u, llp_l);
}
-EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON");
/**
* hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream
@@ -1161,4 +1210,4 @@ u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
return ((u64)ldp_u << 32) | ldp_l;
}
-EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_get_stream_ldp, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda-trace.c b/sound/soc/sof/intel/hda-trace.c
index 351eb2eb184b..5da8188ffcfe 100644
--- a/sound/soc/sof/intel/hda-trace.c
+++ b/sound/soc/sof/intel/hda-trace.c
@@ -68,7 +68,7 @@ int hda_dsp_trace_init(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_trace_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_trace_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_trace_release(struct snd_sof_dev *sdev)
{
@@ -87,7 +87,7 @@ int hda_dsp_trace_release(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "DMA trace stream is not opened!\n");
return -ENODEV;
}
-EXPORT_SYMBOL_NS(hda_dsp_trace_release, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_trace_release, "SND_SOC_SOF_INTEL_HDA_COMMON");
int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd)
{
@@ -95,4 +95,4 @@ int hda_dsp_trace_trigger(struct snd_sof_dev *sdev, int cmd)
return hda_dsp_stream_trigger(sdev, hda->dtrace_stream, cmd);
}
-EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(hda_dsp_trace_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index dead1c19558b..c1518dbee1b7 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -26,6 +26,7 @@
#include <sound/intel-dsp-config.h>
#include <sound/intel-nhlt.h>
#include <sound/soc-acpi-intel-ssp-common.h>
+#include <sound/soc_sdw_utils.h>
#include <sound/sof.h>
#include <sound/sof/xtensa.h>
#include <sound/hda-mlink.h>
@@ -33,6 +34,7 @@
#include "../sof-pci-dev.h"
#include "../ops.h"
#include "../ipc4-topology.h"
+#include "../../intel/common/sof-function-topology-lib.h"
#include "hda.h"
#include <trace/events/sof_intel.h>
@@ -63,6 +65,11 @@ static int sdw_params_stream(struct device *dev,
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(d, params_data->substream->stream);
struct snd_sof_dai_config_data data = { 0 };
+ if (!w) {
+ dev_err(dev, "%s widget not found, check amp link num in the topology\n",
+ d->name);
+ return -EINVAL;
+ }
data.dai_index = (params_data->link_id << 8) | d->id;
data.dai_data = params_data->alh_stream_id;
data.dai_node_id = data.dai_data;
@@ -187,6 +194,9 @@ static int hda_sdw_probe(struct snd_sof_dev *sdev)
res.ext = true;
res.ops = &sdw_ace2x_callback;
+ /* ACE3+ supports microphone privacy */
+ if (chip->hw_ip_version >= SOF_INTEL_ACE_3_0)
+ res.mic_privacy = true;
}
res.irq = sdev->ipc_irq;
res.handle = hdev->info.handle;
@@ -238,7 +248,7 @@ int hda_sdw_startup(struct snd_sof_dev *sdev)
return sdw_intel_startup(hdev->sdw);
}
-EXPORT_SYMBOL_NS(hda_sdw_startup, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_sdw_startup, "SND_SOC_SOF_INTEL_HDA_GENERIC");
static int hda_sdw_exit(struct snd_sof_dev *sdev)
{
@@ -280,7 +290,7 @@ bool hda_common_check_sdw_irq(struct snd_sof_dev *sdev)
out:
return ret;
}
-EXPORT_SYMBOL_NS(hda_common_check_sdw_irq, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_common_check_sdw_irq, "SND_SOC_SOF_INTEL_HDA_GENERIC");
static bool hda_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{
@@ -314,7 +324,7 @@ bool hda_sdw_check_wakeen_irq_common(struct snd_sof_dev *sdev)
return false;
}
-EXPORT_SYMBOL_NS(hda_sdw_check_wakeen_irq_common, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_sdw_check_wakeen_irq_common, "SND_SOC_SOF_INTEL_HDA_GENERIC");
static bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
{
@@ -345,7 +355,28 @@ void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev)
sdw_intel_process_wakeen_event(hdev->sdw);
}
-EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, "SND_SOC_SOF_INTEL_HDA_GENERIC");
+
+static bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->check_mic_privacy_irq)
+ return chip->check_mic_privacy_irq(sdev, true,
+ AZX_REG_ML_LEPTR_ID_SDW);
+
+ return false;
+}
+
+static void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev)
+{
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip && chip->process_mic_privacy)
+ chip->process_mic_privacy(sdev, true, AZX_REG_ML_LEPTR_ID_SDW);
+}
#else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev)
@@ -378,6 +409,13 @@ static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
return false;
}
+static inline bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev)
+{
+ return false;
+}
+
+static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { }
+
#endif /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */
/* pre fw run operations */
@@ -418,7 +456,7 @@ int hda_dsp_post_fw_run(struct snd_sof_dev *sdev)
/* re-enable clock gating and power gating */
return hda_dsp_ctrl_clock_power_gating(sdev, true);
}
-EXPORT_SYMBOL_NS(hda_dsp_post_fw_run, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_dsp_post_fw_run, "SND_SOC_SOF_INTEL_HDA_GENERIC");
/*
* Debug
@@ -444,6 +482,10 @@ 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");
+static int bt_link_mask_override;
+module_param_named(bt_link_mask, bt_link_mask_override, int, 0444);
+MODULE_PARM_DESC(bt_link_mask, "SOF BT offload link mask");
+
static int hda_init(struct snd_sof_dev *sdev)
{
struct hda_bus *hbus;
@@ -511,6 +553,8 @@ static int check_dmic_num(struct snd_sof_dev *sdev)
if (nhlt)
dmic_num = intel_nhlt_get_dmic_geo(sdev->dev, nhlt);
+ dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
+
/* allow for module parameter override */
if (dmic_num_override != -1) {
dev_dbg(sdev->dev,
@@ -527,7 +571,7 @@ static int check_dmic_num(struct snd_sof_dev *sdev)
return dmic_num;
}
-static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
+static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev, u8 device_type)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct nhlt_acpi_table *nhlt;
@@ -538,9 +582,11 @@ static int check_nhlt_ssp_mask(struct snd_sof_dev *sdev)
return ssp_mask;
if (intel_nhlt_has_endpoint_type(nhlt, NHLT_LINK_SSP)) {
- ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, NHLT_DEVICE_I2S);
+ ssp_mask = intel_nhlt_ssp_endpoint_mask(nhlt, device_type);
if (ssp_mask)
- dev_info(sdev->dev, "NHLT_DEVICE_I2S detected, ssp_mask %#x\n", ssp_mask);
+ dev_info(sdev->dev, "NHLT device %s(%d) detected, ssp_mask %#x\n",
+ device_type == NHLT_DEVICE_BT ? "BT" : "I2S",
+ device_type, ssp_mask);
}
return ssp_mask;
@@ -558,82 +604,6 @@ static int check_nhlt_ssp_mclk_mask(struct snd_sof_dev *sdev, int ssp_num)
return intel_nhlt_ssp_mclk_mask(nhlt, ssp_num);
}
-#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC) || IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
-
-static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
- const char *sof_tplg_filename,
- const char *idisp_str,
- const char *dmic_str)
-{
- const char *tplg_filename = NULL;
- char *filename, *tmp;
- const char *split_ext;
-
- filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
- if (!filename)
- return NULL;
-
- /* this assumes a .tplg extension */
- 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);
- kfree(filename);
-
- return tplg_filename;
-}
-
-static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
- const char **tplg_filename,
- const char *idisp_str,
- int *dmic_found,
- bool tplg_fixup)
-{
- const char *dmic_str;
- int dmic_num;
-
- /* first check for DMICs (using NHLT or module parameter) */
- dmic_num = check_dmic_num(sdev);
-
- 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;
- }
-
- if (tplg_fixup) {
- const char *default_tplg_filename = *tplg_filename;
- const char *fixed_tplg_filename;
-
- fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
- idisp_str, dmic_str);
- if (!fixed_tplg_filename)
- return -ENOMEM;
- *tplg_filename = fixed_tplg_filename;
- }
-
- dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
- *dmic_found = dmic_num;
-
- return 0;
-}
-#endif
-
static int hda_init_caps(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
@@ -648,7 +618,7 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
dev_dbg(sdev->dev, "PP capability, will probe DSP later.\n");
/* Init HDA controller after i915 init */
- ret = hda_dsp_ctrl_init_chip(sdev);
+ ret = hda_dsp_ctrl_init_chip(sdev, true);
if (ret < 0) {
dev_err(bus->dev, "error: init chip failed with ret: %d\n",
ret);
@@ -661,6 +631,11 @@ static int hda_init_caps(struct snd_sof_dev *sdev)
if (!(interface_mask & BIT(SOF_DAI_INTEL_ALH)))
goto skip_soundwire;
+ /* Skip SoundWire in nocodec mode */
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto skip_soundwire;
+
/* scan SoundWire capabilities exposed by DSDT */
ret = hda_sdw_acpi_scan(sdev);
if (ret < 0) {
@@ -741,7 +716,13 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context)
if (hda_dsp_check_sdw_irq(sdev)) {
trace_sof_intel_hda_irq(sdev, "sdw");
+
hda_dsp_sdw_thread(irq, hdev->sdw);
+
+ if (hda_dsp_sdw_check_mic_privacy_irq(sdev)) {
+ trace_sof_intel_hda_irq(sdev, "mic privacy");
+ hda_dsp_sdw_process_mic_privacy(sdev);
+ }
}
if (hda_sdw_check_wakeen_irq(sdev)) {
@@ -783,8 +764,8 @@ int hda_dsp_probe_early(struct snd_sof_dev *sdev)
pci->class);
return -ENODEV;
}
- dev_info(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
- pci->class);
+ dev_info_once(sdev->dev, "DSP detected with PCI class/subclass/prog-if 0x%06x\n",
+ pci->class);
}
chip = get_chip_info(sdev->pdata);
@@ -807,7 +788,7 @@ int hda_dsp_probe_early(struct snd_sof_dev *sdev)
err:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_probe_early, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_dsp_probe_early, "SND_SOC_SOF_INTEL_HDA_GENERIC");
int hda_dsp_probe(struct snd_sof_dev *sdev)
{
@@ -934,8 +915,6 @@ skip_dsp_setup:
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);
@@ -964,7 +943,7 @@ hdac_bus_unmap:
return ret;
}
-EXPORT_SYMBOL_NS(hda_dsp_probe, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_dsp_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC");
void hda_dsp_remove(struct snd_sof_dev *sdev)
{
@@ -999,6 +978,10 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
if (sdev->dspless_mode_selected)
goto skip_disable_dsp;
+ /* Cancel the microphone privacy work if mic privacy is active */
+ if (hda->mic_privacy.active)
+ cancel_work_sync(&hda->mic_privacy.work);
+
/* no need to check for error as the DSP will be disabled anyway */
if (chip && chip->power_down_dsp)
chip->power_down_dsp(sdev);
@@ -1006,6 +989,12 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
/* disable DSP */
hda_dsp_ctrl_ppcap_enable(sdev, false);
+ /* Free the persistent DMA buffers used for base firmware download */
+ if (hda->cl_dmab.area)
+ snd_dma_free_pages(&hda->cl_dmab);
+ if (hda->iccmax_dmab.area)
+ snd_dma_free_pages(&hda->iccmax_dmab);
+
skip_disable_dsp:
free_irq(sdev->ipc_irq, sdev);
if (sdev->msi_enabled)
@@ -1018,7 +1007,7 @@ skip_disable_dsp:
if (!sdev->dspless_mode_selected)
iounmap(sdev->bar[HDA_DSP_BAR]);
}
-EXPORT_SYMBOL_NS(hda_dsp_remove, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_dsp_remove, "SND_SOC_SOF_INTEL_HDA_GENERIC");
void hda_dsp_remove_late(struct snd_sof_dev *sdev)
{
@@ -1034,7 +1023,7 @@ int hda_power_down_dsp(struct snd_sof_dev *sdev)
return hda_dsp_core_reset_power_down(sdev, chip->host_managed_cores_mask);
}
-EXPORT_SYMBOL_NS(hda_power_down_dsp, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_power_down_dsp, "SND_SOC_SOF_INTEL_HDA_GENERIC");
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
static void hda_generic_machine_select(struct snd_sof_dev *sdev,
@@ -1045,10 +1034,7 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
struct snd_soc_acpi_mach *hda_mach;
struct snd_sof_pdata *pdata = sdev->pdata;
const char *tplg_filename;
- const char *idisp_str;
- int dmic_num = 0;
int codec_num = 0;
- int ret;
int i;
/* codec detection */
@@ -1071,33 +1057,44 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
* - one external HDAudio codec
*/
if (!*mach && codec_num <= 2) {
- bool tplg_fixup;
+ bool tplg_fixup = false;
- hda_mach = snd_soc_acpi_intel_hda_machines;
+ /*
+ * make a local copy of the match array since we might
+ * be modifying it
+ */
+ hda_mach = devm_kmemdup_array(sdev->dev,
+ snd_soc_acpi_intel_hda_machines,
+ 2, /* we have one entry + sentinel in the array */
+ sizeof(snd_soc_acpi_intel_hda_machines[0]),
+ GFP_KERNEL);
+ if (!hda_mach) {
+ dev_err(bus->dev,
+ "%s: failed to duplicate the HDA match table\n",
+ __func__);
+ return;
+ }
dev_info(bus->dev, "using HDA machine driver %s now\n",
hda_mach->drv_name);
- if (codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask))
- idisp_str = "-idisp";
- else
- idisp_str = "";
-
- /* topology: use the info from hda_machines */
- if (pdata->tplg_filename) {
- tplg_fixup = false;
- tplg_filename = pdata->tplg_filename;
- } else {
+ /*
+ * topology: use the info from hda_machines since tplg file name
+ * is not overwritten
+ */
+ if (!pdata->tplg_filename)
tplg_fixup = true;
- tplg_filename = hda_mach->sof_tplg_filename;
- }
- ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
- tplg_fixup);
- if (ret < 0)
- return;
- hda_mach->mach_params.dmic_num = dmic_num;
- pdata->tplg_filename = tplg_filename;
+ if (tplg_fixup &&
+ codec_num == 1 && HDA_IDISP_CODEC(bus->codec_mask)) {
+ tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "%s-idisp",
+ hda_mach->sof_tplg_filename);
+ if (!tplg_filename)
+ return;
+
+ hda_mach->sof_tplg_filename = tplg_filename;
+ }
if (codec_num == 2 ||
(codec_num == 1 && !HDA_IDISP_CODEC(bus->codec_mask))) {
@@ -1125,7 +1122,6 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
if (*mach) {
mach_params = &(*mach)->mach_params;
mach_params->codec_mask = bus->codec_mask;
- mach_params->common_hdmi_codec_drv = true;
}
}
#else
@@ -1137,14 +1133,174 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
#if IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE)
+static bool is_endpoint_present(struct sdw_slave *sdw_device,
+ struct asoc_sdw_codec_info *dai_info, int dai_type)
+{
+ int i;
+
+ for (i = 0; i < sdw_device->sdca_data.num_functions; i++) {
+ if (dai_type == dai_info->dais[i].dai_type)
+ return true;
+ }
+ dev_dbg(&sdw_device->dev, "Endpoint DAI type %d not found\n", dai_type);
+ return false;
+}
+
+static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev,
+ struct sdw_slave *sdw_device,
+ struct snd_soc_acpi_link_adr *link,
+ int *amp_index)
+{
+ struct snd_soc_acpi_adr_device *adr_dev;
+ const char *name_prefix = "";
+ int index = link->num_adr;
+ bool is_amp = true; /* Set it to false if the codec wiah any NON-AMP DAI type */
+ int ep_index = 0;
+ int i, j;
+
+ link->mask = BIT(sdw_device->bus->link_id);
+ /* index is 0 based, we need allocate index + 1 for the array size */
+ if (!index)
+ adr_dev = devm_kzalloc(dev, sizeof(*adr_dev), GFP_KERNEL);
+ else
+ adr_dev = devm_krealloc(dev, (struct snd_soc_acpi_adr_device *)link->adr_d,
+ (index + 1) * sizeof(*adr_dev), GFP_KERNEL);
+
+ if (!adr_dev)
+ return NULL;
+
+ for (i = 0; i < asoc_sdw_get_codec_info_list_count(); i++) {
+ struct snd_soc_acpi_endpoint *endpoints;
+ int amp_group_id = 1;
+
+ if (sdw_device->id.part_id != codec_info_list[i].part_id)
+ continue;
+
+ endpoints = devm_kcalloc(dev, codec_info_list[i].dai_num,
+ sizeof(struct snd_soc_acpi_endpoint), GFP_KERNEL);
+ if (!endpoints)
+ return NULL;
+
+ name_prefix = codec_info_list[i].name_prefix;
+ /*
+ * This should not happen, but add a paranoid check to avoid NULL pointer
+ * dereference
+ */
+ if (!name_prefix) {
+ dev_err(dev, "codec_info_list name_prefix of part id %#x is missing\n",
+ codec_info_list[i].part_id);
+ return NULL;
+ }
+ for (j = 0; j < codec_info_list[i].dai_num; j++) {
+ /* Check if the endpoint is present by the SDCA DisCo table */
+ if (!is_endpoint_present(sdw_device, &codec_info_list[i],
+ codec_info_list[i].dais[j].dai_type))
+ continue;
+
+ endpoints[ep_index].num = ep_index;
+ if (codec_info_list[i].dais[j].dai_type == SOC_SDW_DAI_TYPE_AMP) {
+ /* Assume all amp are aggregated */
+ endpoints[ep_index].aggregated = 1;
+ endpoints[ep_index].group_id = amp_group_id;
+ endpoints[ep_index].group_position = *amp_index;
+ /* Set group id = 2 for feedback capture endpoint */
+ amp_group_id++;
+ } else {
+ endpoints[ep_index].aggregated = 0;
+ endpoints[ep_index].group_id = 0;
+ endpoints[ep_index].group_position = 0;
+ is_amp = false;
+ }
+ ep_index++;
+ }
+ adr_dev[index].endpoints = endpoints;
+ adr_dev[index].num_endpoints = ep_index;
+ break;
+ }
+
+ if (i == asoc_sdw_get_codec_info_list_count()) {
+ dev_err(dev, "part id %#x is not supported\n", sdw_device->id.part_id);
+ return NULL;
+ }
+
+ adr_dev[index].adr = ((u64)sdw_device->id.class_id & 0xFF) |
+ ((u64)sdw_device->id.part_id & 0xFFFF) << 8 |
+ ((u64)sdw_device->id.mfg_id & 0xFFFF) << 24 |
+ ((u64)(sdw_device->id.unique_id & 0xF) << 40) |
+ ((u64)(sdw_device->id.sdw_version & 0xF) << 44) |
+ ((u64)(sdw_device->bus->link_id & 0xF) << 48);
+
+ if (!is_amp) {
+ /* For non-amp codecs, get name_prefix from codec_info_list[] */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s", name_prefix);
+ goto done_name_prefix;
+ }
+
+ /*
+ * The name_prefix comes from codec_info_list which has a name_prefix per codec.
+ * And we need to give a unique name_prefix for each amp and should be backwards
+ * compatible to the existing acpi match tables to not break existing UCMs.
+ * For the common name_prefix, we append the amp index to it. However, for the
+ * "Left" name_prefix, we convert the second amp name_prefix to "Right" and
+ * for the third and further amps, we set the name_prefix to "AMP<amp_index>".
+ */
+ if (!strcmp(name_prefix, "Left")) {
+ switch (*amp_index) {
+ case 1:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Left");
+ break;
+ case 2:
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL,
+ "%s", "Right");
+ break;
+ default:
+ /* Set the name_fix to AMP<amp_index> if there are more than 2 amps */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ "AMP", *amp_index);
+ break;
+ }
+ } else if (!strcmp(name_prefix, "AMP")) {
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s%d",
+ name_prefix,
+ *amp_index);
+ } else {
+ /*
+ * The name_prefix will be the amp name if it is not "Left" or "AMP", set it to
+ * <name_prefix>-<amp_index> format. Like rt1320-1
+ */
+ adr_dev[index].name_prefix = devm_kasprintf(dev, GFP_KERNEL, "%s-%d",
+ name_prefix,
+ *amp_index);
+ }
+ (*amp_index)++;
+
+done_name_prefix:
+ if (!adr_dev[index].name_prefix) {
+ dev_err(dev, "failed to allocate memory for name_prefix\n");
+ return NULL;
+ }
+
+ dev_dbg(dev, "adr[%d] 0x%llx link id %d name_prefix \"%s\" is found\n",
+ index, adr_dev[index].adr, sdw_device->bus->link_id, adr_dev[index].name_prefix);
+
+ link->num_adr++;
+
+ return adr_dev;
+}
+
static struct snd_soc_acpi_mach *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 sdw_extended_slave_id *ids;
+ const struct sof_intel_dsp_desc *chip;
+ struct snd_soc_acpi_link_adr *links;
+ struct sdw_peripherals *peripherals;
struct snd_soc_acpi_mach *mach;
struct sof_intel_hda_dev *hdev;
- u32 link_mask;
+ int link_index, link_num;
+ int amp_index = 1;
+ u32 link_mask = 0;
int i;
hdev = pdata->hw_pdata;
@@ -1160,7 +1316,7 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
return NULL;
}
- if (!hdev->sdw->num_slaves) {
+ if (!hdev->sdw->peripherals || !hdev->sdw->peripherals->num_peripherals) {
dev_warn(sdev->dev, "No SoundWire peripheral detected in ACPI tables\n");
return NULL;
}
@@ -1196,64 +1352,78 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
* are not found on this link.
*/
if (!snd_soc_acpi_sdw_link_slaves_found(sdev->dev, link,
- hdev->sdw->ids,
- hdev->sdw->num_slaves))
+ hdev->sdw->peripherals))
break;
}
/* Found if all Slaves are checked */
if (i == hdev->info.count || !link->num_adr)
- break;
+ if (!mach->machine_check || mach->machine_check(hdev->sdw))
+ break;
}
if (mach && mach->link_mask) {
- int dmic_num = 0;
- bool tplg_fixup;
- const char *tplg_filename;
-
mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev);
- if (pdata->tplg_filename) {
- tplg_fixup = false;
- } else {
- tplg_fixup = true;
- tplg_filename = mach->sof_tplg_filename;
- }
+ return mach;
+ }
- /*
- * DMICs use up to 4 pins and are typically pin-muxed with SoundWire
- * link 2 and 3, or link 1 and 2, thus we only try to enable dmics
- * if all conditions are true:
- * a) 2 or fewer links are used by SoundWire
- * b) the NHLT table reports the presence of microphones
- */
- if (hweight_long(mach->link_mask) <= 2) {
- int ret;
+ dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n");
+ peripherals = hdev->sdw->peripherals;
+ for (i = 0; i < peripherals->num_peripherals; i++)
+ dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n",
+ peripherals->array[i]->bus->link_id,
+ peripherals->array[i]->id.mfg_id,
+ peripherals->array[i]->id.part_id,
+ peripherals->array[i]->id.sdw_version);
- ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
- &dmic_num, tplg_fixup);
- if (ret < 0)
- return NULL;
- }
- if (tplg_fixup)
- pdata->tplg_filename = tplg_filename;
- mach->mach_params.dmic_num = dmic_num;
+ chip = get_chip_info(sdev->pdata);
- dev_dbg(sdev->dev,
- "SoundWire machine driver %s topology %s\n",
- mach->drv_name,
- pdata->tplg_filename);
+ /* SDCA was not well supported in the BIOS before ACE2.0 */
+ if (chip->hw_ip_version < SOF_INTEL_ACE_2_0)
+ return NULL;
- return mach;
+ if (!peripherals->num_peripherals)
+ return NULL;
+
+ /* Create default SDW mach */
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return NULL;
+
+ /* Get link mask and link number */
+ for (i = 0; i < peripherals->num_peripherals; i++)
+ link_mask |= BIT(peripherals->array[i]->bus->link_id);
+
+ link_num = hweight32(link_mask);
+ links = devm_kcalloc(sdev->dev, link_num, sizeof(*links), GFP_KERNEL);
+ if (!links)
+ return NULL;
+
+ /* Generate snd_soc_acpi_link_adr struct for each peripheral reported by the ACPI table */
+ for (i = 0; i < peripherals->num_peripherals; i++) {
+ /* link_index = the number of used links below the current link */
+ link_index = hweight32(link_mask & (BIT(peripherals->array[i]->bus->link_id) - 1));
+ links[link_index].adr_d = find_acpi_adr_device(sdev->dev, peripherals->array[i],
+ &links[link_index], &amp_index);
+ if (!links[link_index].adr_d)
+ return NULL;
}
- dev_info(sdev->dev, "No SoundWire machine driver found for the ACPI-reported configuration:\n");
- ids = hdev->sdw->ids;
- for (i = 0; i < hdev->sdw->num_slaves; i++)
- dev_info(sdev->dev, "link %d mfg_id 0x%04x part_id 0x%04x version %#x\n",
- ids[i].link_id, ids[i].id.mfg_id, ids[i].id.part_id, ids[i].id.sdw_version);
+ mach->drv_name = "sof_sdw";
+ mach->mach_params.links = links;
+ mach->mach_params.link_mask = link_mask;
+ mach->mach_params.platform = dev_name(sdev->dev);
+ mach->get_function_tplg_files = sof_sdw_get_tplg_files;
+ /*
+ * Set mach->sof_tplg_filename as a dummy topology to avoid tplg file checking
+ * and being used.
+ */
+ mach->sof_tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
+ "sof-%s-dummy.tplg", chip->platform);
- return NULL;
+ dev_info(sdev->dev, "Use SoundWire default machine driver with function topologies\n");
+ return mach;
}
#else
static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev)
@@ -1300,6 +1470,19 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach)
return 0;
}
+static char *remove_file_ext(struct device *dev, const char *tplg_filename)
+{
+ char *filename, *tmp;
+
+ filename = devm_kstrdup(dev, tplg_filename, GFP_KERNEL);
+ if (!filename)
+ return NULL;
+
+ /* remove file extension if exist */
+ tmp = filename;
+ return strsep(&tmp, ".");
+}
+
struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
{
u32 interface_mask = hda_get_interface_mask(sdev);
@@ -1307,24 +1490,79 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
const struct sof_dev_desc *desc = sof_pdata->desc;
struct hdac_bus *bus = sof_to_bus(sdev);
struct snd_soc_acpi_mach *mach = NULL;
- enum snd_soc_acpi_intel_codec codec_type;
+ enum snd_soc_acpi_intel_codec codec_type, amp_type;
const char *tplg_filename;
const char *tplg_suffix;
+ bool amp_name_valid;
+ bool i2s_mach_found = false;
+ bool sdw_mach_found = false;
/* Try I2S or DMIC if it is supported */
- if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC)))
+ if (interface_mask & (BIT(SOF_DAI_INTEL_SSP) | BIT(SOF_DAI_INTEL_DMIC))) {
mach = snd_soc_acpi_find_machine(desc->machines);
+ if (mach)
+ i2s_mach_found = true;
+ }
+
+ /*
+ * If I2S fails and no external HDaudio codec is detected,
+ * try SoundWire if it is supported
+ */
+ if (!mach && !HDA_EXT_CODEC(bus->codec_mask) &&
+ (interface_mask & BIT(SOF_DAI_INTEL_ALH))) {
+ mach = hda_sdw_machine_select(sdev);
+ if (mach)
+ sdw_mach_found = true;
+ }
+
+ /*
+ * Choose HDA generic machine driver if mach is NULL.
+ * Otherwise, set certain mach params.
+ */
+ hda_generic_machine_select(sdev, &mach);
+ if (!mach) {
+ dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
+ return NULL;
+ }
+
+ /* report BT offload link mask to machine driver */
+ mach->mach_params.bt_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_BT);
+
+ dev_info(sdev->dev, "BT link detected in NHLT tables: %#x\n",
+ mach->mach_params.bt_link_mask);
+
+ /* allow for module parameter override */
+ if (bt_link_mask_override) {
+ dev_dbg(sdev->dev, "overriding BT link detected in NHLT tables %#x by kernel param %#x\n",
+ mach->mach_params.bt_link_mask, bt_link_mask_override);
+ mach->mach_params.bt_link_mask = bt_link_mask_override;
+ }
+
+ if (hweight_long(mach->mach_params.bt_link_mask) > 1) {
+ dev_warn(sdev->dev, "invalid BT link mask %#x found, reset the mask\n",
+ mach->mach_params.bt_link_mask);
+ mach->mach_params.bt_link_mask = 0;
+ }
+ /*
+ * Fixup tplg file name by appending dmic num, ssp num, codec/amplifier
+ * name string if quirk flag is set.
+ */
if (mach) {
- bool add_extension = false;
bool tplg_fixup = false;
+ bool dmic_fixup = false;
/*
* If tplg file name is overridden, use it instead of
* the one set in mach table
*/
if (!sof_pdata->tplg_filename) {
- sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ /* remove file extension if it exists */
+ tplg_filename = remove_file_ext(sdev->dev, mach->sof_tplg_filename);
+ if (!tplg_filename)
+ return NULL;
+
+ sof_pdata->tplg_filename = tplg_filename;
tplg_fixup = true;
}
@@ -1342,20 +1580,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev);
+ if (sdw_mach_found || mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER)
+ dmic_fixup = true;
+
if (tplg_fixup &&
- mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
+ dmic_fixup &&
mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s",
sof_pdata->tplg_filename,
- "-dmic",
+ i2s_mach_found ? "-dmic" : "-",
mach->mach_params.dmic_num,
"ch");
if (!tplg_filename)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
}
if (mach->link_mask) {
@@ -1364,7 +1604,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
/* report SSP link mask to machine driver */
- mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
+ mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev, NHLT_DEVICE_I2S);
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
@@ -1395,7 +1635,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
mclk_mask = check_nhlt_ssp_mclk_mask(sdev, ssp_num);
@@ -1413,15 +1652,16 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
}
- codec_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev);
+ amp_type = snd_soc_acpi_intel_detect_amp_type(sdev->dev);
+ codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev);
+ amp_name_valid = amp_type != CODEC_NONE && amp_type != codec_type;
- if (tplg_fixup &&
- mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME &&
- codec_type != CODEC_NONE) {
- tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(codec_type);
+ if (tplg_fixup && amp_name_valid &&
+ mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_AMP_NAME) {
+ tplg_suffix = snd_soc_acpi_intel_get_amp_tplg_suffix(amp_type);
if (!tplg_suffix) {
dev_err(sdev->dev, "no tplg suffix found, amp %d\n",
- codec_type);
+ amp_type);
return NULL;
}
@@ -1433,10 +1673,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
}
- codec_type = snd_soc_acpi_intel_detect_codec_type(sdev->dev);
if (tplg_fixup &&
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME &&
@@ -1456,10 +1694,9 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
return NULL;
sof_pdata->tplg_filename = tplg_filename;
- add_extension = true;
}
- if (tplg_fixup && add_extension) {
+ if (tplg_fixup) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s",
sof_pdata->tplg_filename,
@@ -1478,22 +1715,6 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
}
}
- /*
- * If I2S fails and no external HDaudio codec is detected,
- * try SoundWire if it is supported
- */
- if (!mach && !HDA_EXT_CODEC(bus->codec_mask) &&
- (interface_mask & BIT(SOF_DAI_INTEL_ALH)))
- mach = hda_sdw_machine_select(sdev);
-
- /*
- * Choose HDA generic machine driver if mach is NULL.
- * Otherwise, set certain mach params.
- */
- hda_generic_machine_select(sdev, &mach);
- if (!mach)
- dev_warn(sdev->dev, "warning: No matching ASoC machine driver found\n");
-
return mach;
}
@@ -1509,7 +1730,7 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
return sof_pci_probe(pci, pci_id);
}
-EXPORT_SYMBOL_NS(hda_pci_intel_probe, SND_SOC_SOF_INTEL_HDA_GENERIC);
+EXPORT_SYMBOL_NS(hda_pci_intel_probe, "SND_SOC_SOF_INTEL_HDA_GENERIC");
int hda_register_clients(struct snd_sof_dev *sdev)
{
@@ -1523,13 +1744,14 @@ void hda_unregister_clients(struct snd_sof_dev *sdev)
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for HDaudio platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_AUDIO_CODEC_I915);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_IMPORT_NS(SND_INTEL_SOUNDWIRE_ACPI);
-MODULE_IMPORT_NS(SOUNDWIRE_INTEL_INIT);
-MODULE_IMPORT_NS(SOUNDWIRE_INTEL);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH);
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_AUDIO_CODEC_I915");
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SND_INTEL_SOUNDWIRE_ACPI");
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL_INIT");
+MODULE_IMPORT_NS("SOUNDWIRE_INTEL");
+MODULE_IMPORT_NS("SND_SOC_SDW_UTILS");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");
diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h
index 3c9e1d59e1ab..562fe8be79c1 100644
--- a/sound/soc/sof/intel/hda.h
+++ b/sound/soc/sof/intel/hda.h
@@ -487,6 +487,11 @@ enum sof_hda_D0_substate {
SOF_HDA_DSP_PM_D0I3, /* low power D0 substate */
};
+struct sof_ace3_mic_privacy {
+ bool active;
+ struct work_struct work;
+};
+
/* represents DSP HDA controller frontend - i.e. host facing control */
struct sof_intel_hda_dev {
bool imrboot_supported;
@@ -495,6 +500,15 @@ struct sof_intel_hda_dev {
int boot_iteration;
+ /*
+ * DMA buffers for base firmware download. By default the buffers are
+ * allocated once and kept through the lifetime of the driver.
+ * See module parameter: persistent_cl_buffer
+ */
+ struct snd_dma_buffer cl_dmab;
+ bool cl_dmab_contains_basefw;
+ struct snd_dma_buffer iccmax_dmab;
+
struct hda_bus hbus;
/* hw config */
@@ -533,6 +547,9 @@ struct sof_intel_hda_dev {
/* Intel NHLT information */
struct nhlt_acpi_table *nhlt;
+ /* work queue for mic privacy state change notification sending */
+ struct sof_ace3_mic_privacy mic_privacy;
+
/*
* Pointing to the IPC message if immediate sending was not possible
* because the downlink communication channel was BUSY at the time.
@@ -714,11 +731,12 @@ int hda_cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *hext_stream
struct hdac_ext_stream *hda_cl_prepare(struct device *dev, unsigned int format,
unsigned int size, struct snd_dma_buffer *dmab,
- int direction, bool is_iccmax);
+ bool persistent_buffer, int direction,
+ bool is_iccmax);
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,
- struct hdac_ext_stream *hext_stream);
+ bool persistent_buffer, struct hdac_ext_stream *hext_stream);
int cl_dsp_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
#define HDA_CL_STREAM_FORMAT 0x40
@@ -739,7 +757,7 @@ void hda_dsp_ctrl_ppcap_int_enable(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_link_reset(struct snd_sof_dev *sdev, bool reset);
void hda_dsp_ctrl_misc_clock_gating(struct snd_sof_dev *sdev, bool enable);
int hda_dsp_ctrl_clock_power_gating(struct snd_sof_dev *sdev, bool enable);
-int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev);
+int hda_dsp_ctrl_init_chip(struct snd_sof_dev *sdev, bool detect_codec);
void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev);
/*
* HDA bus operations.
@@ -903,10 +921,6 @@ extern struct snd_sof_dsp_ops sof_tgl_ops;
int sof_tgl_ops_init(struct snd_sof_dev *sdev);
extern struct snd_sof_dsp_ops sof_icl_ops;
int sof_icl_ops_init(struct snd_sof_dev *sdev);
-extern struct snd_sof_dsp_ops sof_mtl_ops;
-int sof_mtl_ops_init(struct snd_sof_dev *sdev);
-extern struct snd_sof_dsp_ops sof_lnl_ops;
-int sof_lnl_ops_init(struct snd_sof_dev *sdev);
extern const struct sof_intel_dsp_desc skl_chip_info;
extern const struct sof_intel_dsp_desc apl_chip_info;
@@ -920,6 +934,9 @@ extern const struct sof_intel_dsp_desc adls_chip_info;
extern const struct sof_intel_dsp_desc mtl_chip_info;
extern const struct sof_intel_dsp_desc arl_s_chip_info;
extern const struct sof_intel_dsp_desc lnl_chip_info;
+extern const struct sof_intel_dsp_desc ptl_chip_info;
+extern const struct sof_intel_dsp_desc wcl_chip_info;
+extern const struct sof_intel_dsp_desc nvl_s_chip_info;
/* Probes support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
@@ -1027,8 +1044,6 @@ const struct hda_dai_widget_dma_ops *
hda_select_dai_widget_ops(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
int hda_dai_config(struct snd_soc_dapm_widget *w, unsigned int flags,
struct snd_sof_dai_config_data *data);
-int hda_link_dma_cleanup(struct snd_pcm_substream *substream, struct hdac_ext_stream *hext_stream,
- struct snd_soc_dai *cpu_dai);
static inline struct snd_sof_dev *widget_to_sdev(struct snd_soc_dapm_widget *w)
{
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index dad6bc72ad37..dbc5ad62258b 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -193,4 +193,5 @@ const struct sof_intel_dsp_desc icl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_0,
+ .platform = "icl",
};
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
index 4b5665f82170..c01ea7e731aa 100644
--- a/sound/soc/sof/intel/lnl.c
+++ b/sound/soc/sof/intel/lnl.c
@@ -20,16 +20,6 @@
#include "lnl.h"
#include <sound/hda-mlink.h>
-/* LunarLake ops */
-struct snd_sof_dsp_ops sof_lnl_ops;
-
-static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = {
- {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS},
- {"fw_regs", HDA_DSP_BAR, MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY},
-};
-
/* this helps allows the DSP to setup DMIC/SSP */
static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable)
{
@@ -110,101 +100,50 @@ static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev)
return 0;
}
-int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
{
- struct sof_ipc4_fw_data *ipc4_data;
+ int ret;
- /* common defaults */
- memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+ ret = sof_mtl_set_ops(sdev, dsp_ops);
+ if (ret)
+ return ret;
/* probe/remove */
if (!sdev->dspless_mode_selected) {
- sof_lnl_ops.probe = lnl_hda_dsp_probe;
- sof_lnl_ops.remove = lnl_hda_dsp_remove;
+ dsp_ops->probe = lnl_hda_dsp_probe;
+ dsp_ops->remove = lnl_hda_dsp_remove;
}
- /* shutdown */
- sof_lnl_ops.shutdown = hda_dsp_shutdown;
-
- /* doorbell */
- sof_lnl_ops.irq_thread = mtl_ipc_irq_thread;
-
- /* ipc */
- sof_lnl_ops.send_msg = mtl_ipc_send_msg;
- sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
- sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
-
- /* debug */
- sof_lnl_ops.debug_map = lnl_dsp_debugfs;
- sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs);
- sof_lnl_ops.dbg_dump = mtl_dsp_dump;
- sof_lnl_ops.ipc_dump = mtl_ipc_dump;
-
- /* pre/post fw run */
- sof_lnl_ops.pre_fw_run = mtl_dsp_pre_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;
-
- /* dsp core get/put */
- /* TODO: add core_get and core_put */
+ /* post fw run */
+ dsp_ops->post_fw_run = lnl_dsp_post_fw_run;
/* PM */
if (!sdev->dspless_mode_selected) {
- sof_lnl_ops.resume = lnl_hda_dsp_resume;
- sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
+ dsp_ops->resume = lnl_hda_dsp_resume;
+ dsp_ops->runtime_resume = lnl_hda_dsp_runtime_resume;
}
- /* dsp core get/put */
- sof_lnl_ops.core_get = mtl_dsp_core_get;
- sof_lnl_ops.core_put = mtl_dsp_core_put;
-
- sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
- if (!sdev->private)
- return -ENOMEM;
-
- ipc4_data = sdev->private;
- ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET;
-
- ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
-
- ipc4_data->fw_context_save = true;
-
- /* External library loading support */
- ipc4_data->load_library = hda_dsp_ipc4_load_library;
-
- /* set DAI ops */
- hda_set_dai_drv_ops(sdev, &sof_lnl_ops);
-
- sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
-
return 0;
-};
+}
+EXPORT_SYMBOL_NS(sof_lnl_set_ops, "SND_SOC_SOF_INTEL_LNL");
/* Check if an SDW IRQ occurred */
-static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
+bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW);
}
+EXPORT_SYMBOL_NS(lnl_dsp_check_sdw_irq, "SND_SOC_SOF_INTEL_LNL");
-static void lnl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
+int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
- struct hdac_bus *bus = sof_to_bus(sdev);
-
- hdac_bus_eml_enable_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW, enable);
-}
-
-static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
-{
- lnl_enable_sdw_irq(sdev, false);
mtl_disable_ipc_interrupts(sdev);
return mtl_enable_interrupts(sdev, false);
}
+EXPORT_SYMBOL_NS(lnl_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_LNL");
-static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
+bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
u16 wake_sts;
@@ -220,6 +159,7 @@ static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev)
/* filter out the range of SDIs that can be set for SoundWire */
return wake_sts & GENMASK(SDW_MAX_DEVICES, SDW_INTEL_DEV_NUM_IDA_MIN);
}
+EXPORT_SYMBOL_NS(lnl_sdw_check_wakeen_irq, "SND_SOC_SOF_INTEL_LNL");
const struct sof_intel_dsp_desc lnl_chip_info = {
.cores_num = 5,
@@ -235,7 +175,6 @@ const struct sof_intel_dsp_desc lnl_chip_info = {
.ssp_count = MTL_SSP_COUNT,
.d0i3_offset = MTL_HDA_VS_D0I3C,
.read_sdw_lcount = hda_sdw_check_lcount_ext,
- .enable_sdw_irq = lnl_enable_sdw_irq,
.check_sdw_irq = lnl_dsp_check_sdw_irq,
.check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
.sdw_process_wakeen = hda_sdw_process_wakeen_common,
@@ -244,4 +183,8 @@ const struct sof_intel_dsp_desc lnl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = lnl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_2_0,
+ .platform = "lnl",
};
+
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h
index 79101af84b2e..2837f818ac51 100644
--- a/sound/soc/sof/intel/lnl.h
+++ b/sound/soc/sof/intel/lnl.h
@@ -12,4 +12,10 @@
#define LNL_DSP_REG_HFDSC 0x160200 /* DSP core0 status */
#define LNL_DSP_REG_HFDEC 0x160204 /* DSP core0 error */
+int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev);
+int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev);
+bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev);
+
#endif /* __SOF_INTEL_LNL_H */
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 1bf274509ee6..095dcf1a18e4 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -11,6 +11,7 @@
#include <linux/debugfs.h>
#include <linux/firmware.h>
+#include <linux/string_choices.h>
#include <sound/sof/ipc4/header.h>
#include <trace/events/sof_intel.h>
#include "../ipc4-priv.h"
@@ -77,7 +78,7 @@ bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev)
return false;
}
-EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, SND_SOC_SOF_INTEL_MTL);
+EXPORT_SYMBOL_NS(mtl_dsp_check_ipc_irq, "SND_SOC_SOF_INTEL_MTL");
/* Check if an SDW IRQ occurred */
static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
@@ -95,7 +96,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev)
return false;
}
-int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
+static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
struct sof_ipc4_msg *msg_data = msg->msg_data;
@@ -121,7 +122,6 @@ int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_ipc_send_msg, SND_SOC_SOF_INTEL_MTL);
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev)
{
@@ -149,7 +149,7 @@ void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev)
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, chip->ipc_ctl,
MTL_DSP_REG_HFIPCXCTL_BUSY | MTL_DSP_REG_HFIPCXCTL_DONE, 0);
}
-EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, SND_SOC_SOF_INTEL_MTL);
+EXPORT_SYMBOL_NS(mtl_disable_ipc_interrupts, "SND_SOC_SOF_INTEL_MTL");
static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
{
@@ -176,7 +176,7 @@ static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
}
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
@@ -209,7 +209,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0) {
dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
return ret;
}
@@ -228,16 +228,16 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable)
HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0) {
dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n",
- enable ? "enable" : "disable");
+ str_enable_disable(enable));
return ret;
}
return ret;
}
-EXPORT_SYMBOL_NS(mtl_enable_interrupts, SND_SOC_SOF_INTEL_MTL);
+EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL");
/* pre fw run operations */
-int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
+static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
{
struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
u32 dsphfpwrsts;
@@ -245,6 +245,18 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
u32 cpa;
u32 pgs;
int ret;
+ u32 dsppwrctl;
+ u32 dsppwrsts;
+ const struct sof_intel_dsp_desc *chip;
+
+ chip = get_chip_info(sdev->pdata);
+ if (chip->hw_ip_version > SOF_INTEL_ACE_2_0) {
+ dsppwrctl = PTL_HFPWRCTL2;
+ dsppwrsts = PTL_HFPWRSTS2;
+ } else {
+ dsppwrctl = MTL_HFPWRCTL;
+ dsppwrsts = MTL_HFPWRSTS;
+ }
/* Set the DSP subsystem power on */
snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFDSSCS,
@@ -264,14 +276,14 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
}
/* Power up gated-DSP-0 domain in order to access the DSP shim register block. */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, MTL_HFPWRCTL,
+ snd_sof_dsp_update_bits(sdev, HDA_DSP_BAR, dsppwrctl,
MTL_HFPWRCTL_WPDSPHPXPG, MTL_HFPWRCTL_WPDSPHPXPG);
usleep_range(1000, 1010);
/* poll with timeout to check if operation successful */
pgs = MTL_HFPWRSTS_DSPHPXPGS_MASK;
- ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_HFPWRSTS, dsphfpwrsts,
+ ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, dsppwrsts, dsphfpwrsts,
(dsphfpwrsts & pgs) == pgs,
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
@@ -285,9 +297,8 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev)
return ret;
}
-EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, SND_SOC_SOF_INTEL_MTL);
-int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
+static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
{
int ret;
@@ -312,9 +323,8 @@ int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev)
hda_sdw_int_enable(sdev, true);
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, SND_SOC_SOF_INTEL_MTL);
-void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
+static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
{
char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR;
u32 fwsts;
@@ -330,7 +340,6 @@ void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags)
sof_ipc4_intel_dump_telemetry_state(sdev, flags);
}
-EXPORT_SYMBOL_NS(mtl_dsp_dump, SND_SOC_SOF_INTEL_MTL);
static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev)
{
@@ -441,7 +450,7 @@ int mtl_power_down_dsp(struct snd_sof_dev *sdev)
(dsphfdsscs & cpa) == 0, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
}
-EXPORT_SYMBOL_NS(mtl_power_down_dsp, SND_SOC_SOF_INTEL_MTL);
+EXPORT_SYMBOL_NS(mtl_power_down_dsp, "SND_SOC_SOF_INTEL_MTL");
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
{
@@ -544,9 +553,9 @@ err:
kfree(dump_msg);
return ret;
}
-EXPORT_SYMBOL_NS(mtl_dsp_cl_init, SND_SOC_SOF_INTEL_MTL);
+EXPORT_SYMBOL_NS(mtl_dsp_cl_init, "SND_SOC_SOF_INTEL_MTL");
-irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
+static irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
{
struct sof_ipc4_msg notification_data = {{ 0 }};
struct snd_sof_dev *sdev = context;
@@ -628,21 +637,18 @@ irqreturn_t mtl_ipc_irq_thread(int irq, void *context)
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, SND_SOC_SOF_INTEL_MTL);
-int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
+static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
{
return MTL_DSP_MBOX_UPLINK_OFFSET;
}
-EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, SND_SOC_SOF_INTEL_MTL);
-int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
+static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id)
{
return MTL_SRAM_WINDOW_OFFSET(id);
}
-EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, SND_SOC_SOF_INTEL_MTL);
-void mtl_ipc_dump(struct snd_sof_dev *sdev)
+static void mtl_ipc_dump(struct snd_sof_dev *sdev)
{
u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl;
@@ -658,7 +664,6 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev)
"Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n",
hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl);
}
-EXPORT_SYMBOL_NS(mtl_ipc_dump, SND_SOC_SOF_INTEL_MTL);
static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
{
@@ -667,7 +672,7 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
return mtl_enable_interrupts(sdev, false);
}
-int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
+static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
@@ -679,9 +684,8 @@ int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_core_get, SND_SOC_SOF_INTEL_MTL);
-int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
+static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
int ret;
@@ -697,45 +701,41 @@ int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
return 0;
}
-EXPORT_SYMBOL_NS(mtl_dsp_core_put, SND_SOC_SOF_INTEL_MTL);
-
-/* Meteorlake ops */
-struct snd_sof_dsp_ops sof_mtl_ops;
-int sof_mtl_ops_init(struct snd_sof_dev *sdev)
+int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
{
struct sof_ipc4_fw_data *ipc4_data;
/* common defaults */
- memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
+ memcpy(dsp_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops));
/* shutdown */
- sof_mtl_ops.shutdown = hda_dsp_shutdown;
+ dsp_ops->shutdown = hda_dsp_shutdown;
/* doorbell */
- sof_mtl_ops.irq_thread = mtl_ipc_irq_thread;
+ dsp_ops->irq_thread = mtl_ipc_irq_thread;
/* ipc */
- sof_mtl_ops.send_msg = mtl_ipc_send_msg;
- sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
- sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset;
+ dsp_ops->send_msg = mtl_ipc_send_msg;
+ dsp_ops->get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset;
+ dsp_ops->get_window_offset = mtl_dsp_ipc_get_window_offset;
/* debug */
- sof_mtl_ops.debug_map = mtl_dsp_debugfs;
- sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
- sof_mtl_ops.dbg_dump = mtl_dsp_dump;
- sof_mtl_ops.ipc_dump = mtl_ipc_dump;
+ dsp_ops->debug_map = mtl_dsp_debugfs;
+ dsp_ops->debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs);
+ dsp_ops->dbg_dump = mtl_dsp_dump;
+ dsp_ops->ipc_dump = mtl_ipc_dump;
/* pre/post fw run */
- sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run;
- sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run;
+ dsp_ops->pre_fw_run = mtl_dsp_pre_fw_run;
+ dsp_ops->post_fw_run = mtl_dsp_post_fw_run;
/* parse platform specific extended manifest */
- sof_mtl_ops.parse_platform_ext_manifest = NULL;
+ dsp_ops->parse_platform_ext_manifest = NULL;
/* dsp core get/put */
- sof_mtl_ops.core_get = mtl_dsp_core_get;
- sof_mtl_ops.core_put = mtl_dsp_core_put;
+ dsp_ops->core_get = mtl_dsp_core_get;
+ dsp_ops->core_put = mtl_dsp_core_put;
sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
@@ -751,13 +751,14 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
- /* set DAI ops */
- hda_set_dai_drv_ops(sdev, &sof_mtl_ops);
+ dsp_ops->set_power_state = hda_dsp_set_power_state_ipc4;
- sof_mtl_ops.set_power_state = hda_dsp_set_power_state_ipc4;
+ /* set DAI ops */
+ hda_set_dai_drv_ops(sdev, dsp_ops);
return 0;
-};
+}
+EXPORT_SYMBOL_NS(sof_mtl_set_ops, "SND_SOC_SOF_INTEL_MTL");
const struct sof_intel_dsp_desc mtl_chip_info = {
.cores_num = 3,
@@ -785,6 +786,7 @@ const struct sof_intel_dsp_desc mtl_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = mtl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "mtl",
};
const struct sof_intel_dsp_desc arl_s_chip_info = {
@@ -813,4 +815,5 @@ const struct sof_intel_dsp_desc arl_s_chip_info = {
.power_down_dsp = mtl_power_down_dsp,
.disable_interrupts = mtl_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_ACE_1_0,
+ .platform = "arl",
};
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 7acaa7e724f4..e01a1536709e 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -12,9 +12,11 @@
#define MTL_HFDSSCS_CPA_MASK BIT(24)
#define MTL_HFSNDWIE 0x114C
#define MTL_HFPWRCTL 0x1D18
+#define PTL_HFPWRCTL2 0x1D20
#define MTL_HfPWRCTL_WPIOXPG(x) BIT((x) + 8)
#define MTL_HFPWRCTL_WPDSPHPXPG BIT(0)
#define MTL_HFPWRSTS 0x1D1C
+#define PTL_HFPWRSTS2 0x1D24
#define MTL_HFPWRSTS_DSPHPXPGS_MASK BIT(0)
#define MTL_HFINTIPPTR 0x1108
#define MTL_IRQ_INTEN_L_HOST_IPC_MASK BIT(0)
@@ -120,26 +122,13 @@
#define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0)
bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev);
-int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg);
void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev);
void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev);
int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable);
-int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev);
-int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev);
-void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags);
-
int mtl_power_down_dsp(struct snd_sof_dev *sdev);
int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
-irqreturn_t mtl_ipc_irq_thread(int irq, void *context);
-
-int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev);
-int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
-
-void mtl_ipc_dump(struct snd_sof_dev *sdev);
-
-int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core);
-int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core);
+int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
diff --git a/sound/soc/sof/intel/nvl.c b/sound/soc/sof/intel/nvl.c
new file mode 100644
index 000000000000..ff215151af2a
--- /dev/null
+++ b/sound/soc/sof/intel/nvl.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2025 Intel Corporation
+
+/*
+ * Hardware interface for audio DSP on NovaLake.
+ */
+
+#include <sound/hda_register.h>
+#include <sound/hda-mlink.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+#include "lnl.h"
+#include "ptl.h"
+#include "nvl.h"
+
+int sof_nvl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
+{
+ /* Use PTL ops for NVL */
+ return sof_ptl_set_ops(sdev, dsp_ops);
+};
+EXPORT_SYMBOL_NS(sof_nvl_set_ops, "SND_SOC_SOF_INTEL_NVL");
+
+const struct sof_intel_dsp_desc nvl_s_chip_info = {
+ .cores_num = 2,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(0),
+ .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+ .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+ .rom_status_reg = LNL_DSP_REG_HFDSC,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_ext,
+ .check_sdw_irq = lnl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = lnl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_4_0,
+};
+
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_PTL");
diff --git a/sound/soc/sof/intel/nvl.h b/sound/soc/sof/intel/nvl.h
new file mode 100644
index 000000000000..0be3fdfbbd48
--- /dev/null
+++ b/sound/soc/sof/intel/nvl.h
@@ -0,0 +1,14 @@
+/* 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) 2025 Intel Corporation
+ */
+
+#ifndef __SOF_INTEL_NVL_H
+#define __SOF_INTEL_NVL_H
+
+int sof_nvl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+#endif /* __SOF_INTEL_NVL_H */
diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c
index f006dcf5458a..0bf7ee753bc3 100644
--- a/sound/soc/sof/intel/pci-apl.c
+++ b/sound/soc/sof/intel/pci-apl.c
@@ -99,13 +99,13 @@ static struct pci_driver snd_sof_pci_intel_apl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_apl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for ApolloLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c
index a8406342f08b..de48640024e4 100644
--- a/sound/soc/sof/intel/pci-cnl.c
+++ b/sound/soc/sof/intel/pci-cnl.c
@@ -137,13 +137,13 @@ static struct pci_driver snd_sof_pci_intel_cnl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_cnl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for CannonLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c
index 25effca50d9f..fd219e654844 100644
--- a/sound/soc/sof/intel/pci-icl.c
+++ b/sound/soc/sof/intel/pci-icl.c
@@ -102,14 +102,14 @@ static struct pci_driver snd_sof_pci_intel_icl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_icl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for IceLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_CNL);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_CNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c
index 602c574064eb..ae379c23f008 100644
--- a/sound/soc/sof/intel/pci-lnl.c
+++ b/sound/soc/sof/intel/pci-lnl.c
@@ -18,7 +18,15 @@
/* platform specific devices */
#include "hda.h"
-#include "mtl.h"
+#include "lnl.h"
+
+/* LunarLake ops */
+static struct snd_sof_dsp_ops sof_lnl_ops;
+
+static int sof_lnl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_lnl_set_ops(sdev, &sof_lnl_ops);
+}
static const struct sof_dev_desc lnl_desc = {
.use_acpi_target_states = true,
@@ -64,15 +72,13 @@ static struct pci_driver snd_sof_pci_intel_lnl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_lnl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for LunarLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_MTL);
-MODULE_IMPORT_NS(SND_SOC_SOF_HDA_MLINK);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c
index 8cb0333c033e..7b2533999195 100644
--- a/sound/soc/sof/intel/pci-mtl.c
+++ b/sound/soc/sof/intel/pci-mtl.c
@@ -20,6 +20,14 @@
#include "hda.h"
#include "mtl.h"
+/* Meteorlake ops */
+static struct snd_sof_dsp_ops sof_mtl_ops;
+
+static int sof_mtl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_mtl_set_ops(sdev, &sof_mtl_ops);
+}
+
static const struct sof_dev_desc mtl_desc = {
.use_acpi_target_states = true,
.machines = snd_soc_acpi_intel_mtl_machines,
@@ -127,13 +135,13 @@ static struct pci_driver snd_sof_pci_intel_mtl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_mtl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for MeteorLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-nvl.c b/sound/soc/sof/intel/pci-nvl.c
new file mode 100644
index 000000000000..c499c14b93d5
--- /dev/null
+++ b/sound/soc/sof/intel/pci-nvl.c
@@ -0,0 +1,82 @@
+// 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) 2025 Intel Corporation.
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "nvl.h"
+
+/* PantherLake ops */
+static struct snd_sof_dsp_ops sof_nvl_ops;
+
+static int sof_nvl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_nvl_set_ops(sdev, &sof_nvl_ops);
+}
+
+static const struct sof_dev_desc nvl_s_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_nvl_machines,
+ .alt_machines = snd_soc_acpi_intel_nvl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &nvl_s_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/nvl-s",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/nvl-s",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-nvl-s.ri",
+ },
+ .nocodec_tplg_filename = "sof-nvl-nocodec.tplg",
+ .ops = &sof_nvl_ops,
+ .ops_init = sof_nvl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, HDA_NVL_S, &nvl_s_desc) }, /* NVL-S */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_nvl_driver = {
+ .name = "sof-audio-pci-intel-nvl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_intel_nvl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF support for NovaLake platforms");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c
new file mode 100644
index 000000000000..68f6a9841633
--- /dev/null
+++ b/sound/soc/sof/intel/pci-ptl.c
@@ -0,0 +1,113 @@
+// 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.
+//
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <sound/soc-acpi.h>
+#include <sound/soc-acpi-intel-match.h>
+#include <sound/sof.h>
+#include "../ops.h"
+#include "../sof-pci-dev.h"
+
+/* platform specific devices */
+#include "hda.h"
+#include "ptl.h"
+
+/* PantherLake ops */
+static struct snd_sof_dsp_ops sof_ptl_ops;
+
+static int sof_ptl_ops_init(struct snd_sof_dev *sdev)
+{
+ return sof_ptl_set_ops(sdev, &sof_ptl_ops);
+}
+
+static const struct sof_dev_desc ptl_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_ptl_machines,
+ .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &ptl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/ptl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/ptl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-ptl.ri",
+ },
+ .nocodec_tplg_filename = "sof-ptl-nocodec.tplg",
+ .ops = &sof_ptl_ops,
+ .ops_init = sof_ptl_ops_init,
+};
+
+static const struct sof_dev_desc wcl_desc = {
+ .use_acpi_target_states = true,
+ .machines = snd_soc_acpi_intel_ptl_machines,
+ .alt_machines = snd_soc_acpi_intel_ptl_sdw_machines,
+ .resindex_lpe_base = 0,
+ .resindex_pcicfg_base = -1,
+ .resindex_imr_base = -1,
+ .irqindex_host_ipc = -1,
+ .chip_info = &wcl_chip_info,
+ .ipc_supported_mask = BIT(SOF_IPC_TYPE_4),
+ .ipc_default = SOF_IPC_TYPE_4,
+ .dspless_mode_supported = true,
+ .default_fw_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4/wcl",
+ },
+ .default_lib_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-lib/wcl",
+ },
+ .default_tplg_path = {
+ [SOF_IPC_TYPE_4] = "intel/sof-ipc4-tplg",
+ },
+ .default_fw_filename = {
+ [SOF_IPC_TYPE_4] = "sof-wcl.ri",
+ },
+ .nocodec_tplg_filename = "sof-ptl-nocodec.tplg",
+ .ops = &sof_ptl_ops,
+ .ops_init = sof_ptl_ops_init,
+};
+
+/* PCI IDs */
+static const struct pci_device_id sof_pci_ids[] = {
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL, &ptl_desc) }, /* PTL */
+ { PCI_DEVICE_DATA(INTEL, HDA_PTL_H, &ptl_desc) }, /* PTL-H */
+ { PCI_DEVICE_DATA(INTEL, HDA_WCL, &wcl_desc) }, /* WCL */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sof_pci_ids);
+
+/* pci_driver definition */
+static struct pci_driver snd_sof_pci_intel_ptl_driver = {
+ .name = "sof-audio-pci-intel-ptl",
+ .id_table = sof_pci_ids,
+ .probe = hda_pci_intel_probe,
+ .remove = sof_pci_remove,
+ .shutdown = sof_pci_shutdown,
+ .driver = {
+ .pm = pm_ptr(&sof_pci_pm),
+ },
+};
+module_pci_driver(snd_sof_pci_intel_ptl_driver);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("SOF support for PantherLake platforms");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c
index 8ca0231d7e4f..a16945dc35f7 100644
--- a/sound/soc/sof/intel/pci-skl.c
+++ b/sound/soc/sof/intel/pci-skl.c
@@ -83,13 +83,13 @@ static struct pci_driver snd_sof_pci_intel_skl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_skl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for SkyLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c
index ebe1a7d16689..437c43819825 100644
--- a/sound/soc/sof/intel/pci-tgl.c
+++ b/sound/soc/sof/intel/pci-tgl.c
@@ -183,7 +183,7 @@ static const struct sof_dev_desc adl_desc = {
.ops_free = hda_ops_free,
};
-static const struct sof_dev_desc adl_n_desc = {
+static const struct sof_dev_desc adln_desc = {
.machines = snd_soc_acpi_intel_adl_machines,
.alt_machines = snd_soc_acpi_intel_adl_sdw_machines,
.use_acpi_target_states = true,
@@ -298,7 +298,7 @@ static const struct pci_device_id sof_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_ADL_PX, &adl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &rpl_desc) },
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &rpl_desc) },
- { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adl_n_desc) },
+ { PCI_DEVICE_DATA(INTEL, HDA_ADL_N, &adln_desc) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, sof_pci_ids);
@@ -311,14 +311,14 @@ static struct pci_driver snd_sof_pci_intel_tgl_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_tgl_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for TigerLake platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_GENERIC);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HDA_COMMON);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_CNL);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_CNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c
index 1375c393827e..0c11cc1fd820 100644
--- a/sound/soc/sof/intel/pci-tng.c
+++ b/sound/soc/sof/intel/pci-tng.c
@@ -238,14 +238,13 @@ static struct pci_driver snd_sof_pci_intel_tng_driver = {
.remove = sof_pci_remove,
.shutdown = sof_pci_shutdown,
.driver = {
- .pm = &sof_pci_pm,
+ .pm = pm_ptr(&sof_pci_pm),
},
};
module_pci_driver(snd_sof_pci_intel_tng_driver);
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("SOF support for Tangier platforms");
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_HIFI_EP_IPC);
-MODULE_IMPORT_NS(SND_SOC_SOF_XTENSA);
-MODULE_IMPORT_NS(SND_SOC_SOF_PCI_DEV);
-MODULE_IMPORT_NS(SND_SOC_SOF_INTEL_ATOM_HIFI_EP);
+MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA");
+MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP");
diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c
new file mode 100644
index 000000000000..c1db735237f8
--- /dev/null
+++ b/sound/soc/sof/intel/ptl.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
+//
+// Copyright(c) 2025 Intel Corporation
+
+/*
+ * Hardware interface for audio DSP on PantherLake.
+ */
+
+#include <sound/hda_register.h>
+#include <sound/hda-mlink.h>
+#include <sound/sof/ipc4/header.h>
+#include "../ipc4-priv.h"
+#include "../ops.h"
+#include "hda.h"
+#include "hda-ipc.h"
+#include "../sof-audio.h"
+#include "mtl.h"
+#include "lnl.h"
+#include "ptl.h"
+
+static bool sof_ptl_check_mic_privacy_irq(struct snd_sof_dev *sdev, bool alt,
+ int elid)
+{
+ if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)
+ return false;
+
+ return hdac_bus_eml_is_mic_privacy_changed(sof_to_bus(sdev), alt, elid);
+}
+
+static void sof_ptl_mic_privacy_work(struct work_struct *work)
+{
+ struct sof_intel_hda_dev *hdev = container_of(work,
+ struct sof_intel_hda_dev,
+ mic_privacy.work);
+ struct hdac_bus *bus = &hdev->hbus.core;
+ struct snd_sof_dev *sdev = dev_get_drvdata(bus->dev);
+ bool state;
+
+ /*
+ * The microphone privacy state is only available via Soundwire shim
+ * in PTL
+ * The work is only scheduled on change.
+ */
+ state = hdac_bus_eml_get_mic_privacy_state(bus, 1,
+ AZX_REG_ML_LEPTR_ID_SDW);
+ sof_ipc4_mic_privacy_state_change(sdev, state);
+}
+
+static void sof_ptl_process_mic_privacy(struct snd_sof_dev *sdev, bool alt,
+ int elid)
+{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+
+ if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW)
+ return;
+
+ /*
+ * Schedule the work to read the microphone privacy state and send IPC
+ * message about the new state to the firmware
+ */
+ schedule_work(&hdev->mic_privacy.work);
+}
+
+static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev,
+ struct sof_ipc4_intel_mic_privacy_cap *caps)
+{
+ struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata;
+ u32 micpvcp;
+
+ if (!caps || !caps->capabilities_length)
+ return;
+
+ micpvcp = caps->capabilities[0];
+
+ /* No need to set the mic privacy if it is not enabled or forced */
+ if (!(micpvcp & PTL_MICPVCP_DDZE_ENABLED) ||
+ micpvcp & PTL_MICPVCP_DDZE_FORCED)
+ return;
+
+ hdac_bus_eml_set_mic_privacy_mask(sof_to_bus(sdev), true,
+ AZX_REG_ML_LEPTR_ID_SDW,
+ PTL_MICPVCP_GET_SDW_MASK(micpvcp));
+
+ INIT_WORK(&hdev->mic_privacy.work, sof_ptl_mic_privacy_work);
+ hdev->mic_privacy.active = true;
+}
+
+int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops)
+{
+ struct sof_ipc4_fw_data *ipc4_data;
+ int ret;
+
+ ret = sof_lnl_set_ops(sdev, dsp_ops);
+ if (ret)
+ return ret;
+
+ ipc4_data = sdev->private;
+ ipc4_data->intel_configure_mic_privacy = sof_ptl_set_mic_privacy;
+
+ return 0;
+};
+EXPORT_SYMBOL_NS(sof_ptl_set_ops, "SND_SOC_SOF_INTEL_PTL");
+
+const struct sof_intel_dsp_desc ptl_chip_info = {
+ .cores_num = 5,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(0),
+ .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+ .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+ .rom_status_reg = LNL_DSP_REG_HFDSC,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_ext,
+ .check_sdw_irq = lnl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .check_mic_privacy_irq = sof_ptl_check_mic_privacy_irq,
+ .process_mic_privacy = sof_ptl_process_mic_privacy,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = lnl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_3_0,
+ .platform = "ptl",
+};
+
+const struct sof_intel_dsp_desc wcl_chip_info = {
+ .cores_num = 3,
+ .init_core_mask = BIT(0),
+ .host_managed_cores_mask = BIT(0),
+ .ipc_req = MTL_DSP_REG_HFIPCXIDR,
+ .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY,
+ .ipc_ack = MTL_DSP_REG_HFIPCXIDA,
+ .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE,
+ .ipc_ctl = MTL_DSP_REG_HFIPCXCTL,
+ .rom_status_reg = LNL_DSP_REG_HFDSC,
+ .rom_init_timeout = 300,
+ .ssp_count = MTL_SSP_COUNT,
+ .d0i3_offset = MTL_HDA_VS_D0I3C,
+ .read_sdw_lcount = hda_sdw_check_lcount_ext,
+ .check_sdw_irq = lnl_dsp_check_sdw_irq,
+ .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq,
+ .sdw_process_wakeen = hda_sdw_process_wakeen_common,
+ .check_ipc_irq = mtl_dsp_check_ipc_irq,
+ .cl_init = mtl_dsp_cl_init,
+ .power_down_dsp = mtl_power_down_dsp,
+ .disable_interrupts = lnl_dsp_disable_interrupts,
+ .hw_ip_version = SOF_INTEL_ACE_3_0,
+ .platform = "wcl",
+};
+
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL");
+MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL");
+MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK");
diff --git a/sound/soc/sof/intel/ptl.h b/sound/soc/sof/intel/ptl.h
new file mode 100644
index 000000000000..6a7ef11f411e
--- /dev/null
+++ b/sound/soc/sof/intel/ptl.h
@@ -0,0 +1,19 @@
+/* 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) 2025 Intel Corporation
+ */
+
+#ifndef __SOF_INTEL_PTL_H
+#define __SOF_INTEL_PTL_H
+
+#define PTL_MICPVCP_DDZE_FORCED BIT(16)
+#define PTL_MICPVCP_DDZE_ENABLED BIT(17)
+#define PTL_MICPVCP_DDZLS_SDW GENMASK(26, 20)
+#define PTL_MICPVCP_GET_SDW_MASK(x) (((x) & PTL_MICPVCP_DDZLS_SDW) >> 20)
+
+int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops);
+
+#endif /* __SOF_INTEL_PTL_H */
diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h
index 9328d2bbfd03..33d27cb5f1d7 100644
--- a/sound/soc/sof/intel/shim.h
+++ b/sound/soc/sof/intel/shim.h
@@ -22,6 +22,8 @@ enum sof_intel_hw_ip_version {
SOF_INTEL_CAVS_2_5, /* TigerLake, AlderLake */
SOF_INTEL_ACE_1_0, /* MeteorLake */
SOF_INTEL_ACE_2_0, /* LunarLake */
+ SOF_INTEL_ACE_3_0, /* PantherLake */
+ SOF_INTEL_ACE_4_0, /* NovaLake */
};
/*
@@ -185,6 +187,7 @@ struct sof_intel_dsp_desc {
u32 sdw_alh_base;
u32 d0i3_offset;
u32 quirks;
+ const char *platform;
enum sof_intel_hw_ip_version hw_ip_version;
int (*read_sdw_lcount)(struct snd_sof_dev *sdev);
void (*enable_sdw_irq)(struct snd_sof_dev *sdev, bool enable);
@@ -192,6 +195,8 @@ struct sof_intel_dsp_desc {
bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev);
void (*sdw_process_wakeen)(struct snd_sof_dev *sdev);
bool (*check_ipc_irq)(struct snd_sof_dev *sdev);
+ bool (*check_mic_privacy_irq)(struct snd_sof_dev *sdev, bool alt, int elid);
+ void (*process_mic_privacy)(struct snd_sof_dev *sdev, bool alt, int elid);
int (*power_down_dsp)(struct snd_sof_dev *sdev);
int (*disable_interrupts)(struct snd_sof_dev *sdev);
int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot);
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index 9a002811e9ff..90a3c2e2334c 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -50,7 +50,7 @@ static int skl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev)
/* skylake ops */
struct snd_sof_dsp_ops sof_skl_ops;
-EXPORT_SYMBOL_NS(sof_skl_ops, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_skl_ops, "SND_SOC_SOF_INTEL_HDA_COMMON");
int sof_skl_ops_init(struct snd_sof_dev *sdev)
{
@@ -96,7 +96,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev)
return 0;
};
-EXPORT_SYMBOL_NS(sof_skl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_skl_ops_init, "SND_SOC_SOF_INTEL_HDA_COMMON");
const struct sof_intel_dsp_desc skl_chip_info = {
.cores_num = 2,
@@ -113,5 +113,6 @@ const struct sof_intel_dsp_desc skl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_1_5,
+ .platform = "skl",
};
-EXPORT_SYMBOL_NS(skl_chip_info, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(skl_chip_info, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/telemetry.c b/sound/soc/sof/intel/telemetry.c
index 2d2f96548310..dcaaf03599db 100644
--- a/sound/soc/sof/intel/telemetry.c
+++ b/sound/soc/sof/intel/telemetry.c
@@ -93,4 +93,4 @@ free_block:
free_telemetry_data:
kfree(telemetry_data);
}
-EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, SND_SOC_SOF_INTEL_HDA_COMMON);
+EXPORT_SYMBOL_NS(sof_ipc4_intel_dump_telemetry_state, "SND_SOC_SOF_INTEL_HDA_COMMON");
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index df2d26b78ddc..e68bbe685ba3 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -162,6 +162,7 @@ const struct sof_intel_dsp_desc tgl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
const struct sof_intel_dsp_desc tglh_chip_info = {
@@ -191,6 +192,7 @@ const struct sof_intel_dsp_desc tglh_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "tgl",
};
const struct sof_intel_dsp_desc ehl_chip_info = {
@@ -220,6 +222,7 @@ const struct sof_intel_dsp_desc ehl_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "ehl",
};
const struct sof_intel_dsp_desc adls_chip_info = {
@@ -249,4 +252,5 @@ const struct sof_intel_dsp_desc adls_chip_info = {
.power_down_dsp = hda_power_down_dsp,
.disable_interrupts = hda_dsp_disable_interrupts,
.hw_ip_version = SOF_INTEL_CAVS_2_5,
+ .platform = "adl",
};