diff options
Diffstat (limited to 'sound/soc/sof/intel')
46 files changed, 1744 insertions, 487 deletions
diff --git a/sound/soc/sof/intel/Kconfig b/sound/soc/sof/intel/Kconfig index 2c43558d96b9..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 @@ -298,6 +300,23 @@ config SND_SOC_SOF_PANTHERLAKE 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 @@ -309,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 @@ -342,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 f40daa616803..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,7 +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 +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 @@ -45,3 +50,4 @@ 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 322ff118f0f6..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; @@ -687,7 +686,7 @@ static struct platform_driver snd_sof_acpi_intel_bdw_driver = { .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 f531710cf94e..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; @@ -468,7 +467,7 @@ static struct platform_driver snd_sof_acpi_intel_byt_driver = { .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.c b/sound/soc/sof/intel/hda-dai.c index ee274d445515..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, @@ -304,7 +317,8 @@ 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; @@ -489,6 +503,12 @@ 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"); @@ -568,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, @@ -603,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) { @@ -660,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; } @@ -729,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) { @@ -743,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. @@ -895,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 6028a80418bb..e9f092f082a1 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -70,6 +70,7 @@ static void hda_get_interfaces(struct snd_sof_dev *sdev, u32 *interface_mask) 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); @@ -90,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) { @@ -120,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. @@ -216,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) { @@ -242,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) { @@ -270,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. @@ -322,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) { @@ -370,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) @@ -411,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) { @@ -430,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) { @@ -448,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) { @@ -732,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) @@ -744,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:- @@ -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"); @@ -948,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) { @@ -964,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) { @@ -978,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) { @@ -991,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 */ @@ -1000,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) { @@ -1017,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) { @@ -1061,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) { @@ -1134,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) { @@ -1154,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) { @@ -1181,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) { @@ -1222,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) @@ -1238,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) { @@ -1252,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) { @@ -1276,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) { @@ -1302,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) { @@ -1314,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) { @@ -1328,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 @@ -1339,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"}, @@ -1550,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, @@ -1623,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 76a03b6b2728..2cc11d8b0f70 100644 --- a/sound/soc/sof/intel/hda-loader.c +++ b/sound/soc/sof/intel/hda-loader.c @@ -113,7 +113,7 @@ 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. @@ -237,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) { @@ -270,7 +270,7 @@ 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, bool persistent_buffer, struct hdac_ext_stream *hext_stream) @@ -308,7 +308,7 @@ int hda_cl_cleanup(struct device *dev, struct snd_dma_buffer *dmab, 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 @@ -405,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) { @@ -567,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) @@ -579,8 +579,11 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev, struct sof_ipc4_msg msg = {}; 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 */ @@ -683,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) @@ -722,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 46f89d6d06f8..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,7 @@ 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) { @@ -497,7 +508,7 @@ void hdac_bus_eml_enable_interrupt_unlocked(struct hdac_bus *bus, bool alt, int 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); +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) { @@ -519,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) { @@ -537,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) { @@ -557,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) { @@ -581,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) { @@ -605,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) { @@ -631,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) { @@ -660,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) @@ -696,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) @@ -708,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) @@ -742,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: @@ -755,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) { @@ -789,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) { @@ -809,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 @@ -853,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) { @@ -866,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) { @@ -876,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) { @@ -895,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) { @@ -913,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) { @@ -925,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) { @@ -937,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) { @@ -949,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) { @@ -961,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) { @@ -985,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 519bafd3b947..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 @@ -738,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) { @@ -761,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) @@ -858,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) { @@ -890,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; } @@ -996,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) { @@ -1026,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) @@ -1113,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)) @@ -1129,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] + @@ -1153,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 @@ -1185,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 01b135068b1f..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 @@ -580,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); @@ -593,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) { @@ -673,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)) { @@ -739,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) { @@ -894,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) { @@ -929,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); @@ -954,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) { @@ -970,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, @@ -1006,7 +1059,21 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, if (!*mach && codec_num <= 2) { 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); @@ -1066,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; + 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; @@ -1150,7 +1377,53 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev peripherals->array[i]->id.part_id, peripherals->array[i]->id.sdw_version); - return NULL; + chip = get_chip_info(sdev->pdata); + + /* SDCA was not well supported in the BIOS before ACE2.0 */ + if (chip->hw_ip_version < SOF_INTEL_ACE_2_0) + return NULL; + + 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], &_index); + if (!links[link_index].adr_d) + return NULL; + } + + 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); + + 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) @@ -1197,11 +1470,11 @@ static int check_tplg_quirk_mask(struct snd_soc_acpi_mach *mach) return 0; } -static char *remove_file_ext(const char *tplg_filename) +static char *remove_file_ext(struct device *dev, const char *tplg_filename) { char *filename, *tmp; - filename = kstrdup(tplg_filename, GFP_KERNEL); + filename = devm_kstrdup(dev, tplg_filename, GFP_KERNEL); if (!filename) return NULL; @@ -1285,7 +1558,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) */ if (!sof_pdata->tplg_filename) { /* remove file extension if it exists */ - tplg_filename = remove_file_ext(mach->sof_tplg_filename); + tplg_filename = remove_file_ext(sdev->dev, mach->sof_tplg_filename); if (!tplg_filename) return NULL; @@ -1307,22 +1580,8 @@ 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) { - /* - * 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) - dmic_fixup = true; - else - mach->mach_params.dmic_num = 0; - } else { - if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER) - dmic_fixup = true; - } + if (sdw_mach_found || mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER) + dmic_fixup = true; if (tplg_fixup && dmic_fixup && @@ -1471,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) { @@ -1485,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 22bd9c3c8216..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; @@ -542,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. @@ -749,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. @@ -913,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; @@ -931,6 +935,8 @@ 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) @@ -1038,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 e3c4b4a0d705..c01ea7e731aa 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -20,17 +20,6 @@ #include "lnl.h" #include <sound/hda-mlink.h> -/* LunarLake ops */ -struct snd_sof_dsp_ops sof_lnl_ops; -EXPORT_SYMBOL_NS(sof_lnl_ops, SND_SOC_SOF_INTEL_LNL); - -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) { @@ -111,94 +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_ops_init, SND_SOC_SOF_INTEL_LNL); +} +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 int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) +int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { 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; @@ -214,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, @@ -237,28 +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", }; -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, - .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, -}; -EXPORT_SYMBOL_NS(ptl_chip_info, SND_SOC_SOF_INTEL_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 2b9d22ccf345..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; @@ -297,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; @@ -324,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; @@ -342,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) { @@ -453,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) { @@ -556,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; @@ -640,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; @@ -670,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) { @@ -679,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; @@ -691,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; @@ -709,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) @@ -763,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, @@ -797,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 = { @@ -825,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 9ab4b21c960e..e01a1536709e 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -122,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 index 69195b5e7b1a..68f6a9841633 100644 --- a/sound/soc/sof/intel/pci-ptl.c +++ b/sound/soc/sof/intel/pci-ptl.c @@ -16,7 +16,15 @@ /* platform specific devices */ #include "hda.h" -#include "mtl.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, @@ -43,13 +51,44 @@ static const struct sof_dev_desc ptl_desc = { [SOF_IPC_TYPE_4] = "sof-ptl.ri", }, .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", - .ops = &sof_lnl_ops, - .ops_init = sof_lnl_ops_init, + .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); @@ -62,16 +101,13 @@ static struct pci_driver snd_sof_pci_intel_ptl_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_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_INTEL_LNL); -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-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 01db2e720b44..437c43819825 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -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 8709b750a11e..33d27cb5f1d7 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -23,6 +23,7 @@ enum sof_intel_hw_ip_version { SOF_INTEL_ACE_1_0, /* MeteorLake */ SOF_INTEL_ACE_2_0, /* LunarLake */ SOF_INTEL_ACE_3_0, /* PantherLake */ + SOF_INTEL_ACE_4_0, /* NovaLake */ }; /* @@ -186,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); @@ -193,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", }; |
