diff options
Diffstat (limited to 'sound/soc/intel')
206 files changed, 8537 insertions, 32287 deletions
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 4b9e498e3303..2db494b0e3cf 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -15,9 +15,6 @@ config SND_SOC_INTEL_SST_TOPLEVEL if SND_SOC_INTEL_SST_TOPLEVEL -config SND_SOC_INTEL_SST - tristate - config SND_SOC_INTEL_CATPT tristate "Haswell and Broadwell" depends on ACPI || COMPILE_TEST @@ -67,126 +64,6 @@ config SND_SST_ATOM_HIFI2_PLATFORM_ACPI Baytrail/Cherrytrail. If you want to enable SOF on Baytrail/Cherrytrail, you need to deselect this option first. -config SND_SOC_INTEL_SKYLAKE - tristate "All Skylake/SST Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKL - select SND_SOC_INTEL_APL - select SND_SOC_INTEL_KBL - select SND_SOC_INTEL_GLK - select SND_SOC_INTEL_CNL - select SND_SOC_INTEL_CFL - help - This is a backwards-compatible option to select all devices - supported by the Intel SST/Skylake driver. This option is no - longer recommended and will be deprecated when the SOF - driver is introduced. Distributions should explicitly - select which platform uses this driver. - -config SND_SOC_INTEL_SKL - tristate "Skylake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Skylake platform with the DSP enabled - in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_APL - tristate "Broxton/ApolloLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Broxton/ApolloLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_KBL - tristate "Kabylake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel Kabylake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_GLK - tristate "GeminiLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel GeminiLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CNL - tristate "CannonLake/WhiskyLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CNL/WHL platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CFL - tristate "CoffeeLake Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CoffeeLake platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CML_H - tristate "CometLake-H Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CometLake-H platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_CML_LP - tristate "CometLake-LP Platforms" - depends on PCI && ACPI - depends on COMMON_CLK - select SND_SOC_INTEL_SKYLAKE_FAMILY - help - If you have a Intel CometLake-LP platform with the DSP - enabled in the BIOS then enable this option by saying Y or m. - -config SND_SOC_INTEL_SKYLAKE_FAMILY - tristate - select SND_SOC_INTEL_SKYLAKE_COMMON - -if SND_SOC_INTEL_SKYLAKE_FAMILY - -config SND_SOC_INTEL_SKYLAKE_SSP_CLK - tristate - -config SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC - bool "HDAudio codec support" - help - If you have Intel Skylake or Kabylake with HDAudio codec - and DMIC present then enable this option by saying Y. - -config SND_SOC_INTEL_SKYLAKE_COMMON - tristate - select SND_HDA_EXT_CORE - select SND_HDA_DSP_LOADER - select SND_SOC_TOPOLOGY - select SND_SOC_INTEL_SST - select SND_SOC_HDAC_HDA - select SND_SOC_ACPI_INTEL_MATCH - select SND_INTEL_DSP_CONFIG - help - If you have a Intel Skylake/Broxton/ApolloLake/KabyLake/ - GeminiLake or CannonLake platform with the DSP enabled in the BIOS - then enable this option by saying Y or m. - -endif ## SND_SOC_INTEL_SKYLAKE_FAMILY - endif ## SND_SOC_INTEL_SST_TOPLEVEL if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL @@ -194,9 +71,14 @@ if SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_ACPI_INTEL_MATCH tristate select SND_SOC_ACPI if ACPI + select SND_SOC_ACPI_INTEL_SDCA_QUIRKS # this option controls the compilation of ACPI matching tables and # helpers and is not meant to be selected by the user. +config SND_SOC_ACPI_INTEL_SDCA_QUIRKS + tristate + select SND_SOC_SDCA if ACPI + endif ## SND_SOC_INTEL_SST_TOPLEVEL || SND_SOC_SOF_INTEL_TOPLEVEL config SND_SOC_INTEL_KEEMBAY @@ -214,6 +96,7 @@ config SND_SOC_INTEL_AVS depends on X86 || COMPILE_TEST depends on PCI depends on COMMON_CLK + select ACPI_NHLT if ACPI select SND_SOC_ACPI if ACPI select SND_SOC_TOPOLOGY select SND_SOC_HDA diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index d44b2652c707..8ecc7047d700 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_SND_SOC) += common/ # Platform Support obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += atom/ obj-$(CONFIG_SND_SOC_INTEL_CATPT) += catpt/ -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += skylake/ obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += keembay/ obj-$(CONFIG_SND_SOC_INTEL_AVS) += avs/ diff --git a/sound/soc/intel/atom/Makefile b/sound/soc/intel/atom/Makefile index c66f03f5d8d6..38e4876025c7 100644 --- a/sound/soc/intel/atom/Makefile +++ b/sound/soc/intel/atom/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-atom-hifi2-platform-objs := sst-mfld-platform-pcm.o \ +snd-soc-sst-atom-hifi2-platform-y := sst-mfld-platform-pcm.o \ sst-mfld-platform-compress.o \ sst-atom-controls.o diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 8652b4a20020..373d68b4cf88 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -812,7 +812,7 @@ static struct platform_driver sst_platform_driver = { .pm = &sst_platform_pm, }, .probe = sst_platform_probe, - .remove_new = sst_platform_remove, + .remove = sst_platform_remove, }; module_platform_driver(sst_platform_driver); diff --git a/sound/soc/intel/atom/sst/Makefile b/sound/soc/intel/atom/sst/Makefile index 5761d30a5f9d..16be0463424d 100644 --- a/sound/soc/intel/atom/sst/Makefile +++ b/sound/soc/intel/atom/sst/Makefile @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o -snd-intel-sst-pci-objs += sst_pci.o -snd-intel-sst-acpi-objs += sst_acpi.o +snd-intel-sst-core-y := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o +snd-intel-sst-pci-y += sst_pci.o +snd-intel-sst-acpi-y += sst_acpi.o obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM) += snd-intel-sst-core.o obj-$(CONFIG_SND_SST_ATOM_HIFI2_PLATFORM_PCI) += snd-intel-sst-pci.o diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 126903e126e4..c43946c5ecee 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -443,9 +443,6 @@ int sst_set_stream_param(int str_id, struct snd_sst_params *str_param); int sst_set_metadata(int str_id, char *params); int sst_get_stream(struct intel_sst_drv *ctx, struct snd_sst_params *str_param); -int sst_get_stream_allocated(struct intel_sst_drv *ctx, - struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld); int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, int str_id, bool partial_drain); int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, @@ -461,8 +458,6 @@ void sst_post_download_mrfld(struct intel_sst_drv *ctx); int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx); -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block); int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block); int sst_create_ipc_msg(struct ipc_post **arg, bool large); @@ -470,7 +465,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id); void sst_clean_stream(struct stream_info *stream); int intel_sst_register_compress(struct intel_sst_drv *sst); int intel_sst_remove_compress(struct intel_sst_drv *sst); -void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id); int sst_send_sync_msg(int ipc, int str_id); int sst_get_num_channel(struct snd_sst_params *str_param); int sst_get_sfreq(struct snd_sst_params *str_param); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 29d44c989e5f..257180630475 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -125,6 +125,28 @@ static const struct sst_res_info bytcr_res_info = { .acpi_ipc_irq_index = 0 }; +/* For "LPE0F28" ACPI device found on some Android factory OS models */ +static const struct sst_res_info lpe8086_res_info = { + .shim_offset = 0x140000, + .shim_size = 0x000100, + .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR, + .ssp0_offset = 0xa0000, + .ssp0_size = 0x1000, + .dma0_offset = 0x98000, + .dma0_size = 0x4000, + .dma1_offset = 0x9c000, + .dma1_size = 0x4000, + .iram_offset = 0x0c0000, + .iram_size = 0x14000, + .dram_offset = 0x100000, + .dram_size = 0x28000, + .mbox_offset = 0x144000, + .mbox_size = 0x1000, + .acpi_lpe_res_index = 1, + .acpi_ddr_index = 0, + .acpi_ipc_irq_index = 0 +}; + static struct sst_platform_info byt_rvp_platform_data = { .probe_data = &byt_fwparse_info, .ipc_info = &byt_ipc_info, @@ -268,10 +290,38 @@ static int sst_acpi_probe(struct platform_device *pdev) mach->pdata = &chv_platform_data; pdata = mach->pdata; - ret = kstrtouint(id->id, 16, &dev_id); - if (ret < 0) { - dev_err(dev, "Unique device id conversion error: %d\n", ret); - return ret; + if (!strcmp(id->id, "LPE0F28")) { + struct resource *rsrc; + + /* Use regular BYT SST PCI VID:PID */ + dev_id = 0x80860F28; + byt_rvp_platform_data.res_info = &lpe8086_res_info; + + /* + * The "LPE0F28" ACPI device has separate IO-mem resources for: + * DDR, SHIM, MBOX, IRAM, DRAM, CFG + * None of which covers the entire LPE base address range. + * lpe8086_res_info.acpi_lpe_res_index points to the SHIM. + * Patch this to cover the entire base address range as expected + * by sst_platform_get_resources(). + */ + rsrc = platform_get_resource(pdev, IORESOURCE_MEM, + pdata->res_info->acpi_lpe_res_index); + if (!rsrc) { + dev_err(dev, "Invalid SHIM base\n"); + return -EIO; + } + rsrc->start -= pdata->res_info->shim_offset; + rsrc->end = rsrc->start + 0x200000 - 1; + } else { + ret = kstrtouint(id->id, 16, &dev_id); + if (ret < 0) { + dev_err(dev, "Unique device id conversion error: %d\n", ret); + return ret; + } + + if (soc_intel_is_byt_cr(pdev)) + byt_rvp_platform_data.res_info = &bytcr_res_info; } dev_dbg(dev, "ACPI device id: %x\n", dev_id); @@ -280,11 +330,6 @@ static int sst_acpi_probe(struct platform_device *pdev) if (ret < 0) return ret; - if (soc_intel_is_byt_cr(pdev)) { - /* override resource info */ - byt_rvp_platform_data.res_info = &bytcr_res_info; - } - /* update machine parameters */ mach->mach_params.acpi_ipc_irq_index = pdata->res_info->acpi_ipc_irq_index; @@ -344,6 +389,7 @@ static void sst_acpi_remove(struct platform_device *pdev) } static const struct acpi_device_id sst_acpi_ids[] = { + { "LPE0F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines}, { "80860F28", (unsigned long)&snd_soc_acpi_intel_baytrail_machines}, { "808622A8", (unsigned long)&snd_soc_acpi_intel_cherrytrail_machines}, { }, @@ -358,7 +404,7 @@ static struct platform_driver sst_acpi_driver = { .pm = &intel_sst_pm, }, .probe = sst_acpi_probe, - .remove_new = sst_acpi_remove, + .remove = sst_acpi_remove, }; module_platform_driver(sst_acpi_driver); diff --git a/sound/soc/intel/atom/sst/sst_drv_interface.c b/sound/soc/intel/atom/sst/sst_drv_interface.c index dc31c2c8f54c..8bb27f86eb65 100644 --- a/sound/soc/intel/atom/sst/sst_drv_interface.c +++ b/sound/soc/intel/atom/sst/sst_drv_interface.c @@ -55,19 +55,6 @@ int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) return ret; } -int sst_get_stream_allocated(struct intel_sst_drv *ctx, - struct snd_sst_params *str_param, - struct snd_sst_lib_download **lib_dnld) -{ - int retval; - - retval = ctx->ops->alloc_stream(ctx, str_param); - if (retval > 0) - dev_dbg(ctx->dev, "Stream allocated %d\n", retval); - return retval; - -} - /* * sst_get_sfreq - this function returns the frequency of the stream * @@ -430,17 +417,6 @@ static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec) return 0; } -void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id) -{ - struct stream_info *stream; - - dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n", - str_id); - stream = &ctx->streams[str_id]; - if (stream->compr_cb) - stream->compr_cb(stream->compr_cb_param); -} - /* * sst_close_pcm_stream - Close PCM interface * diff --git a/sound/soc/intel/atom/sst/sst_pci.c b/sound/soc/intel/atom/sst/sst_pci.c index d1e64c3500be..22ae2d22f121 100644 --- a/sound/soc/intel/atom/sst/sst_pci.c +++ b/sound/soc/intel/atom/sst/sst_pci.c @@ -26,7 +26,7 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) int ddr_base, ret = 0; struct pci_dev *pci = ctx->pci; - ret = pci_request_regions(pci, SST_DRV_NAME); + ret = pcim_request_all_regions(pci, SST_DRV_NAME); if (ret) return ret; @@ -38,67 +38,57 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); if (!ctx->pdata->lib_info) { dev_err(ctx->dev, "lib_info pointer NULL\n"); - ret = -EINVAL; - goto do_release_regions; + return -EINVAL; } if (ddr_base != ctx->pdata->lib_info->mod_base) { dev_err(ctx->dev, "FW LSP DDR BASE does not match with IFWI\n"); - ret = -EINVAL; - goto do_release_regions; + return -EINVAL; } ctx->ddr_end = pci_resource_end(pci, 0); - ctx->ddr = pcim_iomap(pci, 0, - pci_resource_len(pci, 0)); - if (!ctx->ddr) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->ddr = pcim_iomap(pci, 0, 0); + if (!ctx->ddr) + return -ENOMEM; + dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr); } else { ctx->ddr = NULL; } /* SHIM */ ctx->shim_phy_add = pci_resource_start(pci, 1); - ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1)); - if (!ctx->shim) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->shim = pcim_iomap(pci, 1, 0); + if (!ctx->shim) + return -ENOMEM; + dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim); /* Shared SRAM */ ctx->mailbox_add = pci_resource_start(pci, 2); - ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2)); - if (!ctx->mailbox) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->mailbox = pcim_iomap(pci, 2, 0); + if (!ctx->mailbox) + return -ENOMEM; + dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox); /* IRAM */ ctx->iram_end = pci_resource_end(pci, 3); ctx->iram_base = pci_resource_start(pci, 3); - ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3)); - if (!ctx->iram) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->iram = pcim_iomap(pci, 3, 0); + if (!ctx->iram) + return -ENOMEM; + dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram); /* DRAM */ ctx->dram_end = pci_resource_end(pci, 4); ctx->dram_base = pci_resource_start(pci, 4); - ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4)); - if (!ctx->dram) { - ret = -EINVAL; - goto do_release_regions; - } + ctx->dram = pcim_iomap(pci, 4, 0); + if (!ctx->dram) + return -ENOMEM; + dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); -do_release_regions: - pci_release_regions(pci); - return ret; + return 0; } /* @@ -167,7 +157,6 @@ static void intel_sst_remove(struct pci_dev *pci) sst_context_cleanup(sst_drv_ctx); pci_dev_put(sst_drv_ctx->pci); - pci_release_regions(pci); pci_set_drvdata(pci, NULL); } diff --git a/sound/soc/intel/atom/sst/sst_pvt.c b/sound/soc/intel/atom/sst/sst_pvt.c index e6a5c18a7018..5d08f7d803f9 100644 --- a/sound/soc/intel/atom/sst/sst_pvt.c +++ b/sound/soc/intel/atom/sst/sst_pvt.c @@ -70,39 +70,6 @@ void sst_set_fw_state_locked( } /* - * sst_wait_interruptible - wait on event - * - * @sst_drv_ctx: Driver context - * @block: Driver block to wait on - * - * This function waits without a timeout (and is interruptable) for a - * given block event - */ -int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, - struct sst_block *block) -{ - int retval = 0; - - if (!wait_event_interruptible(sst_drv_ctx->wait_queue, - block->condition)) { - /* event wake */ - if (block->ret_code < 0) { - dev_err(sst_drv_ctx->dev, - "stream failed %d\n", block->ret_code); - retval = -EBUSY; - } else { - dev_dbg(sst_drv_ctx->dev, "event up\n"); - retval = 0; - } - } else { - dev_err(sst_drv_ctx->dev, "signal interrupted\n"); - retval = -EINTR; - } - return retval; - -} - -/* * sst_wait_timeout - wait on event for timeout * * @sst_drv_ctx: Driver context diff --git a/sound/soc/intel/avs/Makefile b/sound/soc/intel/avs/Makefile index 5480500337f8..576dc0da381d 100644 --- a/sound/soc/intel/avs/Makefile +++ b/sound/soc/intel/avs/Makefile @@ -1,17 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ - topology.o path.o pcm.o board_selection.o control.o \ - sysfs.o -snd-soc-avs-objs += cldma.o -snd-soc-avs-objs += skl.o apl.o cnl.o icl.o tgl.o +snd-soc-avs-y := dsp.o ipc.o messages.o utils.o core.o loader.o \ + topology.o path.o pcm.o board_selection.o control.o \ + sysfs.o +snd-soc-avs-y += cldma.o +snd-soc-avs-y += skl.o apl.o cnl.o icl.o tgl.o mtl.o lnl.o ptl.o -snd-soc-avs-objs += trace.o +snd-soc-avs-y += trace.o # tell define_trace.h where to find the trace header CFLAGS_trace.o := -I$(src) ifneq ($(CONFIG_DEBUG_FS),) -snd-soc-avs-objs += probes.o debugfs.o +snd-soc-avs-y += probes.o debugfs.o endif obj-$(CONFIG_SND_SOC_INTEL_AVS) += snd-soc-avs.o diff --git a/sound/soc/intel/avs/apl.c b/sound/soc/intel/avs/apl.c index c21ecaef9eba..3dccf0a57a3a 100644 --- a/sound/soc/intel/avs/apl.c +++ b/sound/soc/intel/avs/apl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -8,11 +8,29 @@ #include <linux/devcoredump.h> #include <linux/slab.h> +#include <sound/hdaudio_ext.h> #include "avs.h" #include "messages.h" #include "path.h" +#include "registers.h" #include "topology.h" +static irqreturn_t avs_apl_dsp_interrupt(struct avs_dev *adev) +{ + u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS); + irqreturn_t ret = IRQ_NONE; + + if (adspis == UINT_MAX) + return ret; + + if (adspis & AVS_ADSP_ADSPIS_IPC) { + avs_skl_ipc_interrupt(adev); + ret = IRQ_HANDLED; + } + + return ret; +} + #ifdef CONFIG_DEBUG_FS int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, u32 fifo_full_period, unsigned long resource_mask, u32 *priorities) @@ -108,7 +126,7 @@ int avs_apl_coredump(struct avs_dev *adev, union avs_notify_msg *msg) struct avs_apl_log_buffer_layout layout; void __iomem *addr, *buf; size_t dump_size; - u16 offset = 0; + u32 offset = 0; u8 *dump, *pos; dump_size = AVS_FW_REGS_SIZE + msg->ext.coredump.stack_dump_size; @@ -237,8 +255,7 @@ const struct avs_dsp_ops avs_apl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_skl_irq_thread, + .dsp_interrupt = avs_apl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_hda_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index f80f79415344..4c096afc5848 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2022 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -46,12 +46,12 @@ struct avs_dsp_ops { int (* const power)(struct avs_dev *, u32, bool); int (* const reset)(struct avs_dev *, u32, bool); int (* const stall)(struct avs_dev *, u32, bool); - irqreturn_t (* const irq_handler)(struct avs_dev *); - irqreturn_t (* const irq_thread)(struct avs_dev *); + irqreturn_t (* const dsp_interrupt)(struct avs_dev *); void (* const int_control)(struct avs_dev *, bool); int (* const load_basefw)(struct avs_dev *, struct firmware *); int (* const load_lib)(struct avs_dev *, struct firmware *, u32); int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32); + int (* const config_basefw)(struct avs_dev *); int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long, u32 *); int (* const log_buffer_offset)(struct avs_dev *, u32); @@ -69,9 +69,12 @@ extern const struct avs_dsp_ops avs_apl_dsp_ops; extern const struct avs_dsp_ops avs_cnl_dsp_ops; extern const struct avs_dsp_ops avs_icl_dsp_ops; extern const struct avs_dsp_ops avs_tgl_dsp_ops; +extern const struct avs_dsp_ops avs_ptl_dsp_ops; #define AVS_PLATATTR_CLDMA BIT_ULL(0) #define AVS_PLATATTR_IMR BIT_ULL(1) +#define AVS_PLATATTR_ACE BIT_ULL(2) +#define AVS_PLATATTR_ALTHDA BIT_ULL(3) #define avs_platattr_test(adev, attr) \ ((adev)->spec->attributes & AVS_PLATATTR_##attr) @@ -79,7 +82,6 @@ extern const struct avs_dsp_ops avs_tgl_dsp_ops; struct avs_sram_spec { const u32 base_offset; const u32 window_size; - const u32 rom_status_offset; }; struct avs_hipc_spec { @@ -91,6 +93,7 @@ struct avs_hipc_spec { const u32 rsp_offset; const u32 rsp_busy_mask; const u32 ctl_offset; + const u32 sts_offset; }; /* Platform specific descriptor */ @@ -107,7 +110,7 @@ struct avs_spec { }; struct avs_fw_entry { - char *name; + const char *name; const struct firmware *fw; struct list_head node; @@ -151,7 +154,6 @@ struct avs_dev { struct completion fw_ready; struct work_struct probe_work; - struct nhlt_acpi_table *nhlt; struct list_head comp_list; struct mutex comp_list_mutex; struct list_head path_list; @@ -245,7 +247,6 @@ struct avs_ipc { #define AVS_IPC_RET(ret) \ (((ret) <= 0) ? (ret) : -AVS_EIPC) -irqreturn_t avs_irq_handler(struct avs_dev *adev); void avs_dsp_process_response(struct avs_dev *adev, u64 header); int avs_dsp_send_msg_timeout(struct avs_dev *adev, struct avs_ipc_msg *request, struct avs_ipc_msg *reply, int timeout, const char *name); @@ -267,8 +268,14 @@ void avs_ipc_block(struct avs_ipc *ipc); int avs_dsp_disable_d0ix(struct avs_dev *adev); int avs_dsp_enable_d0ix(struct avs_dev *adev); -irqreturn_t avs_skl_irq_thread(struct avs_dev *adev); -irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev); +int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power); +int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power); +int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); +int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall); +void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable); +void avs_skl_ipc_interrupt(struct avs_dev *adev); +irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev); +irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev); int avs_apl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, u32 fifo_full_period, unsigned long resource_mask, u32 *priorities); int avs_icl_enable_logs(struct avs_dev *adev, enum avs_log_enable enable, u32 aging_period, @@ -342,7 +349,7 @@ struct avs_soc_component { extern const struct snd_soc_dai_ops avs_dai_fe_ops; int avs_soc_component_register(struct device *dev, const char *name, - const struct snd_soc_component_driver *drv, + struct snd_soc_component_driver *drv, struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais); int avs_dmic_platform_register(struct avs_dev *adev, const char *name); int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, @@ -381,6 +388,7 @@ struct avs_apl_log_buffer_layout { u32 write_ptr; u8 buffer[]; } __packed; +static_assert(sizeof(struct avs_apl_log_buffer_layout) == 8); #define avs_apl_log_payload_size(adev) \ (avs_log_buffer_size(adev) - sizeof(struct avs_apl_log_buffer_layout)) diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 8360ce557401..636315060eb4 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -10,17 +10,22 @@ #include <linux/module.h> #include <linux/dmi.h> #include <linux/pci.h> +#include <acpi/nhlt.h> #include <linux/platform_device.h> #include <sound/hda_codec.h> #include <sound/hda_register.h> -#include <sound/intel-nhlt.h> #include <sound/soc-acpi.h> #include <sound/soc-component.h> #include "avs.h" +#include "utils.h" -static bool i2s_test; -module_param(i2s_test, bool, 0444); -MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards"); +static char *i2s_test; +module_param(i2s_test, charp, 0444); +MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port"); + +bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE); +module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444); +MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes"); static const struct dmi_system_id kbl_dmi_table[] = { { @@ -141,7 +146,7 @@ static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = { .mach_params = { .i2s_link_mask = AVS_SSP(0), }, - .pdata = (unsigned long[]){ 0x2, 0, 0, 0, 0, 0 }, /* SSP0 TDMs */ + .pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } }, .tplg_filename = "rt5514-tplg.bin", }, { @@ -202,7 +207,9 @@ static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = { .mach_params = { .i2s_link_mask = AVS_SSP_RANGE(0, 5), }, - .pdata = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }, /* SSP2 TDMs */ + .pdata = (struct avs_mach_pdata[]){ { + .tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 } + } }, .tplg_filename = "tdf8532-tplg.bin", }, { @@ -312,50 +319,16 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { {}, }; -static struct snd_soc_acpi_mach avs_test_i2s_machines[] = { - { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(0), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, - { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(1), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, - { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(2), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, +static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = { { - .drv_name = "avs_i2s_test", + .id = "PCM3168A", + .drv_name = "avs_pcm3168a", .mach_params = { - .i2s_link_mask = AVS_SSP(3), + .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2), }, - .tplg_filename = "i2s-test-tplg.bin", + .tplg_filename = "pcm3168a-tplg.bin", }, - { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(4), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, - { - .drv_name = "avs_i2s_test", - .mach_params = { - .i2s_link_mask = AVS_SSP(5), - }, - .tplg_filename = "i2s-test-tplg.bin", - }, - /* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */ + {} }; struct avs_acpi_boards { @@ -378,10 +351,12 @@ static const struct avs_acpi_boards i2s_boards[] = { AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines), AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines), AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines), - AVS_MACH_ENTRY(HDA_RPL_M, avs_tgl_i2s_machines), - {}, + AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines), + AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines), + { }, }; static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev) @@ -432,10 +407,10 @@ static int avs_register_dmic_board(struct avs_dev *adev) { struct platform_device *codec, *board; struct snd_soc_acpi_mach mach = {{0}}; + struct avs_mach_pdata *pdata; int ret; - if (!adev->nhlt || - !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) { + if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) { dev_dbg(adev->dev, "no DMIC endpoints present\n"); return 0; } @@ -456,6 +431,11 @@ static int avs_register_dmic_board(struct avs_dev *adev) if (ret < 0) return ret; + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + mach.pdata = pdata; mach.tplg_filename = "dmic-tplg.bin"; mach.mach_params.platform = "dmic-platform"; @@ -478,9 +458,11 @@ static int avs_register_dmic_board(struct avs_dev *adev) static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach) { struct platform_device *board; + struct avs_mach_pdata *pdata; int num_ssps; char *name; int ret; + int uid; num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; if (fls(mach->mach_params.i2s_link_mask) > num_ssps) { @@ -490,18 +472,29 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach return -ENODEV; } - name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, - mach->mach_params.i2s_link_mask); + pdata = mach->pdata; + if (!pdata) + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + mach->pdata = pdata; + + uid = mach->mach_params.i2s_link_mask; + if (avs_mach_singular_ssp(mach)) + uid = (uid << AVS_CHANNELS_MAX) + avs_mach_ssp_tdm(mach, avs_mach_ssp_port(mach)); + + name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name, uid); if (!name) return -ENOMEM; - ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata); + ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, pdata->tdms); if (ret < 0) return ret; mach->mach_params.platform = name; - board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask, + board = platform_device_register_data(NULL, mach->drv_name, uid, (const void *)mach, sizeof(*mach)); if (IS_ERR(board)) { dev_err(adev->dev, "ssp board register failed\n"); @@ -517,35 +510,82 @@ static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach return 0; } -static int avs_register_i2s_boards(struct avs_dev *adev) +static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot) { - const struct avs_acpi_boards *boards; struct snd_soc_acpi_mach *mach; + int tdm_mask = BIT(tdm_slot); + unsigned long *tdm_cfg; + char *tplg_name; int ret; - if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) { - dev_dbg(adev->dev, "no I2S endpoints present\n"); - return 0; + mach = devm_kzalloc(adev->dev, sizeof(*mach), GFP_KERNEL); + tdm_cfg = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(unsigned long), GFP_KERNEL); + tplg_name = devm_kasprintf(adev->dev, GFP_KERNEL, AVS_STRING_FMT("i2s", "-test-tplg.bin", + ssp_port, tdm_slot)); + if (!mach || !tdm_cfg || !tplg_name) + return -ENOMEM; + + mach->drv_name = "avs_i2s_test"; + mach->mach_params.i2s_link_mask = AVS_SSP(ssp_port); + tdm_cfg[ssp_port] = tdm_mask; + mach->pdata = tdm_cfg; + mach->tplg_filename = tplg_name; + + ret = avs_register_i2s_board(adev, mach); + if (ret < 0) { + dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret); + return ret; } - if (i2s_test) { - int i, num_ssps; + return 0; +} + +static int avs_register_i2s_test_boards(struct avs_dev *adev) +{ + int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count; + int ssp_port, tdm_slot, ret; + unsigned long tdm_slots; + u32 *array, num_elems; - num_ssps = adev->hw_cfg.i2s_caps.ctrl_count; - /* constrain just in case FW says there can be more SSPs than possible */ - num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps); + ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array); + if (ret < 0) { + dev_err(adev->dev, "failed to parse i2s_test parameter\n"); + return ret; + } - mach = avs_test_i2s_machines; + num_elems = *array; + if (num_elems > max_ssps) { + dev_err(adev->dev, "board supports only %d SSP, %d specified\n", + max_ssps, num_elems); + return -EINVAL; + } - for (i = 0; i < num_ssps; i++) { - ret = avs_register_i2s_board(adev, &mach[i]); - if (ret < 0) - dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, - ret); + for (ssp_port = 0; ssp_port < num_elems; ssp_port++) { + tdm_slots = array[1 + ssp_port]; + for_each_set_bit(tdm_slot, &tdm_slots, 16) { + ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot); + if (ret) + return ret; } + } + + return 0; +} + +static int avs_register_i2s_boards(struct avs_dev *adev) +{ + const struct avs_acpi_boards *boards; + struct snd_soc_acpi_mach *mach; + int ret; + + if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) { + dev_dbg(adev->dev, "no I2S endpoints present\n"); return 0; } + if (i2s_test) + return avs_register_i2s_test_boards(adev); + boards = avs_get_i2s_boards(adev); if (!boards) { dev_dbg(adev->dev, "no I2S endpoints supported\n"); @@ -572,6 +612,7 @@ static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) { struct snd_soc_acpi_mach mach = {{0}}; struct platform_device *board; + struct avs_mach_pdata *pdata; struct hdac_device *hdev = &codec->core; char *pname; int ret, id; @@ -580,11 +621,17 @@ static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec) if (!pname) return -ENOMEM; + pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + pdata->obsolete_card_names = obsolete_card_names; + pdata->codec = codec; + ret = avs_hda_platform_register(adev, pname); if (ret < 0) return ret; - mach.pdata = codec; + mach.pdata = pdata; mach.mach_params.platform = pname; mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin", hdev->vendor_id); diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index 00b0f6c176d6..8b654181004e 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -4,6 +4,14 @@ menu "Intel AVS Machine drivers" comment "Available DSP configurations" +config SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE + bool "Use obsolete card names" + default n + help + Use obsolete names for some of avs cards. This option should be + used if your system depends on old card names, for example having + not up to date UCM files. + config SND_SOC_INTEL_AVS_MACH_DA7219 tristate "da7219 I2S board" depends on I2C @@ -87,6 +95,16 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_PCM3168A + tristate "pcm3168a I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_PCM3168A_I2C + help + This adds support for AVS with PCM3168A I2C codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_AVS_MACH_PROBE tristate "Probing (data) board" depends on DEBUG_FS diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index 0ff21d55be24..a95256b94dc8 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -1,22 +1,23 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-avs-da7219-objs := da7219.o -snd-soc-avs-dmic-objs := dmic.o -snd-soc-avs-es8336-objs := es8336.o -snd-soc-avs-hdaudio-objs := hdaudio.o -snd-soc-avs-i2s-test-objs := i2s_test.o -snd-soc-avs-max98927-objs := max98927.o -snd-soc-avs-max98357a-objs := max98357a.o -snd-soc-avs-max98373-objs := max98373.o -snd-soc-avs-nau8825-objs := nau8825.o -snd-soc-avs-probe-objs := probe.o -snd-soc-avs-rt274-objs := rt274.o -snd-soc-avs-rt286-objs := rt286.o -snd-soc-avs-rt298-objs := rt298.o -snd-soc-avs-rt5514-objs := rt5514.o -snd-soc-avs-rt5663-objs := rt5663.o -snd-soc-avs-rt5682-objs := rt5682.o -snd-soc-avs-ssm4567-objs := ssm4567.o +snd-soc-avs-da7219-y := da7219.o +snd-soc-avs-dmic-y := dmic.o +snd-soc-avs-es8336-y := es8336.o +snd-soc-avs-hdaudio-y := hdaudio.o +snd-soc-avs-i2s-test-y := i2s_test.o +snd-soc-avs-max98927-y := max98927.o +snd-soc-avs-max98357a-y := max98357a.o +snd-soc-avs-max98373-y := max98373.o +snd-soc-avs-nau8825-y := nau8825.o +snd-soc-avs-pcm3168a-y := pcm3168a.o +snd-soc-avs-probe-y := probe.o +snd-soc-avs-rt274-y := rt274.o +snd-soc-avs-rt286-y := rt286.o +snd-soc-avs-rt298-y := rt298.o +snd-soc-avs-rt5514-y := rt5514.o +snd-soc-avs-rt5663-y := rt5663.o +snd-soc-avs-rt5682-y := rt5682.o +snd-soc-avs-ssm4567-y := ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DA7219) += snd-soc-avs-da7219.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_DMIC) += snd-soc-avs-dmic.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PCM3168A) += snd-soc-avs-pcm3168a.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index fc072dc58968..3ef0db254142 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // @@ -113,7 +113,8 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) } num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -197,39 +198,23 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_da7219_be_fixup; dl->init = avs_da7219_codec_init; dl->exit = avs_da7219_codec_exit; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; return 0; } -static int avs_card_suspend_pre(struct snd_soc_card *card) -{ - struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME); - - return snd_soc_component_set_jack(codec_dai->component, NULL, NULL); -} - -static int avs_card_resume_post(struct snd_soc_card *card) -{ - struct snd_soc_dai *codec_dai = snd_soc_card_get_codec_dai(card, DA7219_DAI_NAME); - struct snd_soc_jack *jack = snd_soc_card_get_drvdata(card); - - return snd_soc_component_set_jack(codec_dai->component, jack, NULL); -} - static int avs_da7219_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -238,6 +223,7 @@ static int avs_da7219_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -254,11 +240,14 @@ static int avs_da7219_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_da7219"; + if (pdata->obsolete_card_names) { + card->name = "avs_da7219"; + } else { + card->driver_name = "avs_da7219"; + card->long_name = card->name = "AVS I2S DA7219"; + } card->dev = dev; card->owner = THIS_MODULE; - card->suspend_pre = avs_card_suspend_pre; - card->resume_post = avs_card_resume_post; card->dai_link = dai_link; card->num_links = 1; card->controls = card_controls; @@ -274,7 +263,7 @@ static int avs_da7219_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_da7219_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/dmic.c b/sound/soc/intel/avs/boards/dmic.c index d9e5e85f5233..a1448a98874d 100644 --- a/sound/soc/intel/avs/boards/dmic.c +++ b/sound/soc/intel/avs/boards/dmic.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -10,6 +10,7 @@ #include <linux/module.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include "../utils.h" SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); SND_SOC_DAILINK_DEF(dmic_wov_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC WoV Pin"))); @@ -22,7 +23,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC", .id = 0, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), @@ -30,7 +31,7 @@ static struct snd_soc_dai_link card_dai_links[] = { { .name = "DMIC WoV", .id = 1, - .dpcm_capture = 1, + .capture_only = 1, .nonatomic = 1, .no_pcm = 1, .ignore_suspend = 1, @@ -49,17 +50,24 @@ static const struct snd_soc_dapm_route card_routes[] = { static int avs_dmic_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; int ret; mach = dev_get_platdata(dev); + pdata = mach->pdata; card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) return -ENOMEM; - card->name = "avs_dmic"; + if (pdata->obsolete_card_names) { + card->name = "avs_dmic"; + } else { + card->driver_name = "avs_dmic"; + card->long_name = card->name = "AVS DMIC"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = card_dai_links; @@ -74,7 +82,7 @@ static int avs_dmic_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_dmic_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 5c90a6007577..1955f2d383c5 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -18,7 +18,7 @@ #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> -#include <asm/intel-family.h> +#include <asm/cpu_device_id.h> #include "../utils.h" #define ES8336_CODEC_DAI "ES8316 HiFi" @@ -85,7 +85,7 @@ static const struct snd_kcontrol_new card_controls[] = { SOC_DAPM_PIN_SWITCH("Internal Mic"), }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone", .mask = SND_JACK_HEADPHONE, @@ -109,11 +109,12 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) data = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; - ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0, &data->jack, pins, num_pins); if (ret) return ret; @@ -153,9 +154,9 @@ static int avs_es8336_hw_params(struct snd_pcm_substream *substream, int clk_freq; int ret; - switch (boot_cpu_data.x86_model) { - case INTEL_FAM6_KABYLAKE_L: - case INTEL_FAM6_KABYLAKE: + switch (boot_cpu_data.x86_vfm) { + case INTEL_KABYLAKE_L: + case INTEL_KABYLAKE: clk_freq = 24000000; break; default: @@ -233,8 +234,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_es8336_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -260,6 +259,7 @@ static int avs_es8336_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct avs_card_drvdata *data; struct snd_soc_card *card; struct device *dev = &pdev->dev; @@ -268,6 +268,7 @@ static int avs_es8336_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -284,7 +285,12 @@ static int avs_es8336_probe(struct platform_device *pdev) if (!data || !card) return -ENOMEM; - card->name = "avs_es8336"; + if (pdata->obsolete_card_names) { + card->name = "avs_es8336"; + } else { + card->driver_name = "avs_es8336"; + card->long_name = card->name = "AVS I2S ES8336"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -304,7 +310,7 @@ static int avs_es8336_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_es8336_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/hdaudio.c b/sound/soc/intel/avs/boards/hdaudio.c index 79b4aca41333..19b2255a8ac3 100644 --- a/sound/soc/intel/avs/boards/hdaudio.c +++ b/sound/soc/intel/avs/boards/hdaudio.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -13,6 +13,7 @@ #include <sound/soc.h> #include <sound/soc-acpi.h> #include "../../../codecs/hda.h" +#include "../utils.h" static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count, const char *platform_name, struct snd_soc_dai_link **links) @@ -39,8 +40,6 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int dl[i].id = i; dl[i].nonatomic = 1; dl[i].no_pcm = 1; - dl[i].dpcm_playback = 1; - dl[i].dpcm_capture = 1; dl[i].platforms = platform; dl[i].num_platforms = 1; dl[i].ignore_pmdown_time = 1; @@ -54,7 +53,7 @@ static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int if (!dl[i].cpus->dai_name) return -ENOMEM; - dl[i].codecs->name = devm_kstrdup(dev, cname, GFP_KERNEL); + dl[i].codecs->name = devm_kstrdup_const(dev, cname, GFP_KERNEL); if (!dl[i].codecs->name) return -ENOMEM; @@ -97,7 +96,8 @@ avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx) static int avs_card_late_probe(struct snd_soc_card *card) { struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); - struct hda_codec *codec = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + struct hda_codec *codec = pdata->codec; struct hda_pcm *hpcm; /* Topology pcm indexing is 1-based */ int i = 1; @@ -126,6 +126,7 @@ static int avs_card_late_probe(struct snd_soc_card *card) static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) { struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_dai_link *links = NULL; struct snd_soc_card *card = rtm->card; struct hda_codec *codec; @@ -133,7 +134,8 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) int ret, pcm_count = 0; mach = dev_get_platdata(card->dev); - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; if (list_empty(&codec->pcm_list_head)) return -EINVAL; @@ -155,13 +157,11 @@ static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm) return 0; } -static struct snd_soc_dai_link probing_link = { +static const struct snd_soc_dai_link probing_link = { .name = "probing-LINK", .id = -1, .nonatomic = 1, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .cpus = &snd_soc_dummy_dlc, .num_cpus = 1, .init = avs_probing_link_init, @@ -171,12 +171,14 @@ static int avs_hdaudio_probe(struct platform_device *pdev) { struct snd_soc_dai_link *binder; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; struct hda_codec *codec; mach = dev_get_platdata(dev); - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; /* codec may be unloaded before card's probe() fires */ if (!device_is_registered(&codec->core.dev)) @@ -191,7 +193,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (!binder->platforms || !binder->codecs) return -ENOMEM; - binder->codecs->name = devm_kstrdup(dev, dev_name(&codec->core.dev), GFP_KERNEL); + binder->codecs->name = devm_kstrdup_const(dev, dev_name(&codec->core.dev), GFP_KERNEL); if (!binder->codecs->name) return -ENOMEM; @@ -204,7 +206,16 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = binder->codecs->name; + if (pdata->obsolete_card_names) { + card->name = binder->codecs->name; + } else { + card->driver_name = "avs_hdaudio"; + if (hda_codec_is_display(codec)) + card->long_name = card->name = "AVS HDMI"; + else + card->long_name = card->name = "AVS HD-Audio"; + } + card->dev = dev; card->owner = THIS_MODULE; card->dai_link = binder; @@ -213,7 +224,7 @@ static int avs_hdaudio_probe(struct platform_device *pdev) if (hda_codec_is_display(codec)) card->late_probe = avs_card_late_probe; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_hdaudio_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/i2s_test.c b/sound/soc/intel/avs/boards/i2s_test.c index 027373d6a16d..f7b6d7715738 100644 --- a/sound/soc/intel/avs/boards/i2s_test.c +++ b/sound/soc/intel/avs/boards/i2s_test.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -46,88 +46,25 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->id = 0; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; return 0; } -static int avs_create_dapm_routes(struct device *dev, int ssp_port, int tdm_slot, - struct snd_soc_dapm_route **routes, int *num_routes) -{ - struct snd_soc_dapm_route *dr; - const int num_dr = 2; - - dr = devm_kcalloc(dev, num_dr, sizeof(*dr), GFP_KERNEL); - if (!dr) - return -ENOMEM; - - dr[0].sink = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot)); - dr[0].source = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", " Tx", ssp_port, tdm_slot)); - if (!dr[0].sink || !dr[0].source) - return -ENOMEM; - - dr[1].sink = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", " Rx", ssp_port, tdm_slot)); - dr[1].source = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot)); - if (!dr[1].sink || !dr[1].source) - return -ENOMEM; - - *routes = dr; - *num_routes = num_dr; - - return 0; -} - -static int avs_create_dapm_widgets(struct device *dev, int ssp_port, int tdm_slot, - struct snd_soc_dapm_widget **widgets, int *num_widgets) -{ - struct snd_soc_dapm_widget *dw; - const int num_dw = 2; - - dw = devm_kcalloc(dev, num_dw, sizeof(*dw), GFP_KERNEL); - if (!dw) - return -ENOMEM; - - dw[0].id = snd_soc_dapm_hp; - dw[0].reg = SND_SOC_NOPM; - dw[0].name = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "pb", ssp_port, tdm_slot)); - if (!dw[0].name) - return -ENOMEM; - - dw[1].id = snd_soc_dapm_mic; - dw[1].reg = SND_SOC_NOPM; - dw[1].name = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "cp", ssp_port, tdm_slot)); - if (!dw[1].name) - return -ENOMEM; - - *widgets = dw; - *num_widgets = num_dw; - - return 0; -} - static int avs_i2s_test_probe(struct platform_device *pdev) { - struct snd_soc_dapm_widget *widgets; - struct snd_soc_dapm_route *routes; struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; - int num_routes, num_widgets; int ssp_port, tdm_slot, ret; mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; if (!avs_mach_singular_ssp(mach)) { dev_err(dev, "Invalid SSP configuration\n"); @@ -145,8 +82,15 @@ static int avs_i2s_test_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = devm_kasprintf(dev, GFP_KERNEL, - AVS_STRING_FMT("ssp", "-loopback", ssp_port, tdm_slot)); + if (pdata->obsolete_card_names) { + card->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("ssp", "-loopback", ssp_port, tdm_slot)); + } else { + card->driver_name = "avs_i2s_test"; + card->long_name = card->name = devm_kasprintf(dev, GFP_KERNEL, + AVS_STRING_FMT("AVS I2S TEST-", "", + ssp_port, tdm_slot)); + } if (!card->name) return -ENOMEM; @@ -156,33 +100,17 @@ static int avs_i2s_test_probe(struct platform_device *pdev) return ret; } - ret = avs_create_dapm_routes(dev, ssp_port, tdm_slot, &routes, &num_routes); - if (ret) { - dev_err(dev, "Failed to create dapm routes: %d\n", ret); - return ret; - } - - ret = avs_create_dapm_widgets(dev, ssp_port, tdm_slot, &widgets, &num_widgets); - if (ret) { - dev_err(dev, "Failed to create dapm widgets: %d\n", ret); - return ret; - } - card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; card->num_links = 1; - card->dapm_routes = routes; - card->num_dapm_routes = num_routes; - card->dapm_widgets = widgets; - card->num_dapm_widgets = num_widgets; card->fully_routed = true; ret = snd_soc_fixup_dai_links_platform_name(card, pname); if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_i2s_test_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 1ff85e4d8e16..72053f83e98b 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -78,11 +78,11 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_max98357a_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_playback = 1; + dl->playback_only = 1; *dai_link = dl; @@ -93,6 +93,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; @@ -100,6 +101,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -115,7 +117,12 @@ static int avs_max98357a_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98357a"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98357a"; + } else { + card->driver_name = "avs_max98357a"; + card->long_name = card->name = "AVS I2S MAX98357A"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -132,7 +139,7 @@ static int avs_max98357a_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98357a_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index 8d31586b73ea..cdba1c3ee20b 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -111,7 +111,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; @@ -134,8 +134,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_max98373_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98373_ops; @@ -148,6 +146,7 @@ static int avs_max98373_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; @@ -155,6 +154,7 @@ static int avs_max98373_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -170,7 +170,12 @@ static int avs_max98373_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98373"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98373"; + } else { + card->driver_name = "avs_max98373"; + card->long_name = card->name = "AVS I2S MAX98373"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -189,7 +194,7 @@ static int avs_max98373_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98373_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index 572ec58073d0..a68e227044c5 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -108,7 +108,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; @@ -127,12 +127,10 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_max98927_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; dl->ops = &avs_max98927_ops; @@ -145,6 +143,7 @@ static int avs_max98927_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; @@ -152,6 +151,7 @@ static int avs_max98927_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -167,7 +167,12 @@ static int avs_max98927_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_max98927"; + if (pdata->obsolete_card_names) { + card->name = "avs_max98927"; + } else { + card->driver_name = "avs_max98927"; + card->long_name = card->name = "AVS I2S MAX98927"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -186,7 +191,7 @@ static int avs_max98927_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_max98927_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index 55db75efae41..3fb1a5d07ae1 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -67,7 +67,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "Headset Mic", NULL, "Platform Clock" }, }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -88,7 +88,8 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -96,7 +97,7 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime) * 4 buttons here map to the google Reference headset. * The use of these buttons can be decided by the user space. */ - ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0 | + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, jack, pins, num_pins); if (ret) @@ -203,15 +204,13 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_nau8825_codec_init; dl->exit = avs_nau8825_codec_exit; dl->be_hw_params_fixup = avs_nau8825_be_fixup; dl->ops = &avs_nau8825_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -247,6 +246,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -255,6 +255,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -271,7 +272,12 @@ static int avs_nau8825_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_nau8825"; + if (pdata->obsolete_card_names) { + card->name = "avs_nau8825"; + } else { + card->driver_name = "avs_nau8825"; + card->long_name = card->name = "AVS I2S NAU8825"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -291,7 +297,7 @@ static int avs_nau8825_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_nau8825_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c new file mode 100644 index 000000000000..b5bebadbbcb2 --- /dev/null +++ b/sound/soc/intel/avs/boards/pcm3168a.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2024-2025 Intel Corporation +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "../utils.h" + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL), + SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL), + SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL), + SND_SOC_DAPM_LINE("CPB Line Out", NULL), + SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL), + SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL), + SND_SOC_DAPM_LINE("CPB Line In", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + { "CPB Stereo HP 1", NULL, "AOUT1L" }, + { "CPB Stereo HP 1", NULL, "AOUT1R" }, + { "CPB Stereo HP 2", NULL, "AOUT2L" }, + { "CPB Stereo HP 2", NULL, "AOUT2R" }, + { "CPB Stereo HP 3", NULL, "AOUT3L" }, + { "CPB Stereo HP 3", NULL, "AOUT3R" }, + { "CPB Line Out", NULL, "AOUT4L" }, + { "CPB Line Out", NULL, "AOUT4R" }, + + { "AIN1L", NULL, "CPB Stereo Mic 1" }, + { "AIN1R", NULL, "CPB Stereo Mic 1" }, + { "AIN2L", NULL, "CPB Stereo Mic 2" }, + { "AIN2R", NULL, "CPB Stereo Mic 2" }, + { "AIN3L", NULL, "CPB Line In" }, + { "AIN3R", NULL, "CPB Line In" }, +}; + +static int avs_pcm3168a_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* Set SSP to 24 bit. */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +SND_SOC_DAILINK_DEF(pcm3168a_dac, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-dac"))); +SND_SOC_DAILINK_DEF(pcm3168a_adc, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-adc"))); +SND_SOC_DAILINK_DEF(cpu_ssp0, DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); +SND_SOC_DAILINK_DEF(cpu_ssp2, DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); + +static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + const int num_dl = 2; + + dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = dev_name(dev); + dl[0].num_cpus = 1; + dl[0].num_codecs = 1; + dl[0].platforms = platform; + dl[0].num_platforms = 1; + dl[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + dl[0].be_hw_params_fixup = avs_pcm3168a_be_fixup; + dl[0].nonatomic = 1; + dl[0].no_pcm = 1; + memcpy(&dl[1], &dl[0], sizeof(*dl)); + + dl[0].name = "SSP0-Codec-dac"; + dl[0].cpus = cpu_ssp0; + dl[0].codecs = pcm3168a_dac; + dl[1].name = "SSP2-Codec-adc"; + dl[1].cpus = cpu_ssp2; + dl[1].codecs = pcm3168a_adc; + + *links = dl; + *num_links = num_dl; + return 0; +} + +static int avs_pcm3168a_probe(struct platform_device *pdev) +{ + struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; + struct device *dev = &pdev->dev; + struct snd_soc_card *card; + int ret; + + mach = dev_get_platdata(dev); + pdata = mach->pdata; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links); + if (ret) + return ret; + + if (pdata->obsolete_card_names) { + card->name = "avs_pcm3168a"; + } else { + card->driver_name = "avs_pcm3168a"; + card->long_name = card->name = "AVS I2S PCM3168A"; + } + card->dev = dev; + card->owner = THIS_MODULE; + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + + return devm_snd_soc_register_deferrable_card(dev, card); +} + +static const struct platform_device_id avs_pcm3168a_driver_ids[] = { + { + .name = "avs_pcm3168a", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids); + +static struct platform_driver avs_pcm3168a_driver = { + .probe = avs_pcm3168a_probe, + .driver = { + .name = "avs_pcm3168a", + .pm = &snd_soc_pm_ops, + }, + .id_table = avs_pcm3168a_driver_ids, +}; + +module_platform_driver(avs_pcm3168a_driver); + +MODULE_DESCRIPTION("Intel pcm3168a machine driver"); +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/probe.c b/sound/soc/intel/avs/boards/probe.c index 8be6887bbc6e..06c1f19f27aa 100644 --- a/sound/soc/intel/avs/boards/probe.c +++ b/sound/soc/intel/avs/boards/probe.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -36,7 +36,8 @@ static int avs_probe_mb_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_probe_mb"; + card->driver_name = "avs_probe_mb"; + card->long_name = card->name = "AVS PROBE"; card->dev = dev; card->owner = THIS_MODULE; card->dai_link = probe_mb_dai_links; @@ -47,7 +48,7 @@ static int avs_probe_mb_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_probe_mb_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 1cf524216087..ec5382925157 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -75,7 +75,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { {"MIC", NULL, "Platform Clock"}, }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -98,11 +98,13 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; - ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET, jack, pins, num_pins); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET, jack, pins, + num_pins); if (ret) return ret; @@ -177,14 +179,12 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt274_codec_init; dl->exit = avs_rt274_codec_exit; dl->be_hw_params_fixup = avs_rt274_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -210,6 +210,7 @@ static int avs_rt274_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -218,6 +219,7 @@ static int avs_rt274_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -234,7 +236,12 @@ static int avs_rt274_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt274"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt274"; + } else { + card->driver_name = "avs_rt274"; + card->long_name = card->name = "AVS I2S ALC274"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -254,7 +261,7 @@ static int avs_rt274_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt274_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index 4740bba10570..2566e971ce1c 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -38,7 +38,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { {"Speaker", NULL, "SPOL"}, }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -59,12 +59,13 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; - ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack, - pins, num_pins); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0, + jack, pins, num_pins); if (ret) return ret; @@ -146,15 +147,13 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt286_codec_init; dl->exit = avs_rt286_codec_exit; dl->be_hw_params_fixup = avs_rt286_be_fixup; dl->ops = &avs_rt286_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -180,6 +179,7 @@ static int avs_rt286_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -188,6 +188,7 @@ static int avs_rt286_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -205,7 +206,12 @@ static int avs_rt286_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt286"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt286"; + } else { + card->driver_name = "avs_rt286"; + card->long_name = card->name = "AVS I2S ALC286"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -225,7 +231,7 @@ static int avs_rt286_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt286_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 6e409e29f697..7be34c8ad167 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -49,7 +49,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { {"Speaker", NULL, "SPOL"}, }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -70,12 +70,13 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; - ret = snd_soc_card_jack_new_pins(card, "Headset", SND_JACK_HEADSET | SND_JACK_BTN_0, jack, - pins, num_pins); + ret = snd_soc_card_jack_new_pins(card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0, + jack, pins, num_pins); if (ret) return ret; @@ -164,17 +165,15 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->num_platforms = 1; dl->id = 0; if (dmi_first_match(kblr_dmi_table)) - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; else - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt298_codec_init; dl->exit = avs_rt298_codec_exit; dl->be_hw_params_fixup = avs_rt298_be_fixup; dl->ops = &avs_rt298_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -200,6 +199,7 @@ static int avs_rt298_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -208,6 +208,7 @@ static int avs_rt298_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -224,7 +225,12 @@ static int avs_rt298_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt298"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt298"; + } else { + card->driver_name = "avs_rt298"; + card->long_name = card->name = "AVS I2S ALC298"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -244,7 +250,7 @@ static int avs_rt298_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt298_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index 097ae5f73241..45f091f2ce22 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2023 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -116,12 +116,12 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt5514_codec_init; dl->be_hw_params_fixup = avs_rt5514_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; + dl->capture_only = 1; dl->ops = &avs_rt5514_ops; *dai_link = dl; @@ -133,6 +133,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; @@ -140,6 +141,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -155,7 +157,12 @@ static int avs_rt5514_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_rt5514"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5514"; + } else { + card->driver_name = "avs_rt5514"; + card->long_name = card->name = "AVS I2S ALC5514"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -170,7 +177,7 @@ static int avs_rt5514_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5514_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index 1880c315cc4d..122b6c48fd80 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022-2023 Intel Corporation. All rights reserved. +// Copyright(c) 2022-2023 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -43,7 +43,7 @@ static const struct snd_soc_dapm_route card_routes[] = { { "IN1N", NULL, "Headset Mic" }, }; -static struct snd_soc_jack_pin card_headset_pins[] = { +static const struct snd_soc_jack_pin card_headset_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -65,7 +65,8 @@ static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime) jack = &priv->jack; num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -171,8 +172,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->be_hw_params_fixup = avs_rt5663_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ops = &avs_rt5663_ops; *dai_link = dl; @@ -199,6 +198,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct rt5663_private *priv; struct device *dev = &pdev->dev; @@ -207,6 +207,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -223,7 +224,12 @@ static int avs_rt5663_probe(struct platform_device *pdev) if (!priv || !card) return -ENOMEM; - card->name = "avs_rt5663"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5663"; + } else { + card->driver_name = "avs_rt5663"; + card->long_name = card->name = "AVS I2S ALC5640"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -243,7 +249,7 @@ static int avs_rt5663_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5663_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 594a971ded9e..9677b9ebeff1 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -80,7 +80,7 @@ static const struct snd_soc_dapm_route card_base_routes[] = { { "IN1P", NULL, "Headset Mic" }, }; -static struct snd_soc_jack_pin card_jack_pins[] = { +static const struct snd_soc_jack_pin card_jack_pins[] = { { .pin = "Headphone Jack", .mask = SND_JACK_HEADPHONE, @@ -102,7 +102,8 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_jack_pins); - pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_jack_pins, num_pins, + sizeof(card_jack_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -242,8 +243,6 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->ops = &avs_rt5682_ops; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; *dai_link = dl; @@ -269,6 +268,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct snd_soc_jack *jack; struct device *dev = &pdev->dev; @@ -283,6 +283,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -299,7 +300,12 @@ static int avs_rt5682_probe(struct platform_device *pdev) if (!jack || !card) return -ENOMEM; - card->name = "avs_rt5682"; + if (pdata->obsolete_card_names) { + card->name = "avs_rt5682"; + } else { + card->driver_name = "avs_rt5682"; + card->long_name = card->name = "AVS I2S ALC5682"; + } card->dev = dev; card->owner = THIS_MODULE; card->suspend_pre = avs_card_suspend_pre; @@ -319,7 +325,7 @@ static int avs_rt5682_probe(struct platform_device *pdev) if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_rt5682_driver_ids[] = { diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index d6f7f046c24e..3786eef8c494 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -37,8 +37,6 @@ static const struct snd_kcontrol_new card_controls[] = { static const struct snd_soc_dapm_widget card_widgets[] = { SND_SOC_DAPM_SPK("Left Speaker", NULL), SND_SOC_DAPM_SPK("Right Speaker", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), }; static const struct snd_soc_dapm_route card_base_routes[] = { @@ -99,7 +97,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; @@ -118,13 +116,11 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_ssm4567_codec_init; dl->be_hw_params_fixup = avs_ssm4567_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; - dl->dpcm_capture = 1; - dl->dpcm_playback = 1; dl->ignore_pmdown_time = 1; *dai_link = dl; @@ -136,6 +132,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) { struct snd_soc_dai_link *dai_link; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct snd_soc_card *card; struct device *dev = &pdev->dev; const char *pname; @@ -143,6 +140,7 @@ static int avs_ssm4567_probe(struct platform_device *pdev) mach = dev_get_platdata(dev); pname = mach->mach_params.platform; + pdata = mach->pdata; ret = avs_mach_get_ssp_tdm(dev, mach, &ssp_port, &tdm_slot); if (ret) @@ -158,7 +156,12 @@ static int avs_ssm4567_probe(struct platform_device *pdev) if (!card) return -ENOMEM; - card->name = "avs_ssm4567-adi"; + if (pdata->obsolete_card_names) { + card->name = "avs_ssm4567"; + } else { + card->driver_name = "avs_ssm4567"; + card->long_name = card->name = "AVS I2S SSM4567"; + } card->dev = dev; card->owner = THIS_MODULE; card->dai_link = dai_link; @@ -172,13 +175,12 @@ static int avs_ssm4567_probe(struct platform_device *pdev) card->dapm_routes = card_base_routes; card->num_dapm_routes = ARRAY_SIZE(card_base_routes); card->fully_routed = true; - card->disable_route_checks = true; ret = snd_soc_fixup_dai_links_platform_name(card, pname); if (ret) return ret; - return devm_snd_soc_register_card(dev, card); + return devm_snd_soc_register_deferrable_card(dev, card); } static const struct platform_device_id avs_ssm4567_driver_ids[] = { diff --git a/sound/soc/intel/avs/cldma.c b/sound/soc/intel/avs/cldma.c index d7a9390b5e48..61326d7059b1 100644 --- a/sound/soc/intel/avs/cldma.c +++ b/sound/soc/intel/avs/cldma.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // @@ -35,7 +35,7 @@ struct hda_cldma { unsigned int buffer_size; unsigned int num_periods; - unsigned int stream_tag; + unsigned char stream_tag; void __iomem *sd_addr; struct snd_dma_buffer dmab_data; @@ -248,32 +248,20 @@ void hda_cldma_setup(struct hda_cldma *cl) snd_hdac_stream_writel(cl, CL_SPBFCTL, 1); } -static irqreturn_t cldma_irq_handler(int irq, void *dev_id) +void hda_cldma_interrupt(struct hda_cldma *cl) { - struct hda_cldma *cl = dev_id; - u32 adspis; - - adspis = snd_hdac_adsp_readl(cl, AVS_ADSP_REG_ADSPIS); - if (adspis == UINT_MAX) - return IRQ_NONE; - if (!(adspis & AVS_ADSP_ADSPIS_CLDMA)) - return IRQ_NONE; - - cl->sd_status = snd_hdac_stream_readb(cl, SD_STS); - dev_warn(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status); - /* disable CLDMA interrupt */ snd_hdac_adsp_updatel(cl, AVS_ADSP_REG_ADSPIC, AVS_ADSP_ADSPIC_CLDMA, 0); - complete(&cl->completion); + cl->sd_status = snd_hdac_stream_readb(cl, SD_STS); + dev_dbg(cl->dev, "%s sd_status: 0x%08x\n", __func__, cl->sd_status); - return IRQ_HANDLED; + complete(&cl->completion); } int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba, unsigned int buffer_size) { - struct pci_dev *pci = to_pci_dev(bus->dev); int ret; ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, bus->dev, buffer_size, &cl->dmab_data); @@ -281,8 +269,10 @@ int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp return ret; ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, bus->dev, BDL_SIZE, &cl->dmab_bdl); - if (ret < 0) - goto alloc_err; + if (ret < 0) { + snd_dma_free_pages(&cl->dmab_data); + return ret; + } cl->dev = bus->dev; cl->bus = bus; @@ -290,27 +280,11 @@ int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp cl->buffer_size = buffer_size; cl->sd_addr = dsp_ba + AZX_CL_SD_BASE; - ret = pci_request_irq(pci, 0, cldma_irq_handler, NULL, cl, "CLDMA"); - if (ret < 0) { - dev_err(cl->dev, "Failed to request CLDMA IRQ handler: %d\n", ret); - goto req_err; - } - return 0; - -req_err: - snd_dma_free_pages(&cl->dmab_bdl); -alloc_err: - snd_dma_free_pages(&cl->dmab_data); - - return ret; } void hda_cldma_free(struct hda_cldma *cl) { - struct pci_dev *pci = to_pci_dev(cl->dev); - - pci_free_irq(pci, 0, cl); snd_dma_free_pages(&cl->dmab_data); snd_dma_free_pages(&cl->dmab_bdl); } diff --git a/sound/soc/intel/avs/cldma.h b/sound/soc/intel/avs/cldma.h index 223d3431ab81..7f9b2b1c566e 100644 --- a/sound/soc/intel/avs/cldma.h +++ b/sound/soc/intel/avs/cldma.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2022 Intel Corporation * * Author: Cezary Rojewski <cezary.rojewski@intel.com> */ @@ -24,6 +24,7 @@ int hda_cldma_reset(struct hda_cldma *cl); void hda_cldma_set_data(struct hda_cldma *cl, void *data, unsigned int size); void hda_cldma_setup(struct hda_cldma *cl); +void hda_cldma_interrupt(struct hda_cldma *cl); int hda_cldma_init(struct hda_cldma *cl, struct hdac_bus *bus, void __iomem *dsp_ba, unsigned int buffer_size); void hda_cldma_free(struct hda_cldma *cl); diff --git a/sound/soc/intel/avs/cnl.c b/sound/soc/intel/avs/cnl.c index 5423c29ecc4e..03f8fb0dc187 100644 --- a/sound/soc/intel/avs/cnl.c +++ b/sound/soc/intel/avs/cnl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -9,45 +9,75 @@ #include <sound/hdaudio_ext.h> #include "avs.h" #include "messages.h" +#include "registers.h" -irqreturn_t avs_cnl_irq_thread(struct avs_dev *adev) +static void avs_cnl_ipc_interrupt(struct avs_dev *adev) { - union avs_reply_msg msg; - u32 hipctdr, hipctdd, hipctda; - - hipctdr = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR); - hipctdd = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD); - - /* Ensure DSP sent new response to process. */ - if (!(hipctdr & CNL_ADSP_HIPCTDR_BUSY)) - return IRQ_NONE; - - msg.primary = hipctdr; - msg.ext.val = hipctdd; - avs_dsp_process_response(adev, msg.val); - - /* Tell DSP we accepted its message. */ - snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR, - CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY); - /* Ack this response. */ - snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA, - CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE); - /* HW might have been clock gated, give some time for change to propagate. */ - snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda, - !(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000); - /* Unmask busy interrupt. */ - snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCCTL, - AVS_ADSP_HIPCCTL_BUSY, AVS_ADSP_HIPCCTL_BUSY); - - return IRQ_HANDLED; + const struct avs_spec *spec = adev->spec; + u32 hipc_ack, hipc_rsp; + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); + + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); + + /* DSP acked host's request. */ + if (hipc_ack & spec->hipc->ack_done_mask) { + complete(&adev->ipc->done_completion); + + /* Tell DSP it has our attention. */ + snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask, + spec->hipc->ack_done_mask); + } + + /* DSP sent new response to process. */ + if (hipc_rsp & spec->hipc->rsp_busy_mask) { + union avs_reply_msg msg; + u32 hipctda; + + msg.primary = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDR); + msg.ext.val = snd_hdac_adsp_readl(adev, CNL_ADSP_REG_HIPCTDD); + + avs_dsp_process_response(adev, msg.val); + + /* Tell DSP we accepted its message. */ + snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDR, + CNL_ADSP_HIPCTDR_BUSY, CNL_ADSP_HIPCTDR_BUSY); + /* Ack this response. */ + snd_hdac_adsp_updatel(adev, CNL_ADSP_REG_HIPCTDA, + CNL_ADSP_HIPCTDA_DONE, CNL_ADSP_HIPCTDA_DONE); + /* HW might have been clock gated, give some time for change to propagate. */ + snd_hdac_adsp_readl_poll(adev, CNL_ADSP_REG_HIPCTDA, hipctda, + !(hipctda & CNL_ADSP_HIPCTDA_DONE), 10, 1000); + } + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY); +} + +irqreturn_t avs_cnl_dsp_interrupt(struct avs_dev *adev) +{ + u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS); + irqreturn_t ret = IRQ_NONE; + + if (adspis == UINT_MAX) + return ret; + + if (adspis & AVS_ADSP_ADSPIS_IPC) { + avs_cnl_ipc_interrupt(adev); + ret = IRQ_HANDLED; + } + + return ret; } const struct avs_dsp_ops avs_cnl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_hda_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index 3dfa2e9816db..2e01dc75a15a 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // Cezary Rojewski <cezary.rojewski@intel.com> // +#include <linux/cleanup.h> #include <sound/soc.h> #include "avs.h" #include "control.h" @@ -31,8 +32,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i list_for_each_entry(path, &adev->path_list, node) { list_for_each_entry(ppl, &path->ppl_list, node) { list_for_each_entry(mod, &ppl->mod_list, node) { - if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID) - && mod->template->ctl_id == id) { + guid_t *type = &mod->template->cfg_ext->type; + + if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) || + guid_equal(type, &AVS_GAIN_MOD_UUID)) && + mod->template->ctl_id == id) { spin_unlock(&adev->path_list_lock); return mod; } @@ -44,70 +48,168 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i return NULL; } -int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; - struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); - struct avs_volume_cfg *dspvols = NULL; + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct avs_control_data *ctl_data = mc->dobj.private; struct avs_path_module *active_module; + struct avs_volume_cfg *dspvols; + struct avs_dev *adev; size_t num_dspvols; - int ret = 0; + int ret, i; + + adev = avs_get_kcontrol_adev(kctl); - /* prevent access to modules while path is being constructed */ - mutex_lock(&adev->path_mutex); + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); active_module = avs_get_volume_module(adev, ctl_data->id); if (active_module) { ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, active_module->instance_id, &dspvols, &num_dspvols); - if (!ret) - ucontrol->value.integer.value[0] = dspvols[0].target_volume; + if (ret) + return AVS_IPC_RET(ret); - ret = AVS_IPC_RET(ret); + /* Do not copy more than the control can store. */ + num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN); + for (i = 0; i < num_dspvols; i++) + ctl_data->values[i] = dspvols[i].target_volume; kfree(dspvols); - } else { - ucontrol->value.integer.value[0] = ctl_data->volume; } - mutex_unlock(&adev->path_mutex); - return ret; + memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); + return 0; } -int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; - struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); - long *volume = &ctl_data->volume; struct avs_path_module *active_module; - struct avs_volume_cfg dspvol = {0}; - long ctlvol = ucontrol->value.integer.value[0]; - int ret = 0, changed = 0; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + struct avs_dev *adev; + long *input; + int ret, i; + + mc = (struct soc_mixer_control *)kctl->private_value; + ctl_data = mc->dobj.private; + adev = avs_get_kcontrol_adev(kctl); + input = uctl->value.integer.value; + i = 0; + + /* mc->num_channels can be 0. */ + do { + if (input[i] < mc->min || input[i] > mc->max) + return -EINVAL; + } while (++i < mc->num_channels); + + if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) + return 0; + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); - if (ctlvol < 0 || ctlvol > mc->max) - return -EINVAL; + active_module = avs_get_volume_module(adev, ctl_data->id); + if (active_module) { + ret = avs_peakvol_set_volume(adev, active_module, mc, input); + if (ret) + return ret; + } - /* prevent access to modules while path is being constructed */ - mutex_lock(&adev->path_mutex); + memcpy(ctl_data->values, input, sizeof(ctl_data->values)); + return 1; +} - if (*volume != ctlvol) { - *volume = ctlvol; - changed = 1; - } +int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = max_t(u32, 1, mc->num_channels); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max; + return 0; +} + +int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct avs_control_data *ctl_data = mc->dobj.private; + struct avs_path_module *active_module; + struct avs_mute_cfg *dspmutes; + struct avs_dev *adev; + size_t num_dspmutes; + int ret, i; + + adev = avs_get_kcontrol_adev(kctl); + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); active_module = avs_get_volume_module(adev, ctl_data->id); if (active_module) { - dspvol.channel_id = AVS_ALL_CHANNELS_MASK; - dspvol.target_volume = *volume; + ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id, + active_module->instance_id, &dspmutes, + &num_dspmutes); + if (ret) + return AVS_IPC_RET(ret); + + /* Do not copy more than the control can store. */ + num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN); + for (i = 0; i < num_dspmutes; i++) + ctl_data->values[i] = !dspmutes[i].mute; + kfree(dspmutes); + } - ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id, - active_module->instance_id, &dspvol); - ret = AVS_IPC_RET(ret); + memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); + return 0; +} + +int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) +{ + struct avs_path_module *active_module; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + struct avs_dev *adev; + long *input; + int ret, i; + + mc = (struct soc_mixer_control *)kctl->private_value; + ctl_data = mc->dobj.private; + adev = avs_get_kcontrol_adev(kctl); + input = uctl->value.integer.value; + i = 0; + + /* mc->num_channels can be 0. */ + do { + if (input[i] < mc->min || input[i] > mc->max) + return -EINVAL; + } while (++i < mc->num_channels); + + if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) + return 0; + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); + + active_module = avs_get_volume_module(adev, ctl_data->id); + if (active_module) { + ret = avs_peakvol_set_mute(adev, active_module, mc, input); + if (ret) + return ret; } - mutex_unlock(&adev->path_mutex); + memcpy(ctl_data->values, input, sizeof(ctl_data->values)); + return 1; +} + +int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; - return ret ? ret : changed; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = max_t(u32, 1, mc->num_channels); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max; + return 0; } diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h index 08631bde13c3..08b2919e4629 100644 --- a/sound/soc/intel/avs/control.h +++ b/sound/soc/intel/avs/control.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2022 Intel Corporation * * Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> * Cezary Rojewski <cezary.rojewski@intel.com> @@ -10,14 +10,18 @@ #define __SOUND_SOC_INTEL_AVS_CTRL_H #include <sound/control.h> +#include <uapi/sound/asoc.h> struct avs_control_data { u32 id; - - long volume; + long values[SND_SOC_TPLG_MAX_CHAN]; }; -int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo); +int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo); #endif diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index d7f8940099ce..485842838025 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -14,19 +14,21 @@ // foundation of this driver // +#include <linux/acpi.h> #include <linux/module.h> #include <linux/pci.h> +#include <acpi/nhlt.h> #include <sound/hda_codec.h> #include <sound/hda_i915.h> #include <sound/hda_register.h> #include <sound/hdaudio.h> #include <sound/hdaudio_ext.h> #include <sound/intel-dsp-config.h> -#include <sound/intel-nhlt.h> #include "../../codecs/hda.h" #include "avs.h" #include "cldma.h" #include "messages.h" +#include "pcm.h" static u32 pgctl_mask = AZX_PGCTL_LSRMD_MASK; module_param(pgctl_mask, uint, 0444); @@ -52,14 +54,17 @@ void avs_hda_power_gating_enable(struct avs_dev *adev, bool enable) { u32 value = enable ? 0 : pgctl_mask; - avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); + if (!avs_platattr_test(adev, ACE)) + avs_hda_update_config_dword(&adev->base.core, AZX_PCIREG_PGCTL, pgctl_mask, value); } static void avs_hdac_clock_gating_enable(struct hdac_bus *bus, bool enable) { + struct avs_dev *adev = hdac_to_avs(bus); u32 value = enable ? cgctl_mask : 0; - avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); + if (!avs_platattr_test(adev, ACE)) + avs_hda_update_config_dword(bus, AZX_PCIREG_CGCTL, cgctl_mask, value); } void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) @@ -69,6 +74,8 @@ void avs_hda_clock_gating_enable(struct avs_dev *adev, bool enable) void avs_hda_l1sen_enable(struct avs_dev *adev, bool enable) { + if (avs_platattr_test(adev, ACE)) + return; if (enable) { if (atomic_inc_and_test(&adev->l1sen_counter)) snd_hdac_chip_updatel(&adev->base.core, VS_EM2, AZX_VS_EM2_L1SEN, @@ -97,6 +104,7 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus) static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) { + struct avs_dev *adev = hdac_to_avs(bus); struct hdac_ext_link *hlink; bool ret; @@ -112,7 +120,8 @@ static bool avs_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset) /* Set DUM bit to address incorrect position reporting for capture * streams. In order to do so, CTRL needs to be out of reset state */ - snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); + if (!avs_platattr_test(adev, ACE)) + snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); return ret; } @@ -209,15 +218,13 @@ static void avs_hda_probe_work(struct work_struct *work) snd_hdac_ext_bus_ppcap_enable(bus, true); snd_hdac_ext_bus_ppcap_int_enable(bus, true); + avs_debugfs_init(adev); ret = avs_dsp_first_boot_firmware(adev); if (ret < 0) return; - adev->nhlt = intel_nhlt_init(adev->dev); - if (!adev->nhlt) - dev_info(bus->dev, "platform has no NHLT\n"); - avs_debugfs_init(adev); + acpi_nhlt_get_gbl_table(); avs_register_all_boards(adev); @@ -248,7 +255,7 @@ static void hdac_stream_update_pos(struct hdac_stream *stream, u64 buffer_size) static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream) { if (stream->substream) { - snd_pcm_period_elapsed(stream->substream); + avs_period_elapsed(stream->substream); } else if (stream->cstream) { u64 buffer_size = stream->cstream->runtime->buffer_size; @@ -257,67 +264,55 @@ static void hdac_update_stream(struct hdac_bus *bus, struct hdac_stream *stream) } } -static irqreturn_t hdac_bus_irq_handler(int irq, void *context) +static irqreturn_t avs_hda_interrupt(struct hdac_bus *bus) { - struct hdac_bus *bus = context; - u32 mask, int_enable; + irqreturn_t ret = IRQ_NONE; u32 status; - int ret = IRQ_NONE; - - if (!pm_runtime_active(bus->dev)) - return ret; - - spin_lock(&bus->reg_lock); status = snd_hdac_chip_readl(bus, INTSTS); - if (status == 0 || status == UINT_MAX) { - spin_unlock(&bus->reg_lock); - return ret; - } + if (snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream)) + ret = IRQ_HANDLED; - /* clear rirb int */ + spin_lock_irq(&bus->reg_lock); + /* Clear RIRB interrupt. */ status = snd_hdac_chip_readb(bus, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) snd_hdac_bus_update_rirb(bus); snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); - } - - mask = (0x1 << bus->num_streams) - 1; - - status = snd_hdac_chip_readl(bus, INTSTS); - status &= mask; - if (status) { - /* Disable stream interrupts; Re-enable in bottom half */ - int_enable = snd_hdac_chip_readl(bus, INTCTL); - snd_hdac_chip_writel(bus, INTCTL, (int_enable & (~mask))); - ret = IRQ_WAKE_THREAD; - } else { ret = IRQ_HANDLED; } - spin_unlock(&bus->reg_lock); + spin_unlock_irq(&bus->reg_lock); return ret; } -static irqreturn_t hdac_bus_irq_thread(int irq, void *context) +static irqreturn_t avs_hda_irq_handler(int irq, void *dev_id) +{ + struct hdac_bus *bus = dev_id; + u32 intsts; + + intsts = snd_hdac_chip_readl(bus, INTSTS); + if (intsts == UINT_MAX || !(intsts & AZX_INT_GLOBAL_EN)) + return IRQ_NONE; + + /* Mask GIE, unmasked in irq_thread(). */ + snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, 0); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t avs_hda_irq_thread(int irq, void *dev_id) { - struct hdac_bus *bus = context; + struct hdac_bus *bus = dev_id; u32 status; - u32 int_enable; - u32 mask; - unsigned long flags; status = snd_hdac_chip_readl(bus, INTSTS); + if (status & ~AZX_INT_GLOBAL_EN) + avs_hda_interrupt(bus); - snd_hdac_bus_handle_stream_irq(bus, status, hdac_update_stream); - - /* Re-enable stream interrupts */ - mask = (0x1 << bus->num_streams) - 1; - spin_lock_irqsave(&bus->reg_lock, flags); - int_enable = snd_hdac_chip_readl(bus, INTCTL); - snd_hdac_chip_writel(bus, INTCTL, (int_enable | mask)); - spin_unlock_irqrestore(&bus->reg_lock, flags); + /* Unmask GIE, masked in irq_handler(). */ + snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN); return IRQ_HANDLED; } @@ -326,14 +321,23 @@ static irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id) { struct avs_dev *adev = dev_id; - return avs_dsp_op(adev, irq_handler); + return avs_hda_irq_handler(irq, &adev->base.core); } static irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id) { struct avs_dev *adev = dev_id; + struct hdac_bus *bus = &adev->base.core; + u32 status; - return avs_dsp_op(adev, irq_thread); + status = readl(bus->ppcap + AZX_REG_PP_PPSTS); + if (status & AZX_PPCTL_PIE) + avs_dsp_op(adev, dsp_interrupt); + + /* Unmask GIE, masked in irq_handler(). */ + snd_hdac_chip_updatel(bus, INTCTL, AZX_INT_GLOBAL_EN, AZX_INT_GLOBAL_EN); + + return IRQ_HANDLED; } static int avs_hdac_acquire_irq(struct avs_dev *adev) @@ -343,13 +347,13 @@ static int avs_hdac_acquire_irq(struct avs_dev *adev) int ret; /* request one and check that we only got one interrupt */ - ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_LEGACY); + ret = pci_alloc_irq_vectors(pci, 1, 1, PCI_IRQ_MSI | PCI_IRQ_INTX); if (ret != 1) { dev_err(adev->dev, "Failed to allocate IRQ vector: %d\n", ret); return ret; } - ret = pci_request_irq(pci, 0, hdac_bus_irq_handler, hdac_bus_irq_thread, bus, + ret = pci_request_irq(pci, 0, avs_hda_irq_handler, avs_hda_irq_thread, bus, KBUILD_MODNAME); if (ret < 0) { dev_err(adev->dev, "Failed to request stream IRQ handler: %d\n", ret); @@ -426,8 +430,14 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) int ret; ret = snd_intel_dsp_driver_probe(pci); - if (ret != SND_INTEL_DSP_DRIVER_ANY && ret != SND_INTEL_DSP_DRIVER_AVS) + switch (ret) { + case SND_INTEL_DSP_DRIVER_ANY: + case SND_INTEL_DSP_DRIVER_SST: + case SND_INTEL_DSP_DRIVER_AVS: + break; + default: return -ENODEV; + } ret = pcim_enable_device(pci); if (ret < 0) @@ -442,7 +452,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) return ret; } - ret = pci_request_regions(pci, "AVS HDAudio"); + ret = pcim_request_all_regions(pci, "AVS HDAudio"); if (ret < 0) return ret; @@ -451,8 +461,7 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) bus->remap_addr = pci_ioremap_bar(pci, 0); if (!bus->remap_addr) { dev_err(bus->dev, "ioremap error\n"); - ret = -ENXIO; - goto err_remap_bar0; + return -ENXIO; } adev->dsp_ba = pci_ioremap_bar(pci, 4); @@ -509,8 +518,6 @@ err_init_streams: iounmap(adev->dsp_ba); err_remap_bar4: iounmap(bus->remap_addr); -err_remap_bar0: - pci_release_regions(pci); return ret; } @@ -530,8 +537,6 @@ static void avs_pci_shutdown(struct pci_dev *pci) snd_hdac_bus_stop_chip(bus); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - if (avs_platattr_test(adev, CLDMA)) - pci_free_irq(pci, 0, &code_loader); pci_free_irq(pci, 0, adev); pci_free_irq(pci, 0, bus); pci_free_irq_vectors(pci); @@ -548,9 +553,8 @@ static void avs_pci_remove(struct pci_dev *pci) avs_unregister_all_boards(adev); + acpi_nhlt_put_gbl_table(); avs_debugfs_exit(adev); - if (adev->nhlt) - intel_nhlt_free(adev->nhlt); if (avs_platattr_test(adev, CLDMA)) hda_cldma_free(&code_loader); @@ -584,7 +588,6 @@ static void avs_pci_remove(struct pci_dev *pci) pci_free_irq_vectors(pci); iounmap(bus->remap_addr); iounmap(adev->dsp_ba); - pci_release_regions(pci); /* Firmware is not needed anymore */ avs_release_firmwares(adev); @@ -612,7 +615,7 @@ static int avs_suspend_standby(struct avs_dev *adev) return 0; } -static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power) +static int avs_suspend_common(struct avs_dev *adev, bool low_power) { struct hdac_bus *bus = &adev->base.core; int ret; @@ -673,7 +676,7 @@ static int avs_resume_standby(struct avs_dev *adev) return 0; } -static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge) +static int avs_resume_common(struct avs_dev *adev, bool low_power, bool purge) { struct hdac_bus *bus = &adev->base.core; int ret; @@ -696,41 +699,41 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power return 0; } -static int __maybe_unused avs_suspend(struct device *dev) +static int avs_suspend(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), true); } -static int __maybe_unused avs_resume(struct device *dev) +static int avs_resume(struct device *dev) { return avs_resume_common(to_avs_dev(dev), true, true); } -static int __maybe_unused avs_runtime_suspend(struct device *dev) +static int avs_runtime_suspend(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), true); } -static int __maybe_unused avs_runtime_resume(struct device *dev) +static int avs_runtime_resume(struct device *dev) { return avs_resume_common(to_avs_dev(dev), true, false); } -static int __maybe_unused avs_freeze(struct device *dev) +static int avs_freeze(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), false); } -static int __maybe_unused avs_thaw(struct device *dev) +static int avs_thaw(struct device *dev) { return avs_resume_common(to_avs_dev(dev), false, true); } -static int __maybe_unused avs_poweroff(struct device *dev) +static int avs_poweroff(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), false); } -static int __maybe_unused avs_restore(struct device *dev) +static int avs_restore(struct device *dev) { return avs_resume_common(to_avs_dev(dev), false, true); } @@ -742,19 +745,22 @@ static const struct dev_pm_ops avs_dev_pm = { .thaw = avs_thaw, .poweroff = avs_poweroff, .restore = avs_restore, - SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) + RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) }; static const struct avs_sram_spec skl_sram_spec = { .base_offset = SKL_ADSP_SRAM_BASE_OFFSET, .window_size = SKL_ADSP_SRAM_WINDOW_SIZE, - .rom_status_offset = SKL_ADSP_SRAM_BASE_OFFSET, }; static const struct avs_sram_spec apl_sram_spec = { .base_offset = APL_ADSP_SRAM_BASE_OFFSET, .window_size = APL_ADSP_SRAM_WINDOW_SIZE, - .rom_status_offset = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_sram_spec mtl_sram_spec = { + .base_offset = MTL_ADSP_SRAM_BASE_OFFSET, + .window_size = MTL_ADSP_SRAM_WINDOW_SIZE, }; static const struct avs_hipc_spec skl_hipc_spec = { @@ -766,6 +772,19 @@ static const struct avs_hipc_spec skl_hipc_spec = { .rsp_offset = SKL_ADSP_REG_HIPCT, .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, .ctl_offset = SKL_ADSP_REG_HIPCCTL, + .sts_offset = SKL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_hipc_spec apl_hipc_spec = { + .req_offset = SKL_ADSP_REG_HIPCI, + .req_ext_offset = SKL_ADSP_REG_HIPCIE, + .req_busy_mask = SKL_ADSP_HIPCI_BUSY, + .ack_offset = SKL_ADSP_REG_HIPCIE, + .ack_done_mask = SKL_ADSP_HIPCIE_DONE, + .rsp_offset = SKL_ADSP_REG_HIPCT, + .rsp_busy_mask = SKL_ADSP_HIPCT_BUSY, + .ctl_offset = SKL_ADSP_REG_HIPCCTL, + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, }; static const struct avs_hipc_spec cnl_hipc_spec = { @@ -777,6 +796,19 @@ static const struct avs_hipc_spec cnl_hipc_spec = { .rsp_offset = CNL_ADSP_REG_HIPCTDR, .rsp_busy_mask = CNL_ADSP_HIPCTDR_BUSY, .ctl_offset = CNL_ADSP_REG_HIPCCTL, + .sts_offset = APL_ADSP_SRAM_BASE_OFFSET, +}; + +static const struct avs_hipc_spec lnl_hipc_spec = { + .req_offset = MTL_REG_HfIPCxIDR, + .req_ext_offset = MTL_REG_HfIPCxIDD, + .req_busy_mask = MTL_HfIPCxIDR_BUSY, + .ack_offset = MTL_REG_HfIPCxIDA, + .ack_done_mask = MTL_HfIPCxIDA_DONE, + .rsp_offset = MTL_REG_HfIPCxTDR, + .rsp_busy_mask = MTL_HfIPCxTDR_BUSY, + .ctl_offset = MTL_REG_HfIPCxCTL, + .sts_offset = LNL_REG_HfDFR(0), }; static const struct avs_spec skl_desc = { @@ -796,7 +828,7 @@ static const struct avs_spec apl_desc = { .core_init_mask = 3, .attributes = AVS_PLATATTR_IMR, .sram = &apl_sram_spec, - .hipc = &skl_hipc_spec, + .hipc = &apl_hipc_spec, }; static const struct avs_spec cnl_desc = { @@ -829,10 +861,10 @@ static const struct avs_spec jsl_desc = { .hipc = &cnl_hipc_spec, }; -#define AVS_TGL_BASED_SPEC(sname) \ +#define AVS_TGL_BASED_SPEC(sname, min) \ static const struct avs_spec sname##_desc = { \ .name = #sname, \ - .min_fw_version = { 10, 29, 0, 5646 }, \ + .min_fw_version = { 10, min, 0, 5646 }, \ .dsp_ops = &avs_tgl_dsp_ops, \ .core_init_mask = 1, \ .attributes = AVS_PLATATTR_IMR, \ @@ -840,11 +872,21 @@ static const struct avs_spec sname##_desc = { \ .hipc = &cnl_hipc_spec, \ } -AVS_TGL_BASED_SPEC(lkf); -AVS_TGL_BASED_SPEC(tgl); -AVS_TGL_BASED_SPEC(ehl); -AVS_TGL_BASED_SPEC(adl); -AVS_TGL_BASED_SPEC(adl_n); +AVS_TGL_BASED_SPEC(lkf, 28); +AVS_TGL_BASED_SPEC(tgl, 29); +AVS_TGL_BASED_SPEC(ehl, 30); +AVS_TGL_BASED_SPEC(adl, 35); +AVS_TGL_BASED_SPEC(adl_n, 35); + +static const struct avs_spec fcl_desc = { + .name = "fcl", + .min_fw_version = { 0 }, + .dsp_ops = &avs_ptl_dsp_ops, + .core_init_mask = 1, + .attributes = AVS_PLATATTR_IMR | AVS_PLATATTR_ACE | AVS_PLATATTR_ALTHDA, + .sram = &mtl_sram_spec, + .hipc = &lnl_hipc_spec, +}; static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &skl_desc) }, @@ -881,6 +923,7 @@ static const struct pci_device_id avs_ids[] = { { PCI_DEVICE_DATA(INTEL, HDA_RPL_P_1, &adl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_RPL_M, &adl_desc) }, { PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, &adl_desc) }, + { PCI_DEVICE_DATA(INTEL, HDA_FCL, &fcl_desc) }, { 0 } }; MODULE_DEVICE_TABLE(pci, avs_ids); @@ -893,7 +936,7 @@ static struct pci_driver avs_pci_driver = { .shutdown = avs_pci_shutdown, .dev_groups = avs_attr_groups, .driver = { - .pm = &avs_dev_pm, + .pm = pm_ptr(&avs_dev_pm), }, }; module_pci_driver(avs_pci_driver); @@ -902,3 +945,14 @@ MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); MODULE_AUTHOR("Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>"); MODULE_DESCRIPTION("Intel cAVS sound driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("intel/skl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/apl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/cnl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/icl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/jsl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/lkf/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/tgl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/ehl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/adl/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/adl_n/dsp_basefw.bin"); +MODULE_FIRMWARE("intel/fcl/dsp_basefw.bin"); diff --git a/sound/soc/intel/avs/debugfs.c b/sound/soc/intel/avs/debugfs.c index 4dfbff0ce508..8c4edda97f75 100644 --- a/sound/soc/intel/avs/debugfs.c +++ b/sound/soc/intel/avs/debugfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -10,6 +10,7 @@ #include <linux/kfifo.h> #include <linux/wait.h> #include <linux/sched/signal.h> +#include <linux/string_helpers.h> #include <sound/soc.h> #include "avs.h" #include "messages.h" @@ -68,7 +69,6 @@ static ssize_t fw_regs_read(struct file *file, char __user *to, size_t count, lo static const struct file_operations fw_regs_fops = { .open = simple_open, .read = fw_regs_read, - .llseek = no_llseek, }; static ssize_t debug_window_read(struct file *file, char __user *to, size_t count, loff_t *ppos) @@ -93,7 +93,6 @@ static ssize_t debug_window_read(struct file *file, char __user *to, size_t coun static const struct file_operations debug_window_fops = { .open = simple_open, .read = debug_window_read, - .llseek = no_llseek, }; static ssize_t probe_points_read(struct file *file, char __user *to, size_t count, loff_t *ppos) @@ -170,7 +169,6 @@ static const struct file_operations probe_points_fops = { .open = simple_open, .read = probe_points_read, .write = probe_points_write, - .llseek = no_llseek, }; static ssize_t probe_points_disconnect_write(struct file *file, const char __user *from, diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c index aa03af4473e9..464bd6859182 100644 --- a/sound/soc/intel/avs/dsp.c +++ b/sound/soc/intel/avs/dsp.c @@ -1,18 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // +#include <linux/string_choices.h> #include <sound/hdaudio_ext.h> #include "avs.h" #include "registers.h" #include "trace.h" -#define AVS_ADSPCS_INTERVAL_US 500 -#define AVS_ADSPCS_TIMEOUT_US 50000 #define AVS_ADSPCS_DELAY_US 1000 int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) @@ -39,7 +38,7 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) AVS_ADSPCS_TIMEOUT_US); if (ret) dev_err(adev->dev, "core_mask %d power %s failed: %d\n", - core_mask, power ? "on" : "off", ret); + core_mask, str_on_off(power), ret); return ret; } diff --git a/sound/soc/intel/avs/icl.c b/sound/soc/intel/avs/icl.c index 9d9921e1cd4d..f8d327ea2656 100644 --- a/sound/soc/intel/avs/icl.c +++ b/sound/soc/intel/avs/icl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -52,22 +52,25 @@ union avs_icl_memwnd2_slot_type { u32 type:24; }; } __packed; +static_assert(sizeof(union avs_icl_memwnd2_slot_type) == 4); struct avs_icl_memwnd2_desc { u32 resource_id; union avs_icl_memwnd2_slot_type slot_id; u32 vma; } __packed; +static_assert(sizeof(struct avs_icl_memwnd2_desc) == 12); #define AVS_ICL_MEMWND2_SLOTS_COUNT 15 struct avs_icl_memwnd2 { union { struct avs_icl_memwnd2_desc slot_desc[AVS_ICL_MEMWND2_SLOTS_COUNT]; - u8 rsvd[PAGE_SIZE]; + u8 rsvd[SZ_4K]; }; - u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][PAGE_SIZE]; + u8 slot_array[AVS_ICL_MEMWND2_SLOTS_COUNT][SZ_4K]; } __packed; +static_assert(sizeof(struct avs_icl_memwnd2) == 65536); #define AVS_ICL_SLOT_UNUSED \ ((union avs_icl_memwnd2_slot_type) { 0x00000000U }) @@ -89,8 +92,7 @@ static int avs_icl_slot_offset(struct avs_dev *adev, union avs_icl_memwnd2_slot_ for (i = 0; i < AVS_ICL_MEMWND2_SLOTS_COUNT; i++) if (desc[i].slot_id.val == slot_type.val) - return offsetof(struct avs_icl_memwnd2, slot_array) + - avs_skl_log_buffer_offset(adev, i); + return offsetof(struct avs_icl_memwnd2, slot_array) + i * SZ_4K; return -ENXIO; } @@ -110,6 +112,10 @@ int avs_icl_log_buffer_offset(struct avs_dev *adev, u32 core) bool avs_icl_d0ix_toggle(struct avs_dev *adev, struct avs_ipc_msg *tx, bool wake) { + /* Full-power when starting DMA engines. */ + if (tx->glb.set_ppl_state.state == AVS_PPL_STATE_RUNNING) + return true; + /* Payload-less IPCs do not take part in d0ix toggling. */ return tx->size; } @@ -182,8 +188,7 @@ const struct avs_dsp_ops avs_icl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_icl_load_basefw, .load_lib = avs_hda_load_library, diff --git a/sound/soc/intel/avs/ipc.c b/sound/soc/intel/avs/ipc.c index ad0e535b3c2e..08ed9d96738a 100644 --- a/sound/soc/intel/avs/ipc.c +++ b/sound/soc/intel/avs/ipc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -184,10 +184,11 @@ static void avs_dsp_receive_rx(struct avs_dev *adev, u64 header) { struct avs_ipc *ipc = adev->ipc; union avs_reply_msg msg = AVS_MSG(header); - u64 reg; + u32 sts, lec; - reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); - trace_avs_ipc_reply_msg(header, reg); + sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)); + lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)); + trace_avs_ipc_reply_msg(header, sts, lec); ipc->rx.header = header; /* Abort copying payload if request processing was unsuccessful. */ @@ -209,10 +210,11 @@ static void avs_dsp_process_notification(struct avs_dev *adev, u64 header) union avs_notify_msg msg = AVS_MSG(header); size_t data_size = 0; void *data = NULL; - u64 reg; + u32 sts, lec; - reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); - trace_avs_ipc_notify_msg(header, reg); + sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)); + lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)); + trace_avs_ipc_notify_msg(header, sts, lec); /* Ignore spurious notifications until handshake is established. */ if (!adev->ipc->ready && msg.notify_msg_type != AVS_NOTIFY_FW_READY) { @@ -301,54 +303,6 @@ void avs_dsp_process_response(struct avs_dev *adev, u64 header) complete(&ipc->busy_completion); } -irqreturn_t avs_irq_handler(struct avs_dev *adev) -{ - struct avs_ipc *ipc = adev->ipc; - const struct avs_spec *const spec = adev->spec; - u32 adspis, hipc_rsp, hipc_ack; - irqreturn_t ret = IRQ_NONE; - - adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS); - if (adspis == UINT_MAX || !(adspis & AVS_ADSP_ADSPIS_IPC)) - return ret; - - hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); - hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); - - /* DSP acked host's request */ - if (hipc_ack & spec->hipc->ack_done_mask) { - /* - * As an extra precaution, mask done interrupt. Code executed - * due to complete() found below does not assume any masking. - */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_DONE, 0); - - complete(&ipc->done_completion); - - /* tell DSP it has our attention */ - snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, - spec->hipc->ack_done_mask, - spec->hipc->ack_done_mask); - /* unmask done interrupt */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_DONE, - AVS_ADSP_HIPCCTL_DONE); - ret = IRQ_HANDLED; - } - - /* DSP sent new response to process */ - if (hipc_rsp & spec->hipc->rsp_busy_mask) { - /* mask busy interrupt */ - snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, - AVS_ADSP_HIPCCTL_BUSY, 0); - - ret = IRQ_WAKE_THREAD; - } - - return ret; -} - static bool avs_ipc_is_busy(struct avs_ipc *ipc) { struct avs_dev *adev = to_avs_dev(ipc->dev); @@ -415,13 +369,16 @@ static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply) static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool read_fwregs) { const struct avs_spec *const spec = adev->spec; - u64 reg = ULONG_MAX; + u32 sts = UINT_MAX; + u32 lec = UINT_MAX; tx->header |= spec->hipc->req_busy_mask; - if (read_fwregs) - reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW)); + if (read_fwregs) { + sts = snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)); + lec = snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev)); + } - trace_avs_request(tx, reg); + trace_avs_request(tx, sts, lec); if (tx->size) memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size); diff --git a/sound/soc/intel/avs/lnl.c b/sound/soc/intel/avs/lnl.c new file mode 100644 index 000000000000..03208596dfb1 --- /dev/null +++ b/sound/soc/intel/avs/lnl.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "registers.h" + +int avs_lnl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) +{ + struct hdac_bus *bus = &adev->base.core; + struct hdac_ext_link *hlink; + int ret; + + ret = avs_mtl_core_stall(adev, core_mask, stall); + + /* On unstall, route interrupts from the links to the DSP firmware. */ + if (!ret && !stall) + list_for_each_entry(hlink, &bus->hlink_list, list) + snd_hdac_updatel(hlink->ml_addr, AZX_REG_ML_LCTL, AZX_ML_LCTL_OFLEN, + AZX_ML_LCTL_OFLEN); + return ret; +} diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 8e34d3536082..138e4e9de5e3 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -56,6 +56,7 @@ struct avs_fw_manifest { u32 feature_mask; struct avs_fw_version version; } __packed; +static_assert(sizeof(struct avs_fw_manifest) == 36); struct avs_fw_ext_manifest { u32 id; @@ -64,6 +65,7 @@ struct avs_fw_ext_manifest { u16 version_minor; u32 entries; } __packed; +static_assert(sizeof(struct avs_fw_ext_manifest) == 16); static int avs_fw_ext_manifest_strip(struct firmware *fw) { @@ -165,7 +167,8 @@ int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw) (reg & AVS_ROM_INIT_DONE) == AVS_ROM_INIT_DONE, AVS_ROM_INIT_POLLING_US, SKL_ROM_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(adev->dev, "rom init timeout: %d\n", ret); + dev_err(adev->dev, "rom init failed: %d, status: 0x%08x, lec: 0x%08x\n", + ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); return ret; } @@ -178,7 +181,8 @@ int avs_cldma_load_basefw(struct avs_dev *adev, struct firmware *fw) AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US); hda_cldma_stop(cl); if (ret < 0) { - dev_err(adev->dev, "transfer fw failed: %d\n", ret); + dev_err(adev->dev, "transfer fw failed: %d, status: 0x%08x, lec: 0x%08x\n", + ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); return ret; } @@ -306,12 +310,13 @@ avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge) } /* await ROM init */ - ret = snd_hdac_adsp_readq_poll(adev, spec->sram->rom_status_offset, reg, + ret = snd_hdac_adsp_readl_poll(adev, spec->hipc->sts_offset, reg, (reg & 0xF) == AVS_ROM_INIT_DONE || (reg & 0xF) == APL_ROM_FW_ENTERED, AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US); if (ret < 0) { - dev_err(adev->dev, "rom init timeout: %d\n", ret); + dev_err(adev->dev, "rom init failed: %d, status: 0x%08x, lec: 0x%08x\n", + ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); goto err; } @@ -335,15 +340,15 @@ static int avs_imr_load_basefw(struct avs_dev *adev) /* DMA id ignored when flashing from IMR as no transfer occurs. */ ret = avs_hda_init_rom(adev, 0, false); - if (ret < 0) { - dev_err(adev->dev, "rom init failed: %d\n", ret); + if (ret < 0) return ret; - } ret = wait_for_completion_timeout(&adev->fw_ready, msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS)); if (!ret) { - dev_err(adev->dev, "firmware ready timeout\n"); + dev_err(adev->dev, "firmware ready timeout, status: 0x%08x, lec: 0x%08x\n", + snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)), + snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); return -ETIMEDOUT; } @@ -390,7 +395,7 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw) ret = avs_hda_init_rom(adev, dma_id, true); if (!ret) break; - dev_info(adev->dev, "#%d rom init fail: %d\n", i + 1, ret); + dev_info(adev->dev, "#%d rom init failed: %d\n", i + 1, ret); } if (ret < 0) goto cleanup_resources; @@ -402,7 +407,8 @@ int avs_hda_load_basefw(struct avs_dev *adev, struct firmware *fw) AVS_FW_INIT_POLLING_US, AVS_FW_INIT_TIMEOUT_US); snd_hdac_dsp_trigger(hstream, false); if (ret < 0) { - dev_err(adev->dev, "transfer fw failed: %d\n", ret); + dev_err(adev->dev, "transfer fw failed: %d, status: 0x%08x, lec: 0x%08x\n", + ret, reg, snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); } @@ -535,7 +541,7 @@ int avs_dsp_load_libraries(struct avs_dev *adev, struct avs_tplg_library *libs, if (ret) return ret; - strncpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE); + strscpy(adev->lib_names[id], man->name, AVS_LIB_NAME_SIZE); id++; next_lib: i++; @@ -582,7 +588,9 @@ static int avs_dsp_load_basefw(struct avs_dev *adev) ret = wait_for_completion_timeout(&adev->fw_ready, msecs_to_jiffies(AVS_FW_INIT_TIMEOUT_MS)); if (!ret) { - dev_err(adev->dev, "firmware ready timeout\n"); + dev_err(adev->dev, "firmware ready timeout, status: 0x%08x, lec: 0x%08x\n", + snd_hdac_adsp_readl(adev, AVS_FW_REG_STATUS(adev)), + snd_hdac_adsp_readl(adev, AVS_FW_REG_ERROR(adev))); avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); ret = -ETIMEDOUT; goto release_fw; @@ -595,7 +603,7 @@ release_fw: return ret; } -int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) +static int avs_load_firmware(struct avs_dev *adev, bool purge) { struct avs_soc_component *acomp; int ret, i; @@ -649,39 +657,49 @@ reenable_gating: return 0; } -int avs_dsp_first_boot_firmware(struct avs_dev *adev) +static int avs_config_basefw(struct avs_dev *adev) { - int ret, i; + int ret; - if (avs_platattr_test(adev, CLDMA)) { - ret = hda_cldma_init(&code_loader, &adev->base.core, - adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE); - if (ret < 0) { - dev_err(adev->dev, "cldma init failed: %d\n", ret); + if (adev->spec->dsp_ops->config_basefw) { + ret = avs_dsp_op(adev, config_basefw); + if (ret) return ret; - } } - ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); - if (ret < 0) - return ret; + return 0; +} - ret = avs_dsp_boot_firmware(adev, true); - if (ret < 0) { - dev_err(adev->dev, "firmware boot failed: %d\n", ret); +int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) +{ + int ret; + + ret = avs_load_firmware(adev, purge); + if (ret) return ret; - } + + return avs_config_basefw(adev); +} + +static int avs_dsp_alloc_resources(struct avs_dev *adev) +{ + struct hdac_ext_link *link; + int ret, i; ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg); - if (ret) { - dev_err(adev->dev, "get hw cfg failed: %d\n", ret); + if (ret) return AVS_IPC_RET(ret); - } ret = avs_ipc_get_fw_config(adev, &adev->fw_cfg); - if (ret) { - dev_err(adev->dev, "get fw cfg failed: %d\n", ret); + if (ret) return AVS_IPC_RET(ret); + + /* If hw allows, read capabilities directly from it. */ + if (avs_platattr_test(adev, ALTHDA)) { + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, + AZX_REG_ML_LEPTR_ID_INTEL_SSP); + if (link) + adev->hw_cfg.i2s_caps.ctrl_count = link->slcount; } adev->core_refs = devm_kcalloc(adev->dev, adev->hw_cfg.dsp_cores, @@ -698,9 +716,34 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev) } /* basefw always occupies slot 0 */ - strcpy(&adev->lib_names[0][0], "BASEFW"); + strscpy(adev->lib_names[0], "BASEFW", AVS_LIB_NAME_SIZE); ida_init(&adev->ppl_ida); - return 0; } + +int avs_dsp_first_boot_firmware(struct avs_dev *adev) +{ + int ret; + + if (avs_platattr_test(adev, CLDMA)) { + ret = hda_cldma_init(&code_loader, &adev->base.core, + adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE); + if (ret < 0) { + dev_err(adev->dev, "cldma init failed: %d\n", ret); + return ret; + } + } + + ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); + if (ret < 0) + return ret; + + ret = avs_dsp_boot_firmware(adev, true); + if (ret < 0) { + dev_err(adev->dev, "firmware boot failed: %d\n", ret); + return ret; + } + + return avs_dsp_alloc_resources(adev); +} diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index f874e4f0d95f..a5ba27983091 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -400,10 +400,12 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg) AVS_BASEFW_FIRMWARE_CONFIG, NULL, 0, &payload, &payload_size); if (ret) - return ret; + goto err; /* Non-zero payload expected for FIRMWARE_CONFIG. */ - if (!payload_size) - return -EREMOTEIO; + if (!payload_size) { + ret = -EREMOTEIO; + goto err; + } while (offset < payload_size) { tlv = (struct avs_tlv *)(payload + offset); @@ -502,6 +504,47 @@ int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg) /* No longer needed, free it as it's owned by the get_large_config() caller. */ kfree(payload); +err: + if (ret) + dev_err(adev->dev, "get fw cfg failed: %d\n", ret); + return ret; +} + +int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...) +{ + struct avs_tlv *tlv; + void *payload; + size_t offset; + va_list args; + int ret, i; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + va_start(args, num_tlvs); + for (offset = i = 0; i < num_tlvs && offset < AVS_MAILBOX_SIZE - sizeof(*tlv); i++) { + tlv = (struct avs_tlv *)(payload + offset); + tlv->type = va_arg(args, u32); + tlv->length = va_arg(args, u32); + + offset += sizeof(*tlv) + tlv->length; + if (offset > AVS_MAILBOX_SIZE) + break; + + memcpy(tlv->value, va_arg(args, u8*), tlv->length); + } + + if (i == num_tlvs) + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_FIRMWARE_CONFIG, payload, offset); + else + ret = -ERANGE; + + va_end(args); + kfree(payload); + if (ret) + dev_err(adev->dev, "set fw cfg failed: %d\n", ret); return ret; } @@ -517,10 +560,12 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg) AVS_BASEFW_HARDWARE_CONFIG, NULL, 0, &payload, &payload_size); if (ret) - return ret; + goto err; /* Non-zero payload expected for HARDWARE_CONFIG. */ - if (!payload_size) - return -EREMOTEIO; + if (!payload_size) { + ret = -EREMOTEIO; + goto err; + } while (offset < payload_size) { tlv = (struct avs_tlv *)(payload + offset); @@ -590,6 +635,9 @@ int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg) exit: /* No longer needed, free it as it's owned by the get_large_config() caller. */ kfree(payload); +err: + if (ret) + dev_err(adev->dev, "get hw cfg failed: %d\n", ret); return ret; } @@ -629,13 +677,6 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, (u8 *)&cpr_fmt, sizeof(cpr_fmt)); } -int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, - struct avs_volume_cfg *vol) -{ - return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol, - sizeof(*vol)); -} - int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, struct avs_volume_cfg **vols, size_t *num_vols) { @@ -658,6 +699,110 @@ int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_ return 0; } +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, + (u8 *)vol, sizeof(*vol)); +} + +int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vols, size_t num_vols) +{ + struct avs_tlv *tlv; + size_t offset; + size_t size; + u8 *payload; + int ret, i; + + size = num_vols * sizeof(*vols); + size += num_vols * sizeof(*tlv); + if (size > AVS_MAILBOX_SIZE) + return -EINVAL; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + for (offset = i = 0; i < num_vols; i++) { + tlv = (struct avs_tlv *)(payload + offset); + + tlv->type = AVS_PEAKVOL_VOLUME; + tlv->length = sizeof(*vols); + memcpy(tlv->value, &vols[i], tlv->length); + + offset += sizeof(*tlv) + tlv->length; + } + + ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload, + size); + kfree(payload); + return ret; +} + +int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg **mutes, size_t *num_mutes) +{ + size_t payload_size; + u8 *payload; + int ret; + + ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, NULL, 0, + &payload, &payload_size); + if (ret) + return ret; + + /* Non-zero payload expected for PEAKVOL_MUTE. */ + if (!payload_size) + return -EREMOTEIO; + + *mutes = (struct avs_mute_cfg *)payload; + *num_mutes = payload_size / sizeof(**mutes); + + return 0; +} + +int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mute) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, + (u8 *)mute, sizeof(*mute)); +} + +int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mutes, size_t num_mutes) +{ + struct avs_tlv *tlv; + size_t offset; + size_t size; + u8 *payload; + int ret, i; + + size = num_mutes * sizeof(*mutes); + size += num_mutes * sizeof(*tlv); + if (size > AVS_MAILBOX_SIZE) + return -EINVAL; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + for (offset = i = 0; i < num_mutes; i++) { + tlv = (struct avs_tlv *)(payload + offset); + + tlv->type = AVS_PEAKVOL_MUTE; + tlv->length = sizeof(*mutes); + memcpy(tlv->value, &mutes[i], tlv->length); + + offset += sizeof(*tlv) + tlv->length; + } + + ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload, + size); + kfree(payload); + return ret; +} + #ifdef CONFIG_DEBUG_FS int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) { diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 4e609a08863c..55c04b0142ae 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2022 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -93,12 +93,16 @@ union avs_global_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_global_msg) == 8); struct avs_tlv { u32 type; u32 length; u32 value[]; } __packed; +static_assert(sizeof(struct avs_tlv) == 8); + +#define avs_tlv_size(tlv) struct_size(tlv, value, (tlv)->length / 4) enum avs_module_msg_type { AVS_MOD_INIT_INSTANCE = 0, @@ -155,6 +159,7 @@ union avs_module_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_module_msg) == 8); #define AVS_IPC_NOT_SUPPORTED 15 @@ -190,6 +195,7 @@ union avs_reply_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_reply_msg) == 8); enum avs_notify_msg_type { AVS_NOTIFY_PHRASE_DETECTED = 4, @@ -226,6 +232,7 @@ union avs_notify_msg { } ext; }; } __packed; +static_assert(sizeof(union avs_notify_msg) == 8); #define AVS_MSG(hdr) { .val = hdr } @@ -264,6 +271,7 @@ struct avs_notify_voice_data { u16 kpd_score; u16 reserved; } __packed; +static_assert(sizeof(struct avs_notify_voice_data) == 4); struct avs_notify_res_data { u32 resource_type; @@ -272,6 +280,7 @@ struct avs_notify_res_data { u32 reserved; u32 data[6]; } __packed; +static_assert(sizeof(struct avs_notify_res_data) == 40); struct avs_notify_mod_data { u32 module_instance_id; @@ -279,6 +288,7 @@ struct avs_notify_mod_data { u32 data_size; u32 data[]; } __packed; +static_assert(sizeof(struct avs_notify_mod_data) == 12); /* ROM messages */ enum avs_rom_control_msg_type { @@ -332,6 +342,7 @@ struct avs_dxstate_info { u32 core_mask; /* which cores are subject for power transition */ u32 dx_mask; /* bit[n]=1 core n goes to D0, bit[n]=0 it goes to D3 */ } __packed; +static_assert(sizeof(struct avs_dxstate_info) == 8); int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup); int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming); @@ -367,11 +378,13 @@ struct avs_skl_log_state { u32 enable; u32 min_priority; } __packed; +static_assert(sizeof(struct avs_skl_log_state) == 8); struct avs_skl_log_state_info { u32 core_mask; struct avs_skl_log_state logs_core[]; } __packed; +static_assert(sizeof(struct avs_skl_log_state_info) == 4); struct avs_apl_log_state_info { u32 aging_timer_period; @@ -379,6 +392,7 @@ struct avs_apl_log_state_info { u32 core_mask; struct avs_skl_log_state logs_core[]; } __packed; +static_assert(sizeof(struct avs_apl_log_state_info) == 12); enum avs_icl_log_priority { AVS_ICL_LOG_CRITICAL = 0, @@ -403,6 +417,7 @@ struct avs_icl_log_state_info { u32 enable; u32 logs_priorities_mask[]; } __packed; +static_assert(sizeof(struct avs_icl_log_state_info) == 12); int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size); @@ -438,6 +453,8 @@ enum avs_fw_cfg_params { AVS_FW_CFG_RESERVED, AVS_FW_CFG_POWER_GATING_POLICY, AVS_FW_CFG_ASSERT_MODE, + AVS_FW_CFG_RESERVED2, + AVS_FW_CFG_BUS_HARDWARE_ID, }; struct avs_fw_cfg { @@ -462,7 +479,14 @@ struct avs_fw_cfg { u32 power_gating_policy; }; +struct avs_bus_hwid { + u32 device; + u32 subsystem; + u8 revision; +}; + int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg); +int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...); enum avs_hw_cfg_params { AVS_HW_CFG_AVS_VER, @@ -521,6 +545,7 @@ struct avs_module_type { u32 lib_code:1; u32 rsvd:24; } __packed; +static_assert(sizeof(struct avs_module_type) == 4); union avs_segment_flags { u32 ul; @@ -537,12 +562,14 @@ union avs_segment_flags { u32 length:16; }; } __packed; +static_assert(sizeof(union avs_segment_flags) == 4); struct avs_segment_desc { union avs_segment_flags flags; u32 v_base_addr; u32 file_offset; } __packed; +static_assert(sizeof(struct avs_segment_desc) == 12); struct avs_module_entry { u16 module_id; @@ -559,11 +586,13 @@ struct avs_module_entry { u16 instance_bss_size; struct avs_segment_desc segments[3]; } __packed; +static_assert(sizeof(struct avs_module_entry) == 116); struct avs_mods_info { u32 count; struct avs_module_entry entries[]; } __packed; +static_assert(sizeof(struct avs_mods_info) == 4); static inline bool avs_module_entry_is_loaded(struct avs_module_entry *mentry) { @@ -577,6 +606,7 @@ struct avs_sys_time { u32 val_l; u32 val_u; } __packed; +static_assert(sizeof(struct avs_sys_time) == 8); int avs_ipc_set_system_time(struct avs_dev *adev); @@ -624,6 +654,9 @@ int avs_ipc_set_system_time(struct avs_dev *adev); #define AVS_INTELWOV_MOD_UUID \ GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9, 0x84, 0xF1, 0xEE, 0xB7) +#define AVS_WOVHOSTM_MOD_UUID \ + GUID_INIT(0xF9ED62B7, 0x092E, 0x4A90, 0x8F, 0x4D, 0x82, 0xDA, 0xA8, 0xB3, 0x8F, 0x3B) + /* channel map */ enum avs_channel_index { AVS_CHANNEL_LEFT = 0, @@ -666,8 +699,9 @@ enum avs_sample_type { AVS_SAMPLE_TYPE_FLOAT = 4, }; -#define AVS_CHANNELS_MAX 8 +#define AVS_COEFF_CHANNELS_MAX 8 #define AVS_ALL_CHANNELS_MASK UINT_MAX +#define AVS_CHANNELS_MAX 16 struct avs_audio_format { u32 sampling_freq; @@ -680,6 +714,7 @@ struct avs_audio_format { u32 sample_type:8; u32 reserved:8; } __packed; +static_assert(sizeof(struct avs_audio_format) == 24); struct avs_modcfg_base { u32 cpc; @@ -688,12 +723,14 @@ struct avs_modcfg_base { u32 is_pages; struct avs_audio_format audio_fmt; } __packed; +static_assert(sizeof(struct avs_modcfg_base) == 40); struct avs_pin_format { u32 pin_index; u32 iobs; struct avs_audio_format audio_fmt; } __packed; +static_assert(sizeof(struct avs_pin_format) == 32); struct avs_modcfg_ext { struct avs_modcfg_base base; @@ -703,6 +740,7 @@ struct avs_modcfg_ext { /* input pin formats followed by output ones */ struct avs_pin_format pin_fmts[]; } __packed; +static_assert(sizeof(struct avs_modcfg_ext) == 56); enum avs_dma_type { AVS_DMA_HDA_HOST_OUTPUT = 0, @@ -726,6 +764,7 @@ union avs_virtual_index { u8 instance:3; } dmic; } __packed; +static_assert(sizeof(union avs_virtual_index) == 1); union avs_connector_node_id { u32 val; @@ -735,6 +774,7 @@ union avs_connector_node_id { u32 rsvd:19; }; } __packed; +static_assert(sizeof(union avs_connector_node_id) == 4); #define INVALID_PIPELINE_ID 0xFF #define INVALID_NODE_ID \ @@ -747,16 +787,45 @@ union avs_gtw_attributes { u32 rsvd:31; }; } __packed; +static_assert(sizeof(union avs_gtw_attributes) == 4); + +#define AVS_GTW_DMA_CONFIG_ID 0x1000 +#define AVS_DMA_METHOD_HDA 1 + +struct avs_dma_device_stream_channel_map { + u32 device_address; + u32 channel_map; +} __packed; +static_assert(sizeof(struct avs_dma_device_stream_channel_map) == 8); + +struct avs_dma_stream_channel_map { + u32 device_count; + struct avs_dma_device_stream_channel_map map[16]; +} __packed; +static_assert(sizeof(struct avs_dma_stream_channel_map) == 132); + +struct avs_dma_cfg { + u8 dma_method; + u8 pre_allocated; + u16 rsvd; + u32 dma_channel_id; + u32 stream_id; + struct avs_dma_stream_channel_map map; + u32 config_size; + u8 config[] __counted_by(config_size); +} __packed; +static_assert(sizeof(struct avs_dma_cfg) == 148); struct avs_copier_gtw_cfg { union avs_connector_node_id node_id; u32 dma_buffer_size; u32 config_length; - struct { + union { union avs_gtw_attributes attrs; - u32 blob[]; + DECLARE_FLEX_ARRAY(u32, blob); } config; } __packed; +static_assert(sizeof(struct avs_copier_gtw_cfg) == 16); struct avs_copier_cfg { struct avs_modcfg_base base; @@ -764,6 +833,7 @@ struct avs_copier_cfg { u32 feature_mask; struct avs_copier_gtw_cfg gtw_cfg; } __packed; +static_assert(sizeof(struct avs_copier_cfg) == 84); struct avs_volume_cfg { u32 channel_id; @@ -772,45 +842,62 @@ struct avs_volume_cfg { u32 reserved; /* alignment */ u64 curve_duration; } __packed; +static_assert(sizeof(struct avs_volume_cfg) == 24); + +struct avs_mute_cfg { + u32 channel_id; + u32 mute; + u32 curve_type; + u32 reserved; /* alignment */ + u64 curve_duration; +} __packed; +static_assert(sizeof(struct avs_mute_cfg) == 24); struct avs_peakvol_cfg { struct avs_modcfg_base base; struct avs_volume_cfg vols[]; } __packed; +static_assert(sizeof(struct avs_peakvol_cfg) == 40); struct avs_micsel_cfg { struct avs_modcfg_base base; struct avs_audio_format out_fmt; } __packed; +static_assert(sizeof(struct avs_micsel_cfg) == 64); struct avs_mux_cfg { struct avs_modcfg_base base; struct avs_audio_format ref_fmt; struct avs_audio_format out_fmt; } __packed; +static_assert(sizeof(struct avs_mux_cfg) == 88); struct avs_updown_mixer_cfg { struct avs_modcfg_base base; u32 out_channel_config; u32 coefficients_select; - s32 coefficients[AVS_CHANNELS_MAX]; + s32 coefficients[AVS_COEFF_CHANNELS_MAX]; u32 channel_map; } __packed; +static_assert(sizeof(struct avs_updown_mixer_cfg) == 84); struct avs_src_cfg { struct avs_modcfg_base base; u32 out_freq; } __packed; +static_assert(sizeof(struct avs_src_cfg) == 44); struct avs_probe_gtw_cfg { union avs_connector_node_id node_id; u32 dma_buffer_size; } __packed; +static_assert(sizeof(struct avs_probe_gtw_cfg) == 8); struct avs_probe_cfg { struct avs_modcfg_base base; struct avs_probe_gtw_cfg gtw_cfg; } __packed; +static_assert(sizeof(struct avs_probe_cfg) == 48); struct avs_aec_cfg { struct avs_modcfg_base base; @@ -818,24 +905,38 @@ struct avs_aec_cfg { struct avs_audio_format out_fmt; u32 cpc_lp_mode; } __packed; +static_assert(sizeof(struct avs_aec_cfg) == 92); struct avs_asrc_cfg { struct avs_modcfg_base base; u32 out_freq; - u32 rsvd0:1; - u32 mode:1; + u32 mode:2; u32 rsvd2:2; u32 disable_jitter_buffer:1; u32 rsvd3:27; } __packed; +static_assert(sizeof(struct avs_asrc_cfg) == 48); struct avs_wov_cfg { struct avs_modcfg_base base; u32 cpc_lp_mode; } __packed; +static_assert(sizeof(struct avs_wov_cfg) == 44); + +struct avs_whm_cfg { + struct avs_modcfg_base base; + /* Audio format for output pin 0 */ + struct avs_audio_format ref_fmt; + struct avs_audio_format out_fmt; + u32 wake_tick_period; + struct avs_copier_gtw_cfg gtw_cfg; +} __packed; +static_assert(sizeof(struct avs_whm_cfg) == 108); /* Module runtime parameters */ +#define AVS_VENDOR_CONFIG 0xFF + enum avs_copier_runtime_param { AVS_COPIER_SET_SINK_FORMAT = 2, }; @@ -845,6 +946,7 @@ struct avs_copier_sink_format { struct avs_audio_format src_fmt; struct avs_audio_format sink_fmt; } __packed; +static_assert(sizeof(struct avs_copier_sink_format) == 52); int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, u8 instance_id, u32 sink_id, @@ -853,6 +955,7 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, enum avs_peakvol_runtime_param { AVS_PEAKVOL_VOLUME = 0, + AVS_PEAKVOL_MUTE = 3, }; enum avs_audio_curve_type { @@ -860,10 +963,18 @@ enum avs_audio_curve_type { AVS_AUDIO_CURVE_WINDOWS_FADE = 1, }; -int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, - struct avs_volume_cfg *vol); int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, struct avs_volume_cfg **vols, size_t *num_vols); +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol); +int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vols, size_t num_vols); +int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg **mutes, size_t *num_mutes); +int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mute); +int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mutes, size_t num_mutes); #define AVS_PROBE_INST_ID 0 @@ -878,6 +989,7 @@ struct avs_probe_dma { union avs_connector_node_id node_id; u32 dma_buffer_size; } __packed; +static_assert(sizeof(struct avs_probe_dma) == 8); enum avs_probe_type { AVS_PROBE_TYPE_INPUT = 0, @@ -894,6 +1006,7 @@ union avs_probe_point_id { u32 index:6; } id; } __packed; +static_assert(sizeof(union avs_probe_point_id) == 4); enum avs_connection_purpose { AVS_CONNECTION_PURPOSE_EXTRACT = 0, @@ -906,6 +1019,7 @@ struct avs_probe_point_desc { u32 purpose; union avs_connector_node_id node_id; } __packed; +static_assert(sizeof(struct avs_probe_point_desc) == 12); int avs_ipc_probe_get_dma(struct avs_dev *adev, struct avs_probe_dma **dmas, size_t *num_dmas); int avs_ipc_probe_attach_dma(struct avs_dev *adev, struct avs_probe_dma *dmas, size_t num_dmas); diff --git a/sound/soc/intel/avs/mtl.c b/sound/soc/intel/avs/mtl.c new file mode 100644 index 000000000000..e7b7915b2a82 --- /dev/null +++ b/sound/soc/intel/avs/mtl.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2021-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "registers.h" +#include "trace.h" + +#define MTL_HfDSSGBL_BASE 0x1000 +#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) +#define MTL_HfDSSCS_SPA BIT(16) +#define MTL_HfDSSCS_CPA BIT(24) + +#define MTL_DSPCS_BASE 0x178D00 +#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) +#define MTL_DSPCCTL_SPA BIT(0) +#define MTL_DSPCCTL_CPA BIT(8) +#define MTL_DSPCCTL_OSEL GENMASK(25, 24) +#define MTL_DSPCCTL_OSEL_HOST BIT(25) + +#define MTL_HfINT_BASE 0x1100 +#define MTL_REG_HfINTIPPTR (MTL_HfINT_BASE + 0x8) +#define MTL_REG_HfHIPCIE (MTL_HfINT_BASE + 0x40) +#define MTL_HfINTIPPTR_PTR GENMASK(20, 0) +#define MTL_HfHIPCIE_IE BIT(0) + +#define MTL_DWICTL_INTENL_IE BIT(0) +#define MTL_DWICTL_FINALSTATUSL_IPC BIT(0) /* same as ADSPIS_IPC */ + +static int avs_mtl_core_power_on(struct avs_dev *adev) +{ + u32 reg; + int ret; + + /* Power up DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) { + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); + return ret; + } + + /* Prevent power gating of DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, + MTL_HfPWRCTL_WPDSPHPxPG); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS, reg, + (reg & MTL_HfPWRSTS_DSPHPxPGS) == MTL_HfPWRSTS_DSPHPxPGS, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + + /* Set ownership to HOST. */ + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); + return ret; +} + +static int avs_mtl_core_power_off(struct avs_dev *adev) +{ + u32 reg; + + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL, MTL_HfPWRCTL_WPDSPHPxPG, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); + + /* Power down DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); + + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == 0, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); +} + +int avs_mtl_core_power(struct avs_dev *adev, u32 core_mask, bool power) +{ + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + if (power) + return avs_mtl_core_power_on(adev); + return avs_mtl_core_power_off(adev); +} + +int avs_mtl_core_reset(struct avs_dev *adev, u32 core_mask, bool power) +{ + /* No logical equivalent on ACE 1.x. */ + return 0; +} + +int avs_mtl_core_stall(struct avs_dev *adev, u32 core_mask, bool stall) +{ + u32 value, reg; + int ret; + + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + value = snd_hdac_adsp_readl(adev, MTL_REG_DSPCCTL); + trace_avs_dsp_core_op(value, core_mask, "stall", stall); + if (value == UINT_MAX) + return 0; + + value = stall ? 0 : MTL_DSPCCTL_SPA; + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_SPA, value); + + value = stall ? 0 : MTL_DSPCCTL_CPA; + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_DSPCCTL, + reg, (reg & MTL_DSPCCTL_CPA) == value, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) + dev_err(adev->dev, "core_mask %d %sstall failed: %d\n", + core_mask, stall ? "" : "un", ret); + return ret; +} + +static void avs_mtl_ipc_interrupt(struct avs_dev *adev) +{ + const struct avs_spec *spec = adev->spec; + u32 hipc_ack, hipc_rsp; + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); + + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); + + /* DSP acked host's request. */ + if (hipc_ack & spec->hipc->ack_done_mask) { + complete(&adev->ipc->done_completion); + + /* Tell DSP it has our attention. */ + snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask, + spec->hipc->ack_done_mask); + } + + /* DSP sent new response to process. */ + if (hipc_rsp & spec->hipc->rsp_busy_mask) { + union avs_reply_msg msg; + + msg.primary = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDR); + msg.ext.val = snd_hdac_adsp_readl(adev, MTL_REG_HfIPCxTDD); + + avs_dsp_process_response(adev, msg.val); + + /* Tell DSP we accepted its message. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDR, + MTL_HfIPCxTDR_BUSY, MTL_HfIPCxTDR_BUSY); + /* Ack this response. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxTDA, MTL_HfIPCxTDA_BUSY, 0); + } + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY); +} + +irqreturn_t avs_mtl_dsp_interrupt(struct avs_dev *adev) +{ + u32 adspis = snd_hdac_adsp_readl(adev, MTL_DWICTL_REG_FINALSTATUSL); + irqreturn_t ret = IRQ_NONE; + + if (adspis == UINT_MAX) + return ret; + + if (adspis & MTL_DWICTL_FINALSTATUSL_IPC) { + avs_mtl_ipc_interrupt(adev); + ret = IRQ_HANDLED; + } + + return ret; +} + +void avs_mtl_interrupt_control(struct avs_dev *adev, bool enable) +{ + if (enable) { + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, + MTL_DWICTL_INTENL_IE); + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, MTL_HfHIPCIE_IE); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, + AVS_ADSP_HIPCCTL_DONE); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_BUSY); + } else { + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_BUSY, 0); + snd_hdac_adsp_updatel(adev, MTL_REG_HfIPCxCTL, AVS_ADSP_HIPCCTL_DONE, 0); + snd_hdac_adsp_updatew(adev, MTL_REG_HfHIPCIE, MTL_HfHIPCIE_IE, 0); + snd_hdac_adsp_updatel(adev, MTL_DWICTL_REG_INTENL, MTL_DWICTL_INTENL_IE, 0); + } +} diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index e785fc2a7008..ed8f0ea0e10d 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021 Intel Corporation. All rights reserved. +// Copyright(c) 2021 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // -#include <sound/intel-nhlt.h> +#include <linux/acpi.h> +#include <acpi/nhlt.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include "avs.h" @@ -114,157 +115,308 @@ avs_path_find_variant(struct avs_dev *adev, return NULL; } -__maybe_unused -static bool avs_dma_type_is_host(u32 dma_type) -{ - return dma_type == AVS_DMA_HDA_HOST_OUTPUT || - dma_type == AVS_DMA_HDA_HOST_INPUT; -} +static struct acpi_nhlt_config * +avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t); -__maybe_unused -static bool avs_dma_type_is_link(u32 dma_type) +int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template, + struct snd_pcm_hw_constraint_list *rate_list, + struct snd_pcm_hw_constraint_list *channels_list, + struct snd_pcm_hw_constraint_list *sample_bits_list) { - return !avs_dma_type_is_host(dma_type); -} + struct avs_tplg_path *path_template; + unsigned int *rlist, *clist, *slist; + size_t i; + + i = 0; + list_for_each_entry(path_template, &template->path_list, node) + i++; + + rlist = kcalloc(i, sizeof(*rlist), GFP_KERNEL); + clist = kcalloc(i, sizeof(*clist), GFP_KERNEL); + slist = kcalloc(i, sizeof(*slist), GFP_KERNEL); + + i = 0; + list_for_each_entry(path_template, &template->path_list, node) { + struct avs_tplg_pipeline *pipeline_template; + + list_for_each_entry(pipeline_template, &path_template->ppl_list, node) { + struct avs_tplg_module *module_template; + + list_for_each_entry(module_template, &pipeline_template->mod_list, node) { + const guid_t *type = &module_template->cfg_ext->type; + struct acpi_nhlt_config *blob; + + if (!guid_equal(type, &AVS_COPIER_MOD_UUID) && + !guid_equal(type, &AVS_WOVHOSTM_MOD_UUID)) + continue; + + switch (module_template->cfg_ext->copier.dma_type) { + case AVS_DMA_DMIC_LINK_INPUT: + case AVS_DMA_I2S_LINK_OUTPUT: + case AVS_DMA_I2S_LINK_INPUT: + break; + default: + continue; + } + + blob = avs_nhlt_config_or_default(adev, module_template); + if (IS_ERR(blob)) + continue; + + rlist[i] = path_template->fe_fmt->sampling_freq; + clist[i] = path_template->fe_fmt->num_channels; + slist[i] = path_template->fe_fmt->bit_depth; + i++; + } + } + } -__maybe_unused -static bool avs_dma_type_is_output(u32 dma_type) -{ - return dma_type == AVS_DMA_HDA_HOST_OUTPUT || - dma_type == AVS_DMA_HDA_LINK_OUTPUT || - dma_type == AVS_DMA_I2S_LINK_OUTPUT; + if (i) { + rate_list->count = i; + rate_list->list = rlist; + channels_list->count = i; + channels_list->list = clist; + sample_bits_list->count = i; + sample_bits_list->list = slist; + } else { + kfree(rlist); + kfree(clist); + kfree(slist); + } + + return i; } -__maybe_unused -static bool avs_dma_type_is_input(u32 dma_type) +static void avs_init_node_id(union avs_connector_node_id *node_id, + struct avs_tplg_modcfg_ext *te, u32 dma_id) { - return !avs_dma_type_is_output(dma_type); + node_id->val = 0; + node_id->dma_type = te->copier.dma_type; + + switch (node_id->dma_type) { + case AVS_DMA_DMIC_LINK_INPUT: + case AVS_DMA_I2S_LINK_OUTPUT: + case AVS_DMA_I2S_LINK_INPUT: + /* Gateway's virtual index is statically assigned in the topology. */ + node_id->vindex = te->copier.vindex.val; + break; + + case AVS_DMA_HDA_HOST_OUTPUT: + case AVS_DMA_HDA_HOST_INPUT: + /* Gateway's virtual index is dynamically assigned with DMA ID */ + node_id->vindex = dma_id; + break; + + case AVS_DMA_HDA_LINK_OUTPUT: + case AVS_DMA_HDA_LINK_INPUT: + node_id->vindex = te->copier.vindex.val | dma_id; + break; + + default: + *node_id = INVALID_NODE_ID; + break; + } } -static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) -{ - struct nhlt_acpi_table *nhlt = adev->nhlt; - struct avs_tplg_module *t = mod->template; - struct avs_copier_cfg *cfg; - struct nhlt_specific_cfg *ep_blob; - union avs_connector_node_id node_id = {0}; - size_t cfg_size, data_size = 0; - void *data = NULL; - u32 dma_type; - int ret; +/* Every BLOB contains at least gateway attributes. */ +static struct acpi_nhlt_config *default_blob = (struct acpi_nhlt_config *)&(u32[2]) {4}; - dma_type = t->cfg_ext->copier.dma_type; - node_id.dma_type = dma_type; +static struct acpi_nhlt_config * +avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t) +{ + struct acpi_nhlt_format_config *fmtcfg; + struct avs_tplg_modcfg_ext *te; + struct avs_audio_format *fmt; + int link_type, dev_type; + int bus_id, dir; - switch (dma_type) { - struct avs_audio_format *fmt; - int direction; + te = t->cfg_ext; + switch (te->copier.dma_type) { case AVS_DMA_I2S_LINK_OUTPUT: - case AVS_DMA_I2S_LINK_INPUT: - if (avs_dma_type_is_input(dma_type)) - direction = SNDRV_PCM_STREAM_CAPTURE; - else - direction = SNDRV_PCM_STREAM_PLAYBACK; - - if (t->cfg_ext->copier.blob_fmt) - fmt = t->cfg_ext->copier.blob_fmt; - else if (direction == SNDRV_PCM_STREAM_CAPTURE) - fmt = t->in_fmt; - else - fmt = t->cfg_ext->copier.out_fmt; - - ep_blob = intel_nhlt_get_endpoint_blob(adev->dev, - nhlt, t->cfg_ext->copier.vindex.i2s.instance, - NHLT_LINK_SSP, fmt->valid_bit_depth, fmt->bit_depth, - fmt->num_channels, fmt->sampling_freq, direction, - NHLT_DEVICE_I2S); - if (!ep_blob) { - dev_err(adev->dev, "no I2S ep_blob found\n"); - return -ENOENT; - } - - data = ep_blob->caps; - data_size = ep_blob->size; - /* I2S gateway's vindex is statically assigned in topology */ - node_id.vindex = t->cfg_ext->copier.vindex.val; + link_type = ACPI_NHLT_LINKTYPE_SSP; + dev_type = ACPI_NHLT_DEVICETYPE_CODEC; + bus_id = te->copier.vindex.i2s.instance; + dir = SNDRV_PCM_STREAM_PLAYBACK; + fmt = te->copier.out_fmt; + break; + case AVS_DMA_I2S_LINK_INPUT: + link_type = ACPI_NHLT_LINKTYPE_SSP; + dev_type = ACPI_NHLT_DEVICETYPE_CODEC; + bus_id = te->copier.vindex.i2s.instance; + dir = SNDRV_PCM_STREAM_CAPTURE; + fmt = t->in_fmt; break; case AVS_DMA_DMIC_LINK_INPUT: - direction = SNDRV_PCM_STREAM_CAPTURE; - - if (t->cfg_ext->copier.blob_fmt) - fmt = t->cfg_ext->copier.blob_fmt; - else - fmt = t->in_fmt; - - ep_blob = intel_nhlt_get_endpoint_blob(adev->dev, nhlt, 0, - NHLT_LINK_DMIC, fmt->valid_bit_depth, - fmt->bit_depth, fmt->num_channels, - fmt->sampling_freq, direction, NHLT_DEVICE_DMIC); - if (!ep_blob) { - dev_err(adev->dev, "no DMIC ep_blob found\n"); - return -ENOENT; - } + link_type = ACPI_NHLT_LINKTYPE_PDM; + dev_type = -1; /* ignored */ + bus_id = 0; + dir = SNDRV_PCM_STREAM_CAPTURE; + fmt = t->in_fmt; + break; - data = ep_blob->caps; - data_size = ep_blob->size; - /* DMIC gateway's vindex is statically assigned in topology */ - node_id.vindex = t->cfg_ext->copier.vindex.val; + default: + return default_blob; + } - break; + /* Override format selection if necessary. */ + if (te->copier.blob_fmt) + fmt = te->copier.blob_fmt; + + fmtcfg = acpi_nhlt_find_fmtcfg(link_type, dev_type, dir, bus_id, + fmt->num_channels, fmt->sampling_freq, fmt->valid_bit_depth, + fmt->bit_depth); + if (!fmtcfg) { + dev_warn(adev->dev, "Endpoint format configuration not found.\n"); + return ERR_PTR(-ENOENT); + } + + if (fmtcfg->config.capabilities_size < default_blob->capabilities_size) + return ERR_PTR(-ETOOSMALL); + /* The firmware expects the payload to be DWORD-aligned. */ + if (fmtcfg->config.capabilities_size % sizeof(u32)) + return ERR_PTR(-EINVAL); + + return &fmtcfg->config; +} + +static int avs_append_dma_cfg(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) +{ + u32 dma_type = t->cfg_ext->copier.dma_type; + struct avs_dma_cfg *dma; + struct avs_tlv *tlv; + size_t tlv_size; + + if (!avs_platattr_test(adev, ALTHDA)) + return 0; + switch (dma_type) { case AVS_DMA_HDA_HOST_OUTPUT: case AVS_DMA_HDA_HOST_INPUT: - /* HOST gateway's vindex is dynamically assigned with DMA id */ - node_id.vindex = mod->owner->owner->dma_id; - break; - case AVS_DMA_HDA_LINK_OUTPUT: case AVS_DMA_HDA_LINK_INPUT: - node_id.vindex = t->cfg_ext->copier.vindex.val | - mod->owner->owner->dma_id; - break; - - case INVALID_OBJECT_ID: + return 0; default: - node_id = INVALID_NODE_ID; break; } - cfg_size = sizeof(*cfg) + data_size; - /* Every config-BLOB contains gateway attributes. */ - if (data_size) - cfg_size -= sizeof(cfg->gtw_cfg.config.attrs); - if (cfg_size > AVS_MAILBOX_SIZE) - return -EINVAL; + tlv_size = sizeof(*tlv) + sizeof(*dma); + if (*cfg_size + tlv_size > AVS_MAILBOX_SIZE) + return -E2BIG; + + /* DMA config is a TLV tailing the existing payload. */ + tlv = (struct avs_tlv *)>w->config.blob[gtw->config_length]; + tlv->type = AVS_GTW_DMA_CONFIG_ID; + tlv->length = sizeof(*dma); + + dma = (struct avs_dma_cfg *)tlv->value; + memset(dma, 0, sizeof(*dma)); + dma->dma_method = AVS_DMA_METHOD_HDA; + dma->pre_allocated = true; + dma->dma_channel_id = dma_id; + dma->stream_id = dma_id + 1; + + gtw->config_length += tlv_size / sizeof(u32); + *cfg_size += tlv_size; + + return 0; +} + +static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, + struct avs_tplg_module *t, u32 dma_id, size_t *cfg_size) +{ + struct acpi_nhlt_config *blob; + size_t gtw_size; + + blob = avs_nhlt_config_or_default(adev, t); + if (IS_ERR(blob)) + return PTR_ERR(blob); + gtw_size = blob->capabilities_size; + if (*cfg_size + gtw_size > AVS_MAILBOX_SIZE) + return -E2BIG; + + gtw->config_length = gtw_size / sizeof(u32); + memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size); + *cfg_size += gtw_size; + + return avs_append_dma_cfg(adev, gtw, t, dma_id, cfg_size); +} + +static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_modcfg_ext *te; + struct avs_copier_cfg *cfg; + size_t cfg_size; + u32 dma_id; + int ret; + + te = t->cfg_ext; cfg = adev->modcfg_buf; - memset(cfg, 0, cfg_size); + dma_id = mod->owner->owner->dma_id; + cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config); + + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); + if (ret) + return ret; + cfg->base.cpc = t->cfg_base->cpc; cfg->base.ibs = t->cfg_base->ibs; cfg->base.obs = t->cfg_base->obs; cfg->base.is_pages = t->cfg_base->is_pages; cfg->base.audio_fmt = *t->in_fmt; - cfg->out_fmt = *t->cfg_ext->copier.out_fmt; - cfg->feature_mask = t->cfg_ext->copier.feature_mask; - cfg->gtw_cfg.node_id = node_id; - cfg->gtw_cfg.dma_buffer_size = t->cfg_ext->copier.dma_buffer_size; - /* config_length in DWORDs */ - cfg->gtw_cfg.config_length = DIV_ROUND_UP(data_size, 4); - if (data) - memcpy(&cfg->gtw_cfg.config, data, data_size); + cfg->out_fmt = *te->copier.out_fmt; + cfg->feature_mask = te->copier.feature_mask; + avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id); + cfg->gtw_cfg.dma_buffer_size = te->copier.dma_buffer_size; + mod->gtw_attrs = cfg->gtw_cfg.config.attrs; + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, cfg_size, &mod->instance_id); + return ret; +} + +static int avs_whm_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_modcfg_ext *te; + struct avs_whm_cfg *cfg; + size_t cfg_size; + u32 dma_id; + int ret; + + te = t->cfg_ext; + cfg = adev->modcfg_buf; + dma_id = mod->owner->owner->dma_id; + cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config); + + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, dma_id, &cfg_size); + if (ret) + return ret; + + cfg->base.cpc = t->cfg_base->cpc; + cfg->base.ibs = t->cfg_base->ibs; + cfg->base.obs = t->cfg_base->obs; + cfg->base.is_pages = t->cfg_base->is_pages; + cfg->base.audio_fmt = *t->in_fmt; + cfg->ref_fmt = *te->whm.ref_fmt; + cfg->out_fmt = *te->whm.out_fmt; + cfg->wake_tick_period = te->whm.wake_tick_period; + avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id); + cfg->gtw_cfg.dma_buffer_size = te->whm.dma_buffer_size; mod->gtw_attrs = cfg->gtw_cfg.config.attrs; - ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, - t->core_id, t->domain, cfg, cfg_size, - &mod->instance_id); + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, cfg_size, &mod->instance_id); return ret; } -static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod) +static struct soc_mixer_control *avs_get_module_control(struct avs_path_module *mod, + const char *name) { struct avs_tplg_module *t = mod->template; struct avs_tplg_path_template *path_tmpl; @@ -280,27 +432,93 @@ static struct avs_control_data *avs_get_module_control(struct avs_path_module *m mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value; ctl_data = (struct avs_control_data *)mc->dobj.private; - if (ctl_data->id == t->ctl_id) - return ctl_data; + if (ctl_data->id == t->ctl_id && strstr(w->kcontrols[i]->id.name, name)) + return mc; } return NULL; } +int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input) +{ + struct avs_volume_cfg vols[SND_SOC_TPLG_MAX_CHAN] = {{0}}; + struct avs_control_data *ctl_data; + struct avs_tplg_module *t; + int ret, i; + + ctl_data = mc->dobj.private; + t = mod->template; + if (!input) + input = ctl_data->values; + + if (mc->num_channels) { + for (i = 0; i < mc->num_channels; i++) { + vols[i].channel_id = i; + vols[i].target_volume = input[i]; + vols[i].curve_type = t->cfg_ext->peakvol.curve_type; + vols[i].curve_duration = t->cfg_ext->peakvol.curve_duration; + } + + ret = avs_ipc_peakvol_set_volumes(adev, mod->module_id, mod->instance_id, vols, + mc->num_channels); + return AVS_IPC_RET(ret); + } + + /* Target all channels if no individual selected. */ + vols[0].channel_id = AVS_ALL_CHANNELS_MASK; + vols[0].target_volume = input[0]; + vols[0].curve_type = t->cfg_ext->peakvol.curve_type; + vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration; + + ret = avs_ipc_peakvol_set_volume(adev, mod->module_id, mod->instance_id, &vols[0]); + return AVS_IPC_RET(ret); +} + +int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input) +{ + struct avs_mute_cfg mutes[SND_SOC_TPLG_MAX_CHAN] = {{0}}; + struct avs_control_data *ctl_data; + struct avs_tplg_module *t; + int ret, i; + + ctl_data = mc->dobj.private; + t = mod->template; + if (!input) + input = ctl_data->values; + + if (mc->num_channels) { + for (i = 0; i < mc->num_channels; i++) { + mutes[i].channel_id = i; + mutes[i].mute = !input[i]; + mutes[i].curve_type = t->cfg_ext->peakvol.curve_type; + mutes[i].curve_duration = t->cfg_ext->peakvol.curve_duration; + } + + ret = avs_ipc_peakvol_set_mutes(adev, mod->module_id, mod->instance_id, mutes, + mc->num_channels); + return AVS_IPC_RET(ret); + } + + /* Target all channels if no individual selected. */ + mutes[0].channel_id = AVS_ALL_CHANNELS_MASK; + mutes[0].mute = !input[0]; + mutes[0].curve_type = t->cfg_ext->peakvol.curve_type; + mutes[0].curve_duration = t->cfg_ext->peakvol.curve_duration; + + ret = avs_ipc_peakvol_set_mute(adev, mod->module_id, mod->instance_id, &mutes[0]); + return AVS_IPC_RET(ret); +} + static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) { struct avs_tplg_module *t = mod->template; - struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; struct avs_peakvol_cfg *cfg; - int volume = S32_MAX; size_t cfg_size; int ret; - ctl_data = avs_get_module_control(mod); - if (ctl_data) - volume = ctl_data->volume; - - /* As 2+ channels controls are unsupported, have a single block for all channels. */ cfg_size = struct_size(cfg, vols, 1); if (cfg_size > AVS_MAILBOX_SIZE) return -EINVAL; @@ -312,15 +530,28 @@ static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) cfg->base.obs = t->cfg_base->obs; cfg->base.is_pages = t->cfg_base->is_pages; cfg->base.audio_fmt = *t->in_fmt; - cfg->vols[0].target_volume = volume; cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK; - cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE; - cfg->vols[0].curve_duration = 0; + cfg->vols[0].target_volume = S32_MAX; + cfg->vols[0].curve_type = t->cfg_ext->peakvol.curve_type; + cfg->vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration; ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, t->domain, cfg, cfg_size, &mod->instance_id); + if (ret) + return ret; - return ret; + /* Now configure both VOLUME and MUTE parameters. */ + mc = avs_get_module_control(mod, "Volume"); + if (mc) { + ret = avs_peakvol_set_volume(adev, mod, mc, NULL); + if (ret) + return ret; + } + + mc = avs_get_module_control(mod, "Switch"); + if (mc) + return avs_peakvol_set_mute(adev, mod, mc, NULL); + return 0; } static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod) @@ -336,7 +567,7 @@ static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *m cfg.base.audio_fmt = *t->in_fmt; cfg.out_channel_config = t->cfg_ext->updown_mix.out_channel_config; cfg.coefficients_select = t->cfg_ext->updown_mix.coefficients_select; - for (i = 0; i < AVS_CHANNELS_MAX; i++) + for (i = 0; i < AVS_COEFF_CHANNELS_MAX; i++) cfg.coefficients[i] = t->cfg_ext->updown_mix.coefficients[i]; cfg.channel_map = t->cfg_ext->updown_mix.channel_map; @@ -367,6 +598,7 @@ static int avs_asrc_create(struct avs_dev *adev, struct avs_path_module *mod) struct avs_tplg_module *t = mod->template; struct avs_asrc_cfg cfg; + memset(&cfg, 0, sizeof(cfg)); cfg.base.cpc = t->cfg_base->cpc; cfg.base.ibs = t->cfg_base->ibs; cfg.base.obs = t->cfg_base->obs; @@ -534,6 +766,7 @@ static struct avs_module_create avs_module_create[] = { { &AVS_ASRC_MOD_UUID, avs_asrc_create }, { &AVS_INTELWOV_MOD_UUID, avs_wov_create }, { &AVS_PROBE_MOD_UUID, avs_probe_create }, + { &AVS_WOVHOSTM_MOD_UUID, avs_whm_create }, }; static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod) @@ -710,8 +943,6 @@ static int avs_path_pipeline_arm(struct avs_dev *adev, /* bind current module to next module on list */ source = mod; sink = list_next_entry(mod, node); - if (!source || !sink) - return -EINVAL; ret = avs_ipc_bind(adev, source->module_id, source->instance_id, sink->module_id, sink->instance_id, 0, 0); diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index 657f7b093e80..c65ed84aa853 100644 --- a/sound/soc/intel/avs/path.h +++ b/sound/soc/intel/avs/path.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021 Intel Corporation. All rights reserved. + * Copyright(c) 2021 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -69,4 +69,14 @@ int avs_path_reset(struct avs_path *path); int avs_path_pause(struct avs_path *path); int avs_path_run(struct avs_path *path, int trigger); +int avs_path_set_constraint(struct avs_dev *adev, struct avs_tplg_path_template *template, + struct snd_pcm_hw_constraint_list *rate_list, + struct snd_pcm_hw_constraint_list *channels_list, + struct snd_pcm_hw_constraint_list *sample_bits_list); + +int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input); +int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input); + #endif diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 2cafbc392cdb..405cfc1ab0cb 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -16,20 +16,28 @@ #include <sound/soc-component.h> #include "avs.h" #include "path.h" +#include "pcm.h" #include "topology.h" +#include "utils.h" #include "../../codecs/hda.h" struct avs_dma_data { struct avs_tplg_path_template *template; struct avs_path *path; - /* - * link stream is stored within substream's runtime - * private_data to fulfill the needs of codec BE path - * - * host stream assigned - */ - struct hdac_ext_stream *host_stream; + struct avs_dev *adev; + /* LINK-stream utilized in BE operations while HOST in FE ones. */ + union { + struct hdac_ext_stream *link_stream; + struct hdac_ext_stream *host_stream; + }; + + struct snd_pcm_hw_constraint_list rate_list; + struct snd_pcm_hw_constraint_list channels_list; + struct snd_pcm_hw_constraint_list sample_bits_list; + + struct work_struct period_elapsed_work; + struct hdac_ext_link *link; struct snd_pcm_substream *substream; }; @@ -56,15 +64,69 @@ avs_dai_find_path_template(struct snd_soc_dai *dai, bool is_fe, int direction) return dw->priv; } -static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool is_fe, - const struct snd_soc_dai_ops *ops) +static void avs_period_elapsed_work(struct work_struct *work) +{ + struct avs_dma_data *data = container_of(work, struct avs_dma_data, period_elapsed_work); + + snd_pcm_period_elapsed(data->substream); +} + +void avs_period_elapsed(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); + + schedule_work(&data->period_elapsed_work); +} + +static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule); +static int avs_hw_constraints_init(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct avs_dev *adev = to_avs_dev(dai->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm_hw_constraint_list *r, *c, *s; struct avs_tplg_path_template *template; struct avs_dma_data *data; + int ret; + + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + data = snd_soc_dai_get_dma_data(dai, substream); + r = &(data->rate_list); + c = &(data->channels_list); + s = &(data->sample_bits_list); + + template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream); + ret = avs_path_set_constraint(data->adev, template, r, c, s); + if (ret <= 0) + return ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, r); + if (ret < 0) + return ret; - template = avs_dai_find_path_template(dai, is_fe, substream->stream); + ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, c); + if (ret < 0) + return ret; + + ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, s); + if (ret < 0) + return ret; + + return 0; +} + +static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct avs_tplg_path_template *template; + struct avs_dma_data *data; + + template = avs_dai_find_path_template(dai, !rtd->dai_link->no_pcm, substream->stream); if (!template) { dev_err(dai->dev, "no %s path for dai %s, invalid tplg?\n", snd_pcm_stream_str(substream), dai->name); @@ -77,12 +139,32 @@ static int avs_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_d data->substream = substream; data->template = template; + data->adev = adev; + INIT_WORK(&data->period_elapsed_work, avs_period_elapsed_work); snd_soc_dai_set_dma_data(dai, substream, data); if (rtd->dai_link->ignore_suspend) adev->num_lp_paths++; - return 0; + return avs_hw_constraints_init(substream, dai); +} + +static void avs_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct avs_dma_data *data; + + data = snd_soc_dai_get_dma_data(dai, substream); + + if (rtd->dai_link->ignore_suspend) + data->adev->num_lp_paths--; + + kfree(data->rate_list.list); + kfree(data->channels_list.list); + kfree(data->sample_bits_list.list); + + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(data); } static int avs_dai_hw_params(struct snd_pcm_substream *substream, @@ -92,7 +174,6 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream, { struct avs_dma_data *data; struct avs_path *path; - struct avs_dev *adev = to_avs_dev(dai->dev); int ret; data = snd_soc_dai_get_dma_data(dai, substream); @@ -109,7 +190,7 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream, params_rate(be_hw_params), params_channels(be_hw_params), params_width(be_hw_params), params_physical_width(be_hw_params)); - path = avs_path_create(adev, dma_id, data->template, fe_hw_params, be_hw_params); + path = avs_path_create(data->adev, dma_id, data->template, fe_hw_params, be_hw_params); if (IS_ERR(path)) { ret = PTR_ERR(path); dev_err(dai->dev, "create path failed: %d\n", ret); @@ -129,6 +210,7 @@ static int avs_dai_be_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dpcm *dpcm; be = snd_soc_substream_to_rtd(substream); + /* dpcm_fe_dai_open() guarantees the list is not empty at this point. */ for_each_dpcm_fe(be, substream->stream, dpcm) { fe = dpcm->fe; fe_hw_params = &fe->dpcm[substream->stream].hw_params; @@ -137,8 +219,7 @@ static int avs_dai_be_hw_params(struct snd_pcm_substream *substream, return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id); } -static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int avs_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct avs_dma_data *data; int ret; @@ -159,28 +240,6 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst return ret; } -static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops; - -static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -{ - return avs_dai_startup(substream, dai, false, &avs_dai_nonhda_be_ops); -} - -static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct avs_dev *adev = to_avs_dev(dai->dev); - struct avs_dma_data *data; - - if (rtd->dai_link->ignore_suspend) - adev->num_lp_paths--; - - data = snd_soc_dai_get_dma_data(dai, substream); - - snd_soc_dai_set_dma_data(dai, substream, NULL); - kfree(data); -} - static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { @@ -209,11 +268,6 @@ static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct return 0; } -static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) -{ - return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); -} - static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -265,108 +319,165 @@ static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cm } static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { - .startup = avs_dai_nonhda_be_startup, - .shutdown = avs_dai_nonhda_be_shutdown, + .startup = avs_dai_startup, + .shutdown = avs_dai_shutdown, .hw_params = avs_dai_nonhda_be_hw_params, .hw_free = avs_dai_nonhda_be_hw_free, - .prepare = avs_dai_nonhda_be_prepare, + .prepare = avs_dai_prepare, .trigger = avs_dai_nonhda_be_trigger, }; -static const struct snd_soc_dai_ops avs_dai_hda_be_ops; +static int __avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, + struct hdac_ext_link *link) +{ + struct hdac_ext_stream *link_stream; + struct avs_dma_data *data; + int ret; + + ret = avs_dai_startup(substream, dai); + if (ret) + return ret; + + data = snd_soc_dai_get_dma_data(dai, substream); + link_stream = snd_hdac_ext_stream_assign(&data->adev->base.core, substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!link_stream) { + avs_dai_shutdown(substream, dai); + return -EBUSY; + } + + data->link_stream = link_stream; + data->link = link; + return 0; +} static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - return avs_dai_startup(substream, dai, false, &avs_dai_hda_be_ops); + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct hdac_ext_link *link; + struct avs_dma_data *data; + struct hda_codec *codec; + int ret; + + codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); + + link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); + if (!link) + return -EINVAL; + + ret = __avs_dai_hda_be_startup(substream, dai, link); + if (!ret) { + data = snd_soc_dai_get_dma_data(dai, substream); + substream->runtime->private_data = data->link_stream; + } + + return ret; +} + +static int avs_dai_i2shda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_SSP); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); +} + +static int avs_dai_dmichda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_DMIC); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); } static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - return avs_dai_nonhda_be_shutdown(substream, dai); + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); + + snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); + substream->runtime->private_data = NULL; + avs_dai_shutdown(substream, dai); +} + +static void avs_dai_althda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); + + snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); + avs_dai_shutdown(substream, dai); } static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { struct avs_dma_data *data; - struct hdac_ext_stream *link_stream; data = snd_soc_dai_get_dma_data(dai, substream); if (data->path) return 0; - link_stream = substream->runtime->private_data; - return avs_dai_be_hw_params(substream, hw_params, dai, - hdac_stream(link_stream)->stream_tag - 1); + hdac_stream(data->link_stream)->stream_tag - 1); } static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct avs_dma_data *data; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; - struct hda_codec *codec; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + struct avs_dma_data *data; data = snd_soc_dai_get_dma_data(dai, substream); if (!data->path) return 0; - link_stream = substream->runtime->private_data; + link_stream = data->link_stream; link_stream->link_prepared = false; avs_path_free(data->path); data->path = NULL; /* clear link <-> stream mapping */ - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_clear_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); return 0; } static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; - struct hda_codec *codec; - struct hdac_bus *bus; + struct avs_dma_data *data; unsigned int format_val; unsigned int bits; int ret; - link_stream = runtime->private_data; + data = snd_soc_dai_get_dma_data(dai, substream); + link_stream = data->link_stream; + if (link_stream->link_prepared) return 0; - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - bus = &codec->bus->core; stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, stream_info->sig_bits); format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); + snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true); snd_hdac_ext_stream_reset(link_stream); snd_hdac_ext_stream_setup(link_stream, format_val); - link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_set_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); - ret = avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); + ret = avs_dai_prepare(substream, dai); if (ret) return ret; @@ -378,14 +489,12 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_stream; struct avs_dma_data *data; int ret = 0; dev_dbg(dai->dev, "entry %s cmd=%d\n", __func__, cmd); data = snd_soc_dai_get_dma_data(dai, substream); - link_stream = substream->runtime->private_data; switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: @@ -394,7 +503,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, fallthrough; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_start(link_stream); + snd_hdac_ext_stream_start(data->link_stream); ret = avs_path_pause(data->path); if (ret < 0) { @@ -417,7 +526,7 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, if (ret < 0) dev_err(dai->dev, "pause BE path failed: %d\n", ret); - snd_hdac_ext_stream_clear(link_stream); + snd_hdac_ext_stream_clear(data->link_stream); ret = avs_path_reset(data->path); if (ret < 0) @@ -441,82 +550,110 @@ static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { .trigger = avs_dai_hda_be_trigger, }; -static const unsigned int rates[] = { - 8000, 11025, 12000, 16000, - 22050, 24000, 32000, 44100, - 48000, 64000, 88200, 96000, - 128000, 176400, 192000, +static const struct snd_soc_dai_ops avs_dai_i2shda_be_ops = { + .startup = avs_dai_i2shda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, }; -static const struct snd_pcm_hw_constraint_list hw_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, +static const struct snd_soc_dai_ops avs_dai_dmichda_be_ops = { + .startup = avs_dai_dmichda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, }; -const struct snd_soc_dai_ops avs_dai_fe_ops; +static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) +{ + struct snd_interval *interval = hw_param_interval(params, rule->var); + struct snd_interval to; -static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) + snd_interval_any(&to); + to.integer = interval->integer; + to.max = interval->max; + /* + * Commonly 2ms buffer size is used in HDA scenarios whereas 4ms is used + * when streaming through GPDMA. Align to the latter to account for both. + */ + to.min = params_rate(params) / 1000 * 4; + + if (rule->var == SNDRV_PCM_HW_PARAM_PERIOD_SIZE) + to.min /= params_periods(params); + + return snd_interval_refine(interval, &to); +} + +static int avs_pcm_hw_constraints_init(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - struct avs_dma_data *data; - struct avs_dev *adev = to_avs_dev(dai->dev); - struct hdac_bus *bus = &adev->base.core; + int ret; + + ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) + return ret; + + /* Avoid wrap-around with wall-clock. */ + ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); + if (ret < 0) + return ret; + + /* Adjust buffer and period size based on the audio format. */ + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, hw_rule_param_size, NULL, + SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, hw_rule_param_size, NULL, + SNDRV_PCM_HW_PARAM_FORMAT, SNDRV_PCM_HW_PARAM_CHANNELS, + SNDRV_PCM_HW_PARAM_RATE, -1); + + return 0; +} + +static int avs_dai_fe_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ struct hdac_ext_stream *host_stream; + struct avs_dma_data *data; + struct hdac_bus *bus; int ret; - ret = avs_dai_startup(substream, dai, true, &avs_dai_fe_ops); + ret = avs_pcm_hw_constraints_init(substream); + if (ret) + return ret; + + ret = avs_dai_startup(substream, dai); if (ret) return ret; data = snd_soc_dai_get_dma_data(dai, substream); + bus = &data->adev->base.core; host_stream = snd_hdac_ext_stream_assign(bus, substream, HDAC_EXT_STREAM_TYPE_HOST); if (!host_stream) { - ret = -EBUSY; - goto err; + avs_dai_shutdown(substream, dai); + return -EBUSY; } data->host_stream = host_stream; - ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - goto err; - - /* avoid wrap-around with wall-clock */ - ret = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 20, 178000000); - if (ret < 0) - goto err; - - ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_rates); - if (ret < 0) - goto err; - snd_pcm_set_sync(substream); dev_dbg(dai->dev, "%s fe STARTUP tag %d str %p", __func__, hdac_stream(host_stream)->stream_tag, substream); return 0; - -err: - kfree(data); - return ret; } static void avs_dai_fe_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct avs_dev *adev = to_avs_dev(dai->dev); struct avs_dma_data *data; - if (rtd->dai_link->ignore_suspend) - adev->num_lp_paths--; - data = snd_soc_dai_get_dma_data(dai, substream); - snd_soc_dai_set_dma_data(dai, substream, NULL); snd_hdac_ext_stream_release(data->host_stream, HDAC_EXT_STREAM_TYPE_HOST); - kfree(data); + avs_dai_shutdown(substream, dai); } static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream, @@ -540,6 +677,7 @@ static int avs_dai_fe_hw_params(struct snd_pcm_substream *substream, hdac_stream(host_stream)->format_val = 0; fe = snd_soc_substream_to_rtd(substream); + /* dpcm_fe_dai_open() guarantees the list is not empty at this point. */ for_each_dpcm_be(fe, substream->stream, dpcm) { be = dpcm->be; be_hw_params = &be->dpcm[substream->stream].hw_params; @@ -606,11 +744,11 @@ static int avs_dai_fe_hw_free(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_soc_pcm_stream *stream_info; + const struct snd_soc_pcm_stream *stream_info; struct avs_dma_data *data; - struct avs_dev *adev = to_avs_dev(dai->dev); struct hdac_ext_stream *host_stream; unsigned int format_val; + struct hdac_bus *bus; unsigned int bits; int ret; @@ -620,6 +758,8 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so if (hdac_stream(host_stream)->prepared) return 0; + bus = hdac_stream(host_stream)->bus; + snd_hdac_ext_stream_decouple(bus, data->host_stream, true); snd_hdac_stream_reset(hdac_stream(host_stream)); stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); @@ -635,7 +775,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so if (ret < 0) return ret; - ret = avs_dai_prepare(adev, substream, dai); + ret = avs_dai_prepare(substream, dai); if (ret) return ret; @@ -887,7 +1027,8 @@ static int avs_component_probe(struct snd_soc_component *component) else mach->tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-generic-tplg.bin"); - + if (!mach->tplg_filename) + return -ENOMEM; filename = kasprintf(GFP_KERNEL, "%s/%s", component->driver->topology_name_prefix, mach->tplg_filename); if (!filename) @@ -1226,7 +1367,7 @@ static int avs_component_construct(struct snd_soc_component *component, return 0; } -static const struct snd_soc_component_driver avs_component_driver = { +static struct snd_soc_component_driver avs_component_driver = { .name = "avs-pcm", .probe = avs_component_probe, .remove = avs_component_remove, @@ -1241,7 +1382,7 @@ static const struct snd_soc_component_driver avs_component_driver = { }; int avs_soc_component_register(struct device *dev, const char *name, - const struct snd_soc_component_driver *drv, + struct snd_soc_component_driver *drv, struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) { struct avs_soc_component *acomp; @@ -1259,13 +1400,14 @@ int avs_soc_component_register(struct device *dev, const char *name, acomp->base.name = name; INIT_LIST_HEAD(&acomp->node); + drv->use_dai_pcm_id = !obsolete_card_names; + return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); } static struct snd_soc_dai_driver dmic_cpu_dais[] = { { .name = "DMIC Pin", - .ops = &avs_dai_nonhda_be_ops, .capture = { .stream_name = "DMIC Rx", .channels_min = 1, @@ -1276,7 +1418,6 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { }, { .name = "DMIC WoV Pin", - .ops = &avs_dai_nonhda_be_ops, .capture = { .stream_name = "DMIC WoV Rx", .channels_min = 1, @@ -1289,17 +1430,27 @@ static struct snd_soc_dai_driver dmic_cpu_dais[] = { int avs_dmic_platform_register(struct avs_dev *adev, const char *name) { + const struct snd_soc_dai_ops *ops; + + if (avs_platattr_test(adev, ALTHDA)) + ops = &avs_dai_dmichda_be_ops; + else + ops = &avs_dai_nonhda_be_ops; + + dmic_cpu_dais[0].ops = ops; + dmic_cpu_dais[1].ops = ops; return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, ARRAY_SIZE(dmic_cpu_dais)); } static const struct snd_soc_dai_driver i2s_dai_template = { - .ops = &avs_dai_nonhda_be_ops, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000 | - SNDRV_PCM_RATE_KNOT, + SNDRV_PCM_RATE_12000 | + SNDRV_PCM_RATE_24000 | + SNDRV_PCM_RATE_128000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | @@ -1308,9 +1459,11 @@ static const struct snd_soc_dai_driver i2s_dai_template = { }, .capture = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000 | - SNDRV_PCM_RATE_KNOT, + SNDRV_PCM_RATE_12000 | + SNDRV_PCM_RATE_24000 | + SNDRV_PCM_RATE_128000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, .subformats = SNDRV_PCM_SUBFMTBIT_MSBITS_20 | @@ -1323,10 +1476,15 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l unsigned long *tdms) { struct snd_soc_dai_driver *cpus, *dai; + const struct snd_soc_dai_ops *ops; size_t ssp_count, cpu_count; int i, j; ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; + if (avs_platattr_test(adev, ALTHDA)) + ops = &avs_dai_i2shda_be_ops; + else + ops = &avs_dai_nonhda_be_ops; cpu_count = 0; for_each_set_bit(i, &port_mask, ssp_count) @@ -1336,7 +1494,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l for_each_set_bit(i, &port_mask, ssp_count) cpu_count += hweight_long(tdms[i]); - cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL); + cpus = devm_kcalloc(adev->dev, cpu_count, sizeof(*cpus), GFP_KERNEL); if (!cpus) return -ENOMEM; @@ -1354,6 +1512,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) return -ENOMEM; + dai->ops = ops; dai++; } } @@ -1362,7 +1521,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l goto plat_register; for_each_set_bit(i, &port_mask, ssp_count) { - for_each_set_bit(j, &tdms[i], ssp_count) { + for_each_set_bit(j, &tdms[i], AVS_CHANNELS_MAX) { memcpy(dai, &i2s_dai_template, sizeof(*dai)); dai->name = @@ -1374,6 +1533,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) return -ENOMEM; + dai->ops = ops; dai++; } } @@ -1387,7 +1547,7 @@ static const struct snd_soc_dai_driver hda_cpu_dai = { .ops = &avs_dai_hda_be_ops, .playback = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, @@ -1397,7 +1557,7 @@ static const struct snd_soc_dai_driver hda_cpu_dai = { }, .capture = { .channels_min = 1, - .channels_max = 8, + .channels_max = AVS_CHANNELS_MAX, .rates = SNDRV_PCM_RATE_8000_192000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, @@ -1416,7 +1576,7 @@ static void avs_component_hda_unregister_dais(struct snd_soc_component *componen mach = dev_get_platdata(component->card->dev); codec = mach->pdata; - sprintf(name, "%s-cpu", dev_name(&codec->core.dev)); + snprintf(name, sizeof(name), "%s-cpu", dev_name(&codec->core.dev)); for_each_component_dais_safe(component, dai, save) { int stream; @@ -1436,6 +1596,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component) struct snd_soc_dapm_context *dapm; struct snd_soc_dai_driver *dais; struct snd_soc_acpi_mach *mach; + struct avs_mach_pdata *pdata; struct hda_codec *codec; struct hda_pcm *pcm; const char *cname; @@ -1445,7 +1606,8 @@ static int avs_component_hda_probe(struct snd_soc_component *component) if (!mach) return -EINVAL; - codec = mach->pdata; + pdata = mach->pdata; + codec = pdata->codec; if (list_empty(&codec->pcm_list_head)) return -EINVAL; list_for_each_entry(pcm, &codec->pcm_list_head, list) @@ -1522,6 +1684,7 @@ static int avs_component_hda_probe(struct snd_soc_component *component) if (ret < 0) { dev_err(component->dev, "create widgets failed: %d\n", ret); + snd_soc_unregister_dai(dai); goto exit; } } @@ -1536,16 +1699,14 @@ exit: static void avs_component_hda_remove(struct snd_soc_component *component) { - avs_component_hda_unregister_dais(component); avs_component_remove(component); + avs_component_hda_unregister_dais(component); } static int avs_component_hda_open(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_stream; - struct hda_codec *codec; if (!rtd->dai_link->no_pcm) { struct snd_pcm_hardware hwparams = avs_pcm_hardware; @@ -1577,41 +1738,16 @@ static int avs_component_hda_open(struct snd_soc_component *component, return snd_soc_set_runtime_hwparams(substream, &hwparams); } - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!link_stream) - return -EBUSY; - - substream->runtime->private_data = link_stream; - return 0; -} - -static int avs_component_hda_close(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_stream; - - /* only BE DAI links are handled here */ - if (!rtd->dai_link->no_pcm) - return 0; - - link_stream = substream->runtime->private_data; - snd_hdac_ext_stream_release(link_stream, HDAC_EXT_STREAM_TYPE_LINK); - substream->runtime->private_data = NULL; - return 0; } -static const struct snd_soc_component_driver avs_hda_component_driver = { +static struct snd_soc_component_driver avs_hda_component_driver = { .name = "avs-hda-pcm", .probe = avs_component_hda_probe, .remove = avs_component_hda_remove, .suspend = avs_component_suspend, .resume = avs_component_resume, .open = avs_component_hda_open, - .close = avs_component_hda_close, .pointer = avs_component_pointer, .mmap = avs_component_mmap, .pcm_construct = avs_component_construct, diff --git a/sound/soc/intel/avs/pcm.h b/sound/soc/intel/avs/pcm.h new file mode 100644 index 000000000000..0f3615c90398 --- /dev/null +++ b/sound/soc/intel/avs/pcm.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright(c) 2024 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#ifndef __SOUND_SOC_INTEL_AVS_PCM_H +#define __SOUND_SOC_INTEL_AVS_PCM_H + +#include <sound/pcm.h> + +void avs_period_elapsed(struct snd_pcm_substream *substream); + +#endif diff --git a/sound/soc/intel/avs/probes.c b/sound/soc/intel/avs/probes.c index 817e543036f2..a42736b9aa55 100644 --- a/sound/soc/intel/avs/probes.c +++ b/sound/soc/intel/avs/probes.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -19,8 +19,11 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id struct avs_probe_cfg cfg = {{0}}; struct avs_module_entry mentry; u8 dummy; + int ret; - avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); + ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); + if (ret) + return ret; /* * Probe module uses no cycles, audio data format and input and output @@ -39,11 +42,12 @@ static int avs_dsp_init_probe(struct avs_dev *adev, union avs_connector_node_id static void avs_dsp_delete_probe(struct avs_dev *adev) { struct avs_module_entry mentry; + int ret; - avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); - - /* There is only ever one probe module instance. */ - avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); + ret = avs_get_module_entry(adev, &AVS_PROBE_MOD_UUID, &mentry); + if (!ret) + /* There is only ever one probe module instance. */ + avs_dsp_delete_module(adev, mentry.module_id, 0, INVALID_PIPELINE_ID, 0); } static inline struct hdac_ext_stream *avs_compr_get_host_stream(struct snd_compr_stream *cstream) @@ -280,7 +284,7 @@ static struct snd_soc_dai_driver probe_cpu_dais[] = { }, }; -static const struct snd_soc_component_driver avs_probe_component_driver = { +static struct snd_soc_component_driver avs_probe_component_driver = { .name = "avs-probe-compr", .compress_ops = &avs_probe_compress_ops, .module_get_upon_open = 1, /* increment refcount when a stream is opened */ diff --git a/sound/soc/intel/avs/ptl.c b/sound/soc/intel/avs/ptl.c new file mode 100644 index 000000000000..2be4b545c91d --- /dev/null +++ b/sound/soc/intel/avs/ptl.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2024-2025 Intel Corporation + * + * Authors: Cezary Rojewski <cezary.rojewski@intel.com> + * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> + */ + +#include <sound/hdaudio_ext.h> +#include "avs.h" +#include "registers.h" +#include "trace.h" + +#define MTL_HfDSSGBL_BASE 0x1000 +#define MTL_REG_HfDSSCS (MTL_HfDSSGBL_BASE + 0x0) +#define MTL_HfDSSCS_SPA BIT(16) +#define MTL_HfDSSCS_CPA BIT(24) + +#define MTL_DSPCS_BASE 0x178D00 +#define MTL_REG_DSPCCTL (MTL_DSPCS_BASE + 0x4) +#define MTL_DSPCCTL_OSEL GENMASK(25, 24) +#define MTL_DSPCCTL_OSEL_HOST BIT(25) + +static int avs_ptl_core_power_on(struct avs_dev *adev) +{ + u32 reg; + int ret; + + /* Power up DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, MTL_HfDSSCS_SPA); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "power dsp", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == MTL_HfDSSCS_CPA, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + if (ret) { + dev_err(adev->dev, "power on domain dsp failed: %d\n", ret); + return ret; + } + + /* Prevent power gating of DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, + MTL_HfPWRCTL2_WPDSPHPxPG); + trace_avs_dsp_core_op(1, AVS_MAIN_CORE_MASK, "prevent dsp PG", true); + + ret = snd_hdac_adsp_readl_poll(adev, MTL_REG_HfPWRSTS2, reg, + (reg & MTL_HfPWRSTS2_DSPHPxPGS) == MTL_HfPWRSTS2_DSPHPxPGS, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); + + /* Set ownership to HOST. */ + snd_hdac_adsp_updatel(adev, MTL_REG_DSPCCTL, MTL_DSPCCTL_OSEL, MTL_DSPCCTL_OSEL_HOST); + return ret; +} + +static int avs_ptl_core_power_off(struct avs_dev *adev) +{ + u32 reg; + + /* Allow power gating of DSP domain. No STS polling as HOST is only one of its users. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfPWRCTL2, MTL_HfPWRCTL2_WPDSPHPxPG, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "allow dsp pg", false); + + /* Power down DSP domain. */ + snd_hdac_adsp_updatel(adev, MTL_REG_HfDSSCS, MTL_HfDSSCS_SPA, 0); + trace_avs_dsp_core_op(0, AVS_MAIN_CORE_MASK, "power dsp", false); + + return snd_hdac_adsp_readl_poll(adev, MTL_REG_HfDSSCS, reg, + (reg & MTL_HfDSSCS_CPA) == 0, + AVS_ADSPCS_INTERVAL_US, AVS_ADSPCS_TIMEOUT_US); +} + +static int avs_ptl_core_power(struct avs_dev *adev, u32 core_mask, bool power) +{ + core_mask &= AVS_MAIN_CORE_MASK; + if (!core_mask) + return 0; + + if (power) + return avs_ptl_core_power_on(adev); + return avs_ptl_core_power_off(adev); +} + +const struct avs_dsp_ops avs_ptl_dsp_ops = { + .power = avs_ptl_core_power, + .reset = avs_mtl_core_reset, + .stall = avs_lnl_core_stall, + .dsp_interrupt = avs_mtl_dsp_interrupt, + .int_control = avs_mtl_interrupt_control, + .load_basefw = avs_hda_load_basefw, + .load_lib = avs_hda_load_library, + .transfer_mods = avs_hda_transfer_modules, + .log_buffer_offset = avs_icl_log_buffer_offset, + .log_buffer_status = avs_apl_log_buffer_status, + .coredump = avs_apl_coredump, + .d0ix_toggle = avs_icl_d0ix_toggle, + .set_d0ix = avs_icl_set_d0ix, + AVS_SET_ENABLE_LOGS_OP(icl) +}; diff --git a/sound/soc/intel/avs/registers.h b/sound/soc/intel/avs/registers.h index 6126adca500c..97767882ffa1 100644 --- a/sound/soc/intel/avs/registers.h +++ b/sound/soc/intel/avs/registers.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. + * Copyright(c) 2021-2022 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -9,6 +9,8 @@ #ifndef __SOUND_SOC_INTEL_AVS_REGS_H #define __SOUND_SOC_INTEL_AVS_REGS_H +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/iopoll.h> #include <linux/sizes.h> #define AZX_PCIREG_PGCTL 0x44 @@ -33,6 +35,8 @@ #define AVS_ADSPCS_CSTALL_MASK(cm) ((cm) << 8) #define AVS_ADSPCS_SPA_MASK(cm) ((cm) << 16) #define AVS_ADSPCS_CPA_MASK(cm) ((cm) << 24) +#define AVS_ADSPCS_INTERVAL_US 500 +#define AVS_ADSPCS_TIMEOUT_US 10000 #define AVS_MAIN_CORE_MASK BIT(0) #define AVS_ADSP_HIPCCTL_BUSY BIT(0) @@ -65,16 +69,52 @@ #define CNL_ADSP_HIPCIDR_BUSY BIT(31) #define CNL_ADSP_HIPCIDA_DONE BIT(31) +/* MTL Intel HOST Inter-Processor Communication Registers */ +#define MTL_HfIPC_BASE 0x73000 +#define MTL_REG_HfIPCxTDR (MTL_HfIPC_BASE + 0x200) +#define MTL_REG_HfIPCxTDA (MTL_HfIPC_BASE + 0x204) +#define MTL_REG_HfIPCxIDR (MTL_HfIPC_BASE + 0x210) +#define MTL_REG_HfIPCxIDA (MTL_HfIPC_BASE + 0x214) +#define MTL_REG_HfIPCxCTL (MTL_HfIPC_BASE + 0x228) +#define MTL_REG_HfIPCxTDD (MTL_HfIPC_BASE + 0x300) +#define MTL_REG_HfIPCxIDD (MTL_HfIPC_BASE + 0x380) + +#define MTL_HfIPCxTDR_BUSY BIT(31) +#define MTL_HfIPCxTDA_BUSY BIT(31) +#define MTL_HfIPCxIDR_BUSY BIT(31) +#define MTL_HfIPCxIDA_DONE BIT(31) + +#define MTL_HfFLV_BASE 0x162000 +#define MTL_REG_HfFLGP(x, y) (MTL_HfFLV_BASE + 0x1200 + (x) * 0x20 + (y) * 0x08) +#define LNL_REG_HfDFR(x) (0x160200 + (x) * 0x8) + +#define MTL_DWICTL_BASE 0x1800 +#define MTL_DWICTL_REG_INTENL (MTL_DWICTL_BASE + 0x0) +#define MTL_DWICTL_REG_FINALSTATUSL (MTL_DWICTL_BASE + 0x30) + +#define MTL_HfPMCCU_BASE 0x1D00 +#define MTL_REG_HfCLKCTL (MTL_HfPMCCU_BASE + 0x10) +#define MTL_REG_HfPWRCTL (MTL_HfPMCCU_BASE + 0x18) +#define MTL_REG_HfPWRSTS (MTL_HfPMCCU_BASE + 0x1C) +#define MTL_REG_HfPWRCTL2 (MTL_HfPMCCU_BASE + 0x20) +#define MTL_REG_HfPWRSTS2 (MTL_HfPMCCU_BASE + 0x24) +#define MTL_HfPWRCTL_WPDSPHPxPG BIT(0) +#define MTL_HfPWRSTS_DSPHPxPGS BIT(0) +#define MTL_HfPWRCTL2_WPDSPHPxPG BIT(0) +#define MTL_HfPWRSTS2_DSPHPxPGS BIT(0) + /* Intel HD Audio SRAM windows base addresses */ #define SKL_ADSP_SRAM_BASE_OFFSET 0x8000 #define SKL_ADSP_SRAM_WINDOW_SIZE 0x2000 #define APL_ADSP_SRAM_BASE_OFFSET 0x80000 #define APL_ADSP_SRAM_WINDOW_SIZE 0x20000 +#define MTL_ADSP_SRAM_BASE_OFFSET 0x180000 +#define MTL_ADSP_SRAM_WINDOW_SIZE 0x8000 /* Constants used when accessing SRAM, space shared with firmware */ -#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram->base_offset) +#define AVS_FW_REG_BASE(adev) ((adev)->spec->hipc->sts_offset) #define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0) -#define AVS_FW_REG_ERROR_CODE(adev) (AVS_FW_REG_BASE(adev) + 0x4) +#define AVS_FW_REG_ERROR(adev) (AVS_FW_REG_BASE(adev) + 0x4) #define AVS_WINDOW_CHUNK_SIZE SZ_4K #define AVS_FW_REGS_SIZE AVS_WINDOW_CHUNK_SIZE @@ -98,4 +138,47 @@ #define avs_downlink_addr(adev) \ avs_sram_addr(adev, AVS_DOWNLINK_WINDOW) +#define snd_hdac_adsp_writeb(adev, reg, value) \ + snd_hdac_reg_writeb(&(adev)->base.core, (adev)->dsp_ba + (reg), value) +#define snd_hdac_adsp_readb(adev, reg) \ + snd_hdac_reg_readb(&(adev)->base.core, (adev)->dsp_ba + (reg)) +#define snd_hdac_adsp_writew(adev, reg, value) \ + snd_hdac_reg_writew(&(adev)->base.core, (adev)->dsp_ba + (reg), value) +#define snd_hdac_adsp_readw(adev, reg) \ + snd_hdac_reg_readw(&(adev)->base.core, (adev)->dsp_ba + (reg)) +#define snd_hdac_adsp_writel(adev, reg, value) \ + snd_hdac_reg_writel(&(adev)->base.core, (adev)->dsp_ba + (reg), value) +#define snd_hdac_adsp_readl(adev, reg) \ + snd_hdac_reg_readl(&(adev)->base.core, (adev)->dsp_ba + (reg)) +#define snd_hdac_adsp_writeq(adev, reg, value) \ + snd_hdac_reg_writeq(&(adev)->base.core, (adev)->dsp_ba + (reg), value) +#define snd_hdac_adsp_readq(adev, reg) \ + snd_hdac_reg_readq(&(adev)->base.core, (adev)->dsp_ba + (reg)) + +#define snd_hdac_adsp_updateb(adev, reg, mask, val) \ + snd_hdac_adsp_writeb(adev, reg, \ + (snd_hdac_adsp_readb(adev, reg) & ~(mask)) | (val)) +#define snd_hdac_adsp_updatew(adev, reg, mask, val) \ + snd_hdac_adsp_writew(adev, reg, \ + (snd_hdac_adsp_readw(adev, reg) & ~(mask)) | (val)) +#define snd_hdac_adsp_updatel(adev, reg, mask, val) \ + snd_hdac_adsp_writel(adev, reg, \ + (snd_hdac_adsp_readl(adev, reg) & ~(mask)) | (val)) +#define snd_hdac_adsp_updateq(adev, reg, mask, val) \ + snd_hdac_adsp_writeq(adev, reg, \ + (snd_hdac_adsp_readq(adev, reg) & ~(mask)) | (val)) + +#define snd_hdac_adsp_readb_poll(adev, reg, val, cond, delay_us, timeout_us) \ + readb_poll_timeout((adev)->dsp_ba + (reg), val, cond, \ + delay_us, timeout_us) +#define snd_hdac_adsp_readw_poll(adev, reg, val, cond, delay_us, timeout_us) \ + readw_poll_timeout((adev)->dsp_ba + (reg), val, cond, \ + delay_us, timeout_us) +#define snd_hdac_adsp_readl_poll(adev, reg, val, cond, delay_us, timeout_us) \ + readl_poll_timeout((adev)->dsp_ba + (reg), val, cond, \ + delay_us, timeout_us) +#define snd_hdac_adsp_readq_poll(adev, reg, val, cond, delay_us, timeout_us) \ + readq_poll_timeout((adev)->dsp_ba + (reg), val, cond, \ + delay_us, timeout_us) + #endif /* __SOUND_SOC_INTEL_AVS_REGS_H */ diff --git a/sound/soc/intel/avs/skl.c b/sound/soc/intel/avs/skl.c index d19f8953993f..d66ef000de9e 100644 --- a/sound/soc/intel/avs/skl.c +++ b/sound/soc/intel/avs/skl.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -10,31 +10,68 @@ #include <linux/slab.h> #include <sound/hdaudio_ext.h> #include "avs.h" +#include "cldma.h" #include "messages.h" +#include "registers.h" -irqreturn_t avs_skl_irq_thread(struct avs_dev *adev) +void avs_skl_ipc_interrupt(struct avs_dev *adev) { - union avs_reply_msg msg; - u32 hipct, hipcte; + const struct avs_spec *spec = adev->spec; + u32 hipc_ack, hipc_rsp; - hipct = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT); - hipcte = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE); + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, 0); - /* Ensure DSP sent new response to process. */ - if (!(hipct & SKL_ADSP_HIPCT_BUSY)) - return IRQ_NONE; + hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset); + hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset); - msg.primary = hipct; - msg.ext.val = hipcte; - avs_dsp_process_response(adev, msg.val); + /* DSP acked host's request. */ + if (hipc_ack & spec->hipc->ack_done_mask) { + complete(&adev->ipc->done_completion); - /* Tell DSP we accepted its message. */ - snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY, SKL_ADSP_HIPCT_BUSY); - /* Unmask busy interrupt. */ - snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL, AVS_ADSP_HIPCCTL_BUSY, - AVS_ADSP_HIPCCTL_BUSY); + /* Tell DSP it has our attention. */ + snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset, spec->hipc->ack_done_mask, + spec->hipc->ack_done_mask); + } - return IRQ_HANDLED; + /* DSP sent new response to process */ + if (hipc_rsp & spec->hipc->rsp_busy_mask) { + union avs_reply_msg msg; + + msg.primary = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT); + msg.ext.val = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCTE); + + avs_dsp_process_response(adev, msg.val); + + /* Tell DSP we accepted its message. */ + snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCT, SKL_ADSP_HIPCT_BUSY, + SKL_ADSP_HIPCT_BUSY); + } + + snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY, + AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY); +} + +static irqreturn_t avs_skl_dsp_interrupt(struct avs_dev *adev) +{ + u32 adspis = snd_hdac_adsp_readl(adev, AVS_ADSP_REG_ADSPIS); + irqreturn_t ret = IRQ_NONE; + + if (adspis == UINT_MAX) + return ret; + + if (adspis & AVS_ADSP_ADSPIS_CLDMA) { + hda_cldma_interrupt(&code_loader); + ret = IRQ_HANDLED; + } + + if (adspis & AVS_ADSP_ADSPIS_IPC) { + avs_skl_ipc_interrupt(adev); + ret = IRQ_HANDLED; + } + + return ret; } static int __maybe_unused @@ -128,8 +165,7 @@ const struct avs_dsp_ops avs_skl_dsp_ops = { .power = avs_dsp_core_power, .reset = avs_dsp_core_reset, .stall = avs_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_skl_irq_thread, + .dsp_interrupt = avs_skl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_cldma_load_basefw, .load_lib = avs_cldma_load_library, diff --git a/sound/soc/intel/avs/sysfs.c b/sound/soc/intel/avs/sysfs.c index cce21636fbc0..74b2e6f38d76 100644 --- a/sound/soc/intel/avs/sysfs.c +++ b/sound/soc/intel/avs/sysfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c index 0e052e7f6bac..9dbb3ad0954a 100644 --- a/sound/soc/intel/avs/tgl.c +++ b/sound/soc/intel/avs/tgl.c @@ -1,12 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2024 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2024 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // +#include <linux/pci.h> #include "avs.h" +#include "messages.h" + +#define CPUID_TSC_LEAF 0x15 static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) { @@ -35,16 +39,44 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal return avs_dsp_core_stall(adev, core_mask, stall); } +static int avs_tgl_config_basefw(struct avs_dev *adev) +{ + struct pci_dev *pci = adev->base.pci; + struct avs_bus_hwid hwid; + int ret; +#ifdef CONFIG_X86 + unsigned int ecx; + +#include <asm/cpuid/api.h> + ecx = cpuid_ecx(CPUID_TSC_LEAF); + if (ecx) { + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); + if (ret) + return AVS_IPC_RET(ret); + } +#endif + + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; + + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_BUS_HARDWARE_ID, sizeof(hwid), &hwid); + if (ret) + return AVS_IPC_RET(ret); + + return 0; +} + const struct avs_dsp_ops avs_tgl_dsp_ops = { .power = avs_tgl_dsp_core_power, .reset = avs_tgl_dsp_core_reset, .stall = avs_tgl_dsp_core_stall, - .irq_handler = avs_irq_handler, - .irq_thread = avs_cnl_irq_thread, + .dsp_interrupt = avs_cnl_dsp_interrupt, .int_control = avs_dsp_interrupt_control, .load_basefw = avs_icl_load_basefw, .load_lib = avs_hda_load_library, .transfer_mods = avs_hda_transfer_modules, + .config_basefw = avs_tgl_config_basefw, .log_buffer_offset = avs_icl_log_buffer_offset, .log_buffer_status = avs_apl_log_buffer_status, .coredump = avs_apl_coredump, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index 13061bd1488b..f2e4ad8b8e14 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021 Intel Corporation. All rights reserved. +// Copyright(c) 2021 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -815,6 +815,66 @@ static const struct avs_tplg_token_parser modcfg_ext_parsers[] = { .offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins), .parse = avs_parse_short_token, }, + { + .token = AVS_TKN_MODCFG_WHM_REF_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.ref_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_WHM_OUT_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.out_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_WHM_WAKE_TICK_PERIOD_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.wake_tick_period), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_VINDEX_U8, + .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.vindex), + .parse = avs_parse_byte_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_DMA_TYPE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_type), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_DMABUFF_SIZE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_buffer_size), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_BLOB_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.blob_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_VOLUME_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.target_volume), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_TYPE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_type), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_DURATION_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_duration), + .parse = avs_parse_word_token, + }, }; static const struct avs_tplg_token_parser pin_format_parsers[] = { @@ -1466,7 +1526,7 @@ avs_tplg_path_template_create(struct snd_soc_component *comp, struct avs_tplg *o static const struct avs_tplg_token_parser mod_init_config_parsers[] = { { - .token = AVS_TKN_MOD_INIT_CONFIG_ID_U32, + .token = AVS_TKN_INIT_CONFIG_ID_U32, .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, .offset = offsetof(struct avs_tplg_init_config, id), .parse = avs_parse_word_token, @@ -1519,7 +1579,7 @@ static int avs_tplg_parse_initial_configs(struct snd_soc_component *comp, esize = le32_to_cpu(tuples->size) + le32_to_cpu(tmp->size); ret = parse_dictionary_entries(comp, tuples, esize, config, 1, sizeof(*config), - AVS_TKN_MOD_INIT_CONFIG_ID_U32, + AVS_TKN_INIT_CONFIG_ID_U32, mod_init_config_parsers, ARRAY_SIZE(mod_init_config_parsers)); @@ -1545,8 +1605,8 @@ static int avs_route_load(struct snd_soc_component *comp, int index, { struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev); size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN; - char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int ssp_port, tdm_slot; + char *buf; /* See parse_link_formatted_string() for dynamic naming when(s). */ if (!avs_mach_singular_ssp(mach)) @@ -1557,13 +1617,24 @@ static int avs_route_load(struct snd_soc_component *comp, int index, return 0; tdm_slot = avs_mach_ssp_tdm(mach, ssp_port); + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot); - strscpy((char *)route->source, buf, len); + route->source = buf; + + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot); - strscpy((char *)route->sink, buf, len); + route->sink = buf; + if (route->control) { + buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot); - strscpy((char *)route->control, buf, len); + route->control = buf; } return 0; @@ -1582,6 +1653,8 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, if (!le32_to_cpu(dw->priv.size)) return 0; + w->no_wname_in_kcontrol_name = true; + if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) { dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n"); w->ignore_suspend = false; @@ -1595,8 +1668,8 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, /* See parse_link_formatted_string() for dynamic naming when(s). */ if (avs_mach_singular_tdm(mach, ssp_port)) { - /* size is based on possible %d -> SSP:TDM, where SSP and TDM < 10 + '\0' */ - size_t size = strlen(dw->name) + 2; + /* size is based on possible %d -> SSP:TDM, where SSP and TDM < 16 + '\0' */ + size_t size = strlen(dw->name) + 3; char *buf; tdm_slot = avs_mach_ssp_tdm(mach, ssp_port); @@ -1832,13 +1905,23 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return 0; } -#define AVS_CONTROL_OPS_VOLUME 257 +enum { + AVS_CONTROL_OPS_VOLUME = 257, + AVS_CONTROL_OPS_MUTE, +}; static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { { .id = AVS_CONTROL_OPS_VOLUME, .get = avs_control_volume_get, .put = avs_control_volume_put, + .info = avs_control_volume_info, + }, + { + .id = AVS_CONTROL_OPS_MUTE, + .get = avs_control_mute_get, + .put = avs_control_mute_put, + .info = avs_control_mute_info, }, }; @@ -1860,18 +1943,20 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_ struct avs_control_data *ctl_data; struct soc_mixer_control *mc; size_t block_size; - int ret; + int ret, i; switch (le32_to_cpu(hdr->type)) { case SND_SOC_TPLG_TYPE_MIXER: - tmc = container_of(hdr, typeof(*tmc), hdr); - tuples = tmc->priv.array; - block_size = le32_to_cpu(tmc->priv.size); break; default: return -EINVAL; } + mc = (struct soc_mixer_control *)ctmpl->private_value; + tmc = container_of(hdr, typeof(*tmc), hdr); + tuples = tmc->priv.array; + block_size = le32_to_cpu(tmc->priv.size); + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); if (!ctl_data) return -ENOMEM; @@ -1882,12 +1967,17 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_ if (ret) return ret; - mc = (struct soc_mixer_control *)ctmpl->private_value; mc->dobj.private = ctl_data; + if (tmc->invert) { + ctl_data->values[0] = mc->max; + for (i = 1; i < mc->num_channels; i++) + ctl_data->values[i] = mc->max; + } + return 0; } -static struct snd_soc_tplg_ops avs_tplg_ops = { +static const struct snd_soc_tplg_ops avs_tplg_ops = { .io_ops = avs_control_ops, .io_ops_count = ARRAY_SIZE(avs_control_ops), .control_load = avs_control_load, diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 6a59dd766603..f5601a4e3ec8 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2021 Intel Corporation. All rights reserved. + * Copyright(c) 2021 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -74,13 +74,20 @@ struct avs_tplg_modcfg_ext { union avs_virtual_index vindex; u32 dma_type; u32 dma_buffer_size; - u32 config_length; - /* config_data part of priv data */ } copier; struct { + struct avs_audio_format *ref_fmt; + struct avs_audio_format *out_fmt; + u32 wake_tick_period; + union avs_virtual_index vindex; + u32 dma_type; + u32 dma_buffer_size; + struct avs_audio_format *blob_fmt; /* optional override */ + } whm; + struct { u32 out_channel_config; u32 coefficients_select; - s32 coefficients[AVS_CHANNELS_MAX]; + s32 coefficients[AVS_COEFF_CHANNELS_MAX]; u32 channel_map; } updown_mix; struct { @@ -106,6 +113,11 @@ struct avs_tplg_modcfg_ext { struct { struct avs_audio_format *out_fmt; } micsel; + struct { + u32 target_volume; + u32 curve_type; + u32 curve_duration; + } peakvol; }; }; diff --git a/sound/soc/intel/avs/trace.c b/sound/soc/intel/avs/trace.c index c63eea909b5e..a98da521db0f 100644 --- a/sound/soc/intel/avs/trace.c +++ b/sound/soc/intel/avs/trace.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> diff --git a/sound/soc/intel/avs/trace.h b/sound/soc/intel/avs/trace.h index 855b06bb14b0..f4288d0ad5ef 100644 --- a/sound/soc/intel/avs/trace.h +++ b/sound/soc/intel/avs/trace.h @@ -24,7 +24,7 @@ TRACE_EVENT(avs_dsp_core_op, TP_fast_assign( __entry->reg = reg; __entry->mask = mask; - __assign_str(op, op); + __assign_str(op); __entry->flag = flag; ), @@ -37,60 +37,62 @@ TRACE_EVENT(avs_dsp_core_op, void trace_avs_msg_payload(const void *data, size_t size); -#define trace_avs_request(msg, fwregs) \ +#define trace_avs_request(msg, sts, lec) \ ({ \ - trace_avs_ipc_request_msg((msg)->header, fwregs); \ + trace_avs_ipc_request_msg((msg)->header, sts, lec); \ trace_avs_msg_payload((msg)->data, (msg)->size); \ }) -#define trace_avs_reply(msg, fwregs) \ +#define trace_avs_reply(msg, sts, lec) \ ({ \ - trace_avs_ipc_reply_msg((msg)->header, fwregs); \ + trace_avs_ipc_reply_msg((msg)->header, sts, lec); \ trace_avs_msg_payload((msg)->data, (msg)->size); \ }) -#define trace_avs_notify(msg, fwregs) \ +#define trace_avs_notify(msg, sts, lec) \ ({ \ - trace_avs_ipc_notify_msg((msg)->header, fwregs); \ + trace_avs_ipc_notify_msg((msg)->header, sts, lec); \ trace_avs_msg_payload((msg)->data, (msg)->size); \ }) #endif DECLARE_EVENT_CLASS(avs_ipc_msg_hdr, - TP_PROTO(u64 header, u64 fwregs), + TP_PROTO(u64 header, u32 sts, u32 lec), - TP_ARGS(header, fwregs), + TP_ARGS(header, sts, lec), TP_STRUCT__entry( __field(u64, header) - __field(u64, fwregs) + __field(u32, sts) + __field(u32, lec) ), TP_fast_assign( __entry->header = header; - __entry->fwregs = fwregs; + __entry->sts = sts; + __entry->lec = lec; ), TP_printk("primary: 0x%08X, extension: 0x%08X,\n" - "fwstatus: 0x%08X, fwerror: 0x%08X", + "status: 0x%08X, error: 0x%08X", lower_32_bits(__entry->header), upper_32_bits(__entry->header), - lower_32_bits(__entry->fwregs), upper_32_bits(__entry->fwregs)) + __entry->sts, __entry->lec) ); DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_request_msg, - TP_PROTO(u64 header, u64 fwregs), - TP_ARGS(header, fwregs) + TP_PROTO(u64 header, u32 sts, u32 lec), + TP_ARGS(header, sts, lec) ); DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_reply_msg, - TP_PROTO(u64 header, u64 fwregs), - TP_ARGS(header, fwregs) + TP_PROTO(u64 header, u32 sts, u32 lec), + TP_ARGS(header, sts, lec) ); DEFINE_EVENT(avs_ipc_msg_hdr, avs_ipc_notify_msg, - TP_PROTO(u64 header, u64 fwregs), - TP_ARGS(header, fwregs) + TP_PROTO(u64 header, u32 sts, u32 lec), + TP_ARGS(header, sts, lec) ); TRACE_EVENT_CONDITION(avs_ipc_msg_payload, @@ -135,7 +137,7 @@ TRACE_EVENT(avs_d0ix, ), TP_fast_assign( - __assign_str(op, op); + __assign_str(op); __entry->proceed = proceed; __entry->header = header; ), diff --git a/sound/soc/intel/avs/utils.c b/sound/soc/intel/avs/utils.c index 82416b86662d..81f9b67d8e29 100644 --- a/sound/soc/intel/avs/utils.c +++ b/sound/soc/intel/avs/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2021-2022 Intel Corporation. All rights reserved. +// Copyright(c) 2021-2022 Intel Corporation // // Authors: Cezary Rojewski <cezary.rojewski@intel.com> // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -250,7 +250,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con if (!entry) return -ENOMEM; - entry->name = kstrdup(name, GFP_KERNEL); + entry->name = kstrdup_const(name, GFP_KERNEL); if (!entry->name) { kfree(entry); return -ENOMEM; @@ -258,7 +258,7 @@ int avs_request_firmware(struct avs_dev *adev, const struct firmware **fw_p, con ret = request_firmware(&entry->fw, name, adev->dev); if (ret < 0) { - kfree(entry->name); + kfree_const(entry->name); kfree(entry); return ret; } @@ -282,7 +282,7 @@ void avs_release_last_firmware(struct avs_dev *adev) list_del(&entry->node); release_firmware(entry->fw); - kfree(entry->name); + kfree_const(entry->name); kfree(entry); } @@ -296,7 +296,7 @@ void avs_release_firmwares(struct avs_dev *adev) list_for_each_entry_safe(entry, tmp, &adev->fw_list, node) { list_del(&entry->node); release_firmware(entry->fw); - kfree(entry->name); + kfree_const(entry->name); kfree(entry); } } diff --git a/sound/soc/intel/avs/utils.h b/sound/soc/intel/avs/utils.h index 0b82a98ed024..955a40d2c30c 100644 --- a/sound/soc/intel/avs/utils.h +++ b/sound/soc/intel/avs/utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2023 Intel Corporation. All rights reserved. + * Copyright(c) 2023 Intel Corporation * * Authors: Cezary Rojewski <cezary.rojewski@intel.com> * Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> @@ -11,6 +11,16 @@ #include <sound/soc-acpi.h> +extern bool obsolete_card_names; + +struct avs_mach_pdata { + struct hda_codec *codec; + unsigned long *tdms; + char *codec_name; /* DMIC only */ + + bool obsolete_card_names; +}; + static inline bool avs_mach_singular_ssp(struct snd_soc_acpi_mach *mach) { return hweight_long(mach->mach_params.i2s_link_mask) == 1; @@ -23,14 +33,16 @@ static inline u32 avs_mach_ssp_port(struct snd_soc_acpi_mach *mach) static inline bool avs_mach_singular_tdm(struct snd_soc_acpi_mach *mach, u32 port) { - unsigned long *tdms = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + unsigned long *tdms = pdata->tdms; return !tdms || (hweight_long(tdms[port]) == 1); } static inline u32 avs_mach_ssp_tdm(struct snd_soc_acpi_mach *mach, u32 port) { - unsigned long *tdms = mach->pdata; + struct avs_mach_pdata *pdata = mach->pdata; + unsigned long *tdms = pdata->tdms; return tdms ? __ffs(tdms[port]) : 0; } diff --git a/sound/soc/intel/boards/Kconfig b/sound/soc/intel/boards/Kconfig index 18ac3ce0752e..2df7afa2f469 100644 --- a/sound/soc/intel/boards/Kconfig +++ b/sound/soc/intel/boards/Kconfig @@ -41,9 +41,6 @@ config SND_SOC_INTEL_SOF_CIRRUS_COMMON config SND_SOC_INTEL_SOF_NUVOTON_COMMON tristate -config SND_SOC_INTEL_SOF_SSP_COMMON - tristate - config SND_SOC_INTEL_SOF_BOARD_HELPERS tristate @@ -255,94 +252,6 @@ config SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH endif ## SND_SST_ATOM_HIFI2_PLATFORM -if SND_SOC_INTEL_SKL - -config SND_SOC_INTEL_SKL_RT286_MACH - tristate "SKL with RT286 I2S mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT286 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Skylake platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH - tristate "SKL with NAU88L25 and SSM4567 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_SSM4567 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + SSM4567. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH - tristate "SKL with NAU88L25 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_NAU8825 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + MAX98357A. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_SKL - -config SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - tristate - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_MAX98390 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON - tristate - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - -if SND_SOC_INTEL_APL - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "Broxton with DA7219 and MAX98357A/MAX98390 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON - help - This adds support for ASoC machine driver for Broxton-P platforms - with DA7219 + MAX98357A/MAX98390 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_BXT_RT298_MACH - tristate "Broxton with RT298 I2S mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT298 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON - help - This adds support for ASoC machine driver for Broxton platforms - with RT286 I2S audio codec. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -endif ## SND_SOC_INTEL_APL - if SND_SOC_SOF_APOLLOLAKE config SND_SOC_INTEL_SOF_WM8804_MACH @@ -359,119 +268,37 @@ config SND_SOC_INTEL_SOF_WM8804_MACH endif ## SND_SOC_SOF_APOLLOLAKE -if SND_SOC_INTEL_KBL - -config SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH - tristate "KBL with RT5663 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_RT5663 - select SND_SOC_MAX98927 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH - tristate "KBL with RT5663, RT5514 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SPI - select SND_SOC_RT5663 - select SND_SOC_RT5514 - select SND_SOC_RT5514_SPI - select SND_SOC_MAX98927 - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_SKYLAKE_SSP_CLK - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5663 + RT5514 + MAX98927. - Say Y or m if you have such a device. This is a recommended option. - If unsure select "N". - -config SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH - tristate "KBL with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_DA7219_MAX98357A_GENERIC - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98357A I2S audio codec. - Say Y if you have such a device. - -config SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH - tristate "KBL with DA7219 and MAX98927 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_DA7219 - select SND_SOC_MAX98927 - select SND_SOC_MAX98373_I2C - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for DA7219 + MAX98927 I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_KBL_RT5660_MACH - tristate "KBL with RT5660 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on GPIOLIB || COMPILE_TEST - select SND_SOC_RT5660 - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for RT5660 I2S audio codec. - Say Y if you have such a device. - -endif ## SND_SOC_INTEL_KBL - if SND_SOC_SOF_GEMINILAKE config SND_SOC_INTEL_GLK_DA7219_MAX98357A_MACH tristate "GLK with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + imply SND_SOC_INTEL_SOF_DA7219_MACH help This adds support for ASoC machine driver for Geminilake platforms - with DA7219 + MAX98357A I2S audio codec. + with DA7219 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_DA7219_MACH instead. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH tristate "GLK with RT5682 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_RT5682_I2C - select SND_SOC_RT5682S - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON + imply SND_SOC_INTEL_SOF_RT5682_MACH help This adds support for ASoC machine driver for Geminilake platforms - with RT5682 + MAX98357A I2S audio codec. + with RT5682 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_RT5682_MACH instead. Say Y if you have such a device. If unsure select "N". endif ## SND_SOC_SOF_GEMINILAKE -if SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +if SND_SOC_SOF_HDA_AUDIO_CODEC config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH tristate "Skylake+ with HDA Codecs" depends on SND_HDA_CODEC_HDMI - select SND_SOC_HDAC_HDMI select SND_SOC_INTEL_HDA_DSP_COMMON + select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_DMIC # SND_SOC_HDAC_HDA is already selected help @@ -481,7 +308,7 @@ config SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH Say Y or m if you have such a device. This is a recommended option. If unsure select "N". -endif ## SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC || SND_SOC_SOF_HDA_AUDIO_CODEC +endif ## SND_SOC_SOF_HDA_AUDIO_CODEC if SND_SOC_SOF_HDA_LINK || SND_SOC_SOF_BAYTRAIL config SND_SOC_INTEL_SOF_RT5682_MACH @@ -490,6 +317,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH depends on ((SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC) &&\ (MFD_INTEL_LPSS || COMPILE_TEST)) ||\ (SND_SOC_SOF_BAYTRAIL && (X86_INTEL_LPSS || COMPILE_TEST)) + select SND_SOC_MAX98357A select SND_SOC_MAX98373_I2C select SND_SOC_MAX98390 select SND_SOC_RT1011 @@ -503,7 +331,7 @@ config SND_SOC_INTEL_SOF_RT5682_MACH select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_MAXIM_COMMON select SND_SOC_INTEL_SOF_REALTEK_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with rt5650 or rt5682 codec. @@ -521,7 +349,7 @@ config SND_SOC_INTEL_SOF_CS42L42_MACH select SND_SOC_INTEL_HDA_DSP_COMMON select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_MAXIM_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with cs42l42 codec. @@ -574,7 +402,7 @@ config SND_SOC_INTEL_SOF_NAU8825_MACH select SND_SOC_INTEL_SOF_MAXIM_COMMON select SND_SOC_INTEL_SOF_NUVOTON_COMMON select SND_SOC_INTEL_SOF_REALTEK_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with nau8825 codec. @@ -587,28 +415,21 @@ if (SND_SOC_SOF_COMETLAKE && SND_SOC_SOF_HDA_LINK) config SND_SOC_INTEL_CML_LP_DA7219_MAX98357A_MACH tristate "CML_LP with DA7219 and MAX98357A in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - select SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON + imply SND_SOC_INTEL_SOF_DA7219_MACH help This adds support for ASoC machine driver for Cometlake platforms - with DA7219 + MAX98357A I2S audio codec. + with DA7219 + MAX98357A I2S audio codec. This option is deprecated + and please use SND_SOC_INTEL_SOF_DA7219_MACH instead. Say Y or m if you have such a device. This is a recommended option. If unsure select "N". config SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH tristate "CML with RT1011 and RT5682 in I2S Mode" - depends on I2C && ACPI - depends on MFD_INTEL_LPSS || COMPILE_TEST - depends on SND_HDA_CODEC_HDMI && SND_SOC_SOF_HDA_AUDIO_CODEC - select SND_SOC_RT1011 - select SND_SOC_RT5682_I2C - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_SOC_INTEL_HDA_DSP_COMMON + imply SND_SOC_INTEL_SOF_RT5682_MACH help This adds support for ASoC machine driver for SOF platform with - RT1011 + RT5682 I2S codec. + RT1011 + RT5682 I2S codec. This option is deprecated and please used + SND_SOC_INTEL_SOF_RT5682_MACH instead. Say Y if you have such a device. If unsure select "N". @@ -623,9 +444,11 @@ config SND_SOC_INTEL_SOF_DA7219_MACH select SND_SOC_DA7219 select SND_SOC_MAX98357A select SND_SOC_MAX98373_I2C + select SND_SOC_MAX98390 select SND_SOC_DMIC + select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_MAXIM_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with Dialog DA7219 I2S audio codec. @@ -645,7 +468,7 @@ config SND_SOC_INTEL_SOF_SSP_AMP_MACH select SND_SOC_INTEL_SOF_BOARD_HELPERS select SND_SOC_INTEL_SOF_REALTEK_COMMON select SND_SOC_INTEL_SOF_CIRRUS_COMMON - select SND_SOC_INTEL_SOF_SSP_COMMON + select SND_SOC_ACPI_INTEL_MATCH help This adds support for ASoC machine driver for SOF platforms with RT1308/CS35L41 I2S audio codec. @@ -673,11 +496,11 @@ if SND_SOC_SOF_INTEL_SOUNDWIRE config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH tristate "SoundWire generic machine driver" - depends on I2C && ACPI + depends on I2C && SPI_MASTER && ACPI depends on MFD_INTEL_LPSS || COMPILE_TEST depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST depends on SOUNDWIRE - select SND_SOC_INTEL_SOF_BOARD_HELPERS + select SND_SOC_SDW_UTILS select SND_SOC_MAX98363 select SND_SOC_MAX98373_I2C select SND_SOC_MAX98373_SDW @@ -688,21 +511,25 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH select SND_SOC_RT712_SDCA_DMIC_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW + select SND_SOC_RT721_SDCA_SDW select SND_SOC_RT722_SDCA_SDW select SND_SOC_RT1308_SDW select SND_SOC_RT1308 select SND_SOC_RT1316_SDW select SND_SOC_RT1318_SDW + select SND_SOC_RT1320_SDW select SND_SOC_RT5682_SDW select SND_SOC_CS42L42_SDW select SND_SOC_CS42L43 select SND_SOC_CS42L43_SDW select MFD_CS42L43 select MFD_CS42L43_SDW + select PINCTRL_CS42L43 + select SPI_CS42L43 + select SND_SOC_CS35L56_SPI select SND_SOC_CS35L56_SDW select SND_SOC_DMIC select SND_SOC_INTEL_HDA_DSP_COMMON - select SND_SOC_INTEL_SOF_MAXIM_COMMON imply SND_SOC_SDW_MOCKUP help Add support for Intel SoundWire-based platforms connected to diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index bbf796a5f7ba..fcd517d6c279 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -1,50 +1,30 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-hsw-rt5640-objs := hsw_rt5640.o -snd-soc-sst-bdw-rt5650-mach-objs := bdw-rt5650.o -snd-soc-sst-bdw-rt5677-mach-objs := bdw-rt5677.o -snd-soc-bdw-rt286-objs := bdw_rt286.o -snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o -snd-soc-sst-bxt-rt298-objs := bxt_rt298.o -snd-soc-sst-sof-pcm512x-objs := sof_pcm512x.o -snd-soc-sst-sof-wm8804-objs := sof_wm8804.o -snd-soc-sst-glk-rt5682_max98357a-objs := glk_rt5682_max98357a.o -snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o -snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o -snd-soc-sst-bytcr-wm5102-objs := bytcr_wm5102.o -snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o -snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o -snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o -snd-soc-sst-cht-bsw-nau8824-objs := cht_bsw_nau8824.o -snd-soc-sst-byt-cht-cx2072x-objs := bytcht_cx2072x.o -snd-soc-sst-byt-cht-da7213-objs := bytcht_da7213.o -snd-soc-sst-byt-cht-es8316-objs := bytcht_es8316.o -snd-soc-sst-byt-cht-nocodec-objs := bytcht_nocodec.o -snd-soc-sof_rt5682-objs := sof_rt5682.o -snd-soc-sof_cs42l42-objs := sof_cs42l42.o -snd-soc-sof_es8336-objs := sof_es8336.o -snd-soc-sof_nau8825-objs := sof_nau8825.o -snd-soc-sof_da7219-objs := sof_da7219.o -snd-soc-cml_rt1011_rt5682-objs := cml_rt1011_rt5682.o -snd-soc-kbl_da7219_max98357a-objs := kbl_da7219_max98357a.o -snd-soc-kbl_da7219_max98927-objs := kbl_da7219_max98927.o -snd-soc-kbl_rt5663_max98927-objs := kbl_rt5663_max98927.o -snd-soc-kbl_rt5663_rt5514_max98927-objs := kbl_rt5663_rt5514_max98927.o -snd-soc-kbl_rt5660-objs := kbl_rt5660.o -snd-soc-skl_rt286-objs := skl_rt286.o -snd-soc-skl_hda_dsp-objs := skl_hda_dsp_generic.o skl_hda_dsp_common.o -snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o -snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o -snd-soc-ehl-rt5660-objs := ehl_rt5660.o -snd-soc-sof-ssp-amp-objs := sof_ssp_amp.o -snd-soc-sof-sdw-objs += sof_sdw.o \ - sof_sdw_maxim.o sof_sdw_rt_amp.o \ - sof_sdw_rt5682.o sof_sdw_rt700.o \ - sof_sdw_rt711.o sof_sdw_rt_sdca_jack_common.o \ - sof_sdw_rt712_sdca.o sof_sdw_rt715.o \ - sof_sdw_rt715_sdca.o sof_sdw_rt722_sdca.o \ - sof_sdw_cs42l42.o sof_sdw_cs42l43.o \ - sof_sdw_cs_amp.o \ - sof_sdw_dmic.o \ +snd-soc-hsw-rt5640-y := hsw_rt5640.o +snd-soc-sst-bdw-rt5650-mach-y := bdw-rt5650.o +snd-soc-sst-bdw-rt5677-mach-y := bdw-rt5677.o +snd-soc-bdw-rt286-y := bdw_rt286.o +snd-soc-sst-sof-pcm512x-y := sof_pcm512x.o +snd-soc-sst-sof-wm8804-y := sof_wm8804.o +snd-soc-sst-bytcr-rt5640-y := bytcr_rt5640.o +snd-soc-sst-bytcr-rt5651-y := bytcr_rt5651.o +snd-soc-sst-bytcr-wm5102-y := bytcr_wm5102.o +snd-soc-sst-cht-bsw-rt5672-y := cht_bsw_rt5672.o +snd-soc-sst-cht-bsw-rt5645-y := cht_bsw_rt5645.o +snd-soc-sst-cht-bsw-max98090_ti-y := cht_bsw_max98090_ti.o +snd-soc-sst-cht-bsw-nau8824-y := cht_bsw_nau8824.o +snd-soc-sst-byt-cht-cx2072x-y := bytcht_cx2072x.o +snd-soc-sst-byt-cht-da7213-y := bytcht_da7213.o +snd-soc-sst-byt-cht-es8316-y := bytcht_es8316.o +snd-soc-sst-byt-cht-nocodec-y := bytcht_nocodec.o +snd-soc-sof_rt5682-y := sof_rt5682.o +snd-soc-sof_cs42l42-y := sof_cs42l42.o +snd-soc-sof_es8336-y := sof_es8336.o +snd-soc-sof_nau8825-y := sof_nau8825.o +snd-soc-sof_da7219-y := sof_da7219.o +snd-soc-skl_hda_dsp-y := skl_hda_dsp_generic.o +snd-soc-ehl-rt5660-y := ehl_rt5660.o +snd-soc-sof-ssp-amp-y := sof_ssp_amp.o +snd-soc-sof-sdw-y += sof_sdw.o \ sof_sdw_hdmi.o obj-$(CONFIG_SND_SOC_INTEL_SOF_RT5682_MACH) += snd-soc-sof_rt5682.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CS42L42_MACH) += snd-soc-sof_cs42l42.o @@ -52,11 +32,8 @@ obj-$(CONFIG_SND_SOC_INTEL_SOF_ES8336_MACH) += snd-soc-sof_es8336.o obj-$(CONFIG_SND_SOC_INTEL_SOF_NAU8825_MACH) += snd-soc-sof_nau8825.o obj-$(CONFIG_SND_SOC_INTEL_SOF_DA7219_MACH) += snd-soc-sof_da7219.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-hsw-rt5640.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_COMMON) += snd-soc-sst-bxt-da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o obj-$(CONFIG_SND_SOC_INTEL_SOF_PCM512x_MACH) += snd-soc-sst-sof-pcm512x.o obj-$(CONFIG_SND_SOC_INTEL_SOF_WM8804_MACH) += snd-soc-sst-sof-wm8804.o -obj-$(CONFIG_SND_SOC_INTEL_GLK_RT5682_MAX98357A_MACH) += snd-soc-sst-glk-rt5682_max98357a.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-bdw-rt286.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5650_MACH) += snd-soc-sst-bdw-rt5650-mach.o obj-$(CONFIG_SND_SOC_INTEL_BDW_RT5677_MACH) += snd-soc-sst-bdw-rt5677-mach.o @@ -71,38 +48,26 @@ obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_CX2072X_MACH) += snd-soc-sst-byt-cht-cx2072x. obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_DA7213_MACH) += snd-soc-sst-byt-cht-da7213.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_ES8316_MACH) += snd-soc-sst-byt-cht-es8316.o obj-$(CONFIG_SND_SOC_INTEL_BYT_CHT_NOCODEC_MACH) += snd-soc-sst-byt-cht-nocodec.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_CML_RT1011_RT5682_MACH) += snd-soc-cml_rt1011_rt5682.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98357A_MACH) += snd-soc-kbl_da7219_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_DA7219_MAX98927_MACH) += snd-soc-kbl_da7219_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_MAX98927_MACH) += snd-soc-kbl_rt5663_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5663_RT5514_MAX98927_MACH) += snd-soc-kbl_rt5663_rt5514_max98927.o -obj-$(CONFIG_SND_SOC_INTEL_KBL_RT5660_MACH) += snd-soc-kbl_rt5660.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o -obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_SKL_HDA_DSP_GENERIC_MACH) += snd-soc-skl_hda_dsp.o obj-$(CONFIG_SND_SOC_INTEL_EHL_RT5660_MACH) += snd-soc-ehl-rt5660.o obj-$(CONFIG_SND_SOC_INTEL_SOUNDWIRE_SOF_MACH) += snd-soc-sof-sdw.o obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_AMP_MACH) += snd-soc-sof-ssp-amp.o # common modules -snd-soc-intel-hda-dsp-common-objs := hda_dsp_common.o +snd-soc-intel-hda-dsp-common-y := hda_dsp_common.o obj-$(CONFIG_SND_SOC_INTEL_HDA_DSP_COMMON) += snd-soc-intel-hda-dsp-common.o -snd-soc-intel-sof-maxim-common-objs += sof_maxim_common.o +snd-soc-intel-sof-maxim-common-y += sof_maxim_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_MAXIM_COMMON) += snd-soc-intel-sof-maxim-common.o -snd-soc-intel-sof-realtek-common-objs += sof_realtek_common.o +snd-soc-intel-sof-realtek-common-y += sof_realtek_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_REALTEK_COMMON) += snd-soc-intel-sof-realtek-common.o -snd-soc-intel-sof-cirrus-common-objs += sof_cirrus_common.o +snd-soc-intel-sof-cirrus-common-y += sof_cirrus_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_CIRRUS_COMMON) += snd-soc-intel-sof-cirrus-common.o -snd-soc-intel-sof-nuvoton-common-objs += sof_nuvoton_common.o +snd-soc-intel-sof-nuvoton-common-y += sof_nuvoton_common.o obj-$(CONFIG_SND_SOC_INTEL_SOF_NUVOTON_COMMON) += snd-soc-intel-sof-nuvoton-common.o -snd-soc-intel-sof-ssp-common-objs += sof_ssp_common.o -obj-$(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) += snd-soc-intel-sof-ssp-common.o - -snd-soc-intel-sof-board-helpers-objs += sof_board_helpers.o +snd-soc-intel-sof-board-helpers-y += sof_board_helpers.o obj-$(CONFIG_SND_SOC_INTEL_SOF_BOARD_HELPERS) += snd-soc-intel-sof-board-helpers.o diff --git a/sound/soc/intel/boards/bdw-rt5650.c b/sound/soc/intel/boards/bdw-rt5650.c index 3ae26f21458f..d25a7188f603 100644 --- a/sound/soc/intel/boards/bdw-rt5650.c +++ b/sound/soc/intel/boards/bdw-rt5650.c @@ -131,7 +131,7 @@ static int bdw_rt5650_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops bdw_rt5650_ops = { +static const struct snd_soc_ops bdw_rt5650_ops = { .hw_params = bdw_rt5650_hw_params, }; @@ -239,8 +239,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -256,8 +254,6 @@ static struct snd_soc_dai_link bdw_rt5650_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5650_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5650_init, SND_SOC_DAILINK_REG(ssp0_port, be, platform), }, diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 304af3d06d01..9484f3410787 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -329,8 +329,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, - .dpcm_capture = 1, - .dpcm_playback = 1, .ops = &bdw_rt5677_fe_ops, SND_SOC_DAILINK_REG(fe, dummy, platform), }, @@ -356,8 +354,6 @@ static struct snd_soc_dai_link bdw_rt5677_dais[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = broadwell_ssp0_fixup, .ops = &bdw_rt5677_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = bdw_rt5677_init, .exit = bdw_rt5677_exit, SND_SOC_DAILINK_REG(ssp0_port, be, platform), diff --git a/sound/soc/intel/boards/bdw_rt286.c b/sound/soc/intel/boards/bdw_rt286.c index 7f20159c23e5..523ade9f31ab 100644 --- a/sound/soc/intel/boards/bdw_rt286.c +++ b/sound/soc/intel/boards/bdw_rt286.c @@ -2,7 +2,7 @@ /* * Sound card driver for Intel Broadwell Wildcat Point with Realtek 286 * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #include <linux/module.h> @@ -133,8 +133,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -143,7 +141,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -152,7 +150,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -161,7 +159,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -177,8 +175,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c deleted file mode 100644 index 540f7a29310a..000000000000 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ /dev/null @@ -1,894 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2016, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/da7219.h" -#include "../common/soc-intel-quirks.h" -#include "hda_dsp_common.h" - -#define BXT_DIALOG_CODEC_DAI "da7219-hifi" -#define BXT_MAXIM_CODEC_DAI "HiFi" -#define MAX98390_DEV0_NAME "i2c-MX98390:00" -#define MAX98390_DEV1_NAME "i2c-MX98390:01" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -#define SPKAMP_MAX98357A 1 -#define SPKAMP_MAX98390 2 - -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -struct bxt_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct bxt_card_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; - int spkamp; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_HS_PB, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - int ret = 0; - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - - codec_dai = snd_soc_card_get_codec_dai(card, BXT_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if(SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_kcontrol_new max98357a_controls[] = { - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_kcontrol_new max98390_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static const struct snd_soc_dapm_widget broxton_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD|SND_SOC_DAPM_PRE_PMU), -}; - -static const struct snd_soc_dapm_widget max98357a_widgets[] = { - SND_SOC_DAPM_SPK("Spk", NULL), -}; - -static const struct snd_soc_dapm_widget max98390_widgets[] = { - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - -static const struct snd_soc_dapm_route audio_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone Jack", NULL, "HPL"}, - {"Headphone Jack", NULL, "HPR"}, - - /* other jacks */ - {"MIC", NULL, "Headset Mic"}, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - {"hifi3", NULL, "iDisp3 Tx"}, - {"iDisp3 Tx", NULL, "iDisp3_out"}, - {"hifi2", NULL, "iDisp2 Tx"}, - {"iDisp2 Tx", NULL, "iDisp2_out"}, - {"hifi1", NULL, "iDisp1 Tx"}, - {"iDisp1 Tx", NULL, "iDisp1_out"}, - - /* DMIC */ - {"dmic01_hifi", NULL, "DMIC01 Rx"}, - {"DMIC01 Rx", NULL, "DMIC AIF"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, -}; - -static const struct snd_soc_dapm_route max98357a_routes[] = { - /* speaker */ - {"Spk", NULL, "Speaker"}, -}; - -static const struct snd_soc_dapm_route max98390_routes[] = { - /* Speaker */ - {"Left Spk", NULL, "Left BE_OUT"}, - {"Right Spk", NULL, "Right BE_OUT"}, -}; - -static const struct snd_soc_dapm_route broxton_map[] = { - {"HiFi Playback", NULL, "ssp5 Tx"}, - {"ssp5 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp1 Rx"}, - {"ssp1 Rx", NULL, "Capture"}, -}; - -static const struct snd_soc_dapm_route gemini_map[] = { - {"HiFi Playback", NULL, "ssp1 Tx"}, - {"ssp1 Tx", NULL, "codec0_out"}, - - {"Playback", NULL, "ssp2 Tx"}, - {"ssp2 Tx", NULL, "codec1_out"}, - - {"codec0_in", NULL, "ssp2 Rx"}, - {"ssp2 Rx", NULL, "Capture"}, -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, - }, -}; - -static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int clk_freq; - - /* Configure sysclk for codec */ - if (soc_intel_is_cml()) - clk_freq = 24000000; - else - clk_freq = 19200000; - - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, clk_freq, - SND_SOC_CLOCK_IN); - - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &broxton_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(broxton_headset.jack, SND_JACK_BTN_3, - KEY_VOICECOMMAND); - - snd_soc_component_set_jack(component, &broxton_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static const unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int bxt_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops broxton_da7219_fe_ops = { - .startup = bxt_fe_startup, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops broxton_dmic_ops = { - .startup = broxton_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int broxton_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -}; - -static const struct snd_soc_ops broxton_refcap_ops = { - .startup = broxton_refcap_startup, -}; - -/* broxton digital audio interface glue - connects codec <--> CPU */ -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - - /* Back End DAI */ -SND_SOC_DAILINK_DEF(ssp5_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); -SND_SOC_DAILINK_DEF(ssp5_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", - BXT_MAXIM_CODEC_DAI))); -SND_SOC_DAILINK_DEF(max98390_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAX98390_DEV0_NAME, "max98390-aif1"), - /* Right */ COMP_CODEC(MAX98390_DEV1_NAME, "max98390-aif1"))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - BXT_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); - -static struct snd_soc_dai_link broxton_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .name = "Bxt Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = broxton_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .name = "Bxt Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_HS_PB] = { - .name = "Bxt Audio Headset Playback", - .stream_name = "Headset Playback", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_da7219_fe_ops, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "Refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP5 - Codec */ - .name = "SSP5-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = broxton_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .name = "dmic16k", - .id = 6, - .be_hw_params_fixup = broxton_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, -}; - -static struct snd_soc_codec_conf max98390_codec_confs[] = { - { - .dlc = COMP_CODEC_CONF(MAX98390_DEV0_NAME), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF(MAX98390_DEV1_NAME), - .name_prefix = "Right", - }, -}; - -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_card_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - const struct snd_kcontrol_new *controls; - const struct snd_soc_dapm_widget *widgets; - const struct snd_soc_dapm_route *routes; - int num_controls, num_widgets, num_routes, err, i = 0; - char jack_name[NAME_SIZE]; - - switch (ctx->spkamp) { - case SPKAMP_MAX98357A: - controls = max98357a_controls; - num_controls = ARRAY_SIZE(max98357a_controls); - widgets = max98357a_widgets; - num_widgets = ARRAY_SIZE(max98357a_widgets); - routes = max98357a_routes; - num_routes = ARRAY_SIZE(max98357a_routes); - break; - case SPKAMP_MAX98390: - controls = max98390_controls; - num_controls = ARRAY_SIZE(max98390_controls); - widgets = max98390_widgets; - num_widgets = ARRAY_SIZE(max98390_widgets); - routes = max98390_routes; - num_routes = ARRAY_SIZE(max98390_routes); - break; - default: - dev_err(card->dev, "Invalid speaker amplifier %d\n", ctx->spkamp); - return -EINVAL; - } - - err = snd_soc_dapm_new_controls(&card->dapm, widgets, num_widgets); - if (err) { - dev_err(card->dev, "Fail to new widgets\n"); - return err; - } - - err = snd_soc_add_card_controls(card, controls, num_controls); - if (err) { - dev_err(card->dev, "Fail to add controls\n"); - return err; - } - - err = snd_soc_dapm_add_routes(&card->dapm, routes, num_routes); - if (err) { - dev_err(card->dev, "Fail to add routes\n"); - return err; - } - - if (soc_intel_is_glk()) - snd_soc_dapm_add_routes(&card->dapm, gemini_map, - ARRAY_SIZE(gemini_map)); - else - snd_soc_dapm_add_routes(&card->dapm, broxton_map, - ARRAY_SIZE(broxton_map)); - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &broxton_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* broxton audio machine driver for SPT + da7219 */ -static struct snd_soc_card broxton_audio_card = { - .name = "bxtda7219max", - .owner = THIS_MODULE, - .dai_link = broxton_dais, - .num_links = ARRAY_SIZE(broxton_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = audio_map, - .num_dapm_routes = ARRAY_SIZE(audio_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - if (acpi_dev_present("MX98390", NULL, -1)) - ctx->spkamp = SPKAMP_MAX98390; - else - ctx->spkamp = SPKAMP_MAX98357A; - - broxton_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&broxton_audio_card, ctx); - if (soc_intel_is_glk()) { - unsigned int i; - - broxton_audio_card.name = "glkda7219max"; - /* Fixup the SSP entries for geminilake */ - for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { - if (!broxton_dais[i].codecs->dai_name) - continue; - - /* MAXIM_CODEC is connected to SSP1. */ - if (!strcmp(broxton_dais[i].codecs->dai_name, - BXT_MAXIM_CODEC_DAI)) { - broxton_dais[i].name = "SSP1-Codec"; - broxton_dais[i].cpus->dai_name = "SSP1 Pin"; - } - /* DIALOG_CODE is connected to SSP2 */ - else if (!strcmp(broxton_dais[i].codecs->dai_name, - BXT_DIALOG_CODEC_DAI)) { - broxton_dais[i].name = "SSP2-Codec"; - broxton_dais[i].cpus->dai_name = "SSP2 Pin"; - } - } - } else if (soc_intel_is_cml()) { - unsigned int i; - - if (ctx->spkamp == SPKAMP_MAX98390) { - broxton_audio_card.name = "cml_max98390_da7219"; - - broxton_audio_card.codec_conf = max98390_codec_confs; - broxton_audio_card.num_configs = ARRAY_SIZE(max98390_codec_confs); - } else - broxton_audio_card.name = "cmlda7219max"; - - for (i = 0; i < ARRAY_SIZE(broxton_dais); i++) { - if (!broxton_dais[i].codecs->dai_name) - continue; - - /* MAXIM_CODEC is connected to SSP1. */ - if (!strcmp(broxton_dais[i].codecs->dai_name, - BXT_MAXIM_CODEC_DAI)) { - broxton_dais[i].name = "SSP1-Codec"; - broxton_dais[i].cpus->dai_name = "SSP1 Pin"; - - if (ctx->spkamp == SPKAMP_MAX98390) { - broxton_dais[i].codecs = max98390_codec; - broxton_dais[i].num_codecs = ARRAY_SIZE(max98390_codec); - broxton_dais[i].dpcm_capture = 1; - } - } - /* DIALOG_CODEC is connected to SSP0 */ - else if (!strcmp(broxton_dais[i].codecs->dai_name, - BXT_DIALOG_CODEC_DAI)) { - broxton_dais[i].name = "SSP0-Codec"; - broxton_dais[i].cpus->dai_name = "SSP0 Pin"; - } - } - } - - /* override platform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(&broxton_audio_card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_da7219_mx98357a" }, - { .name = "glk_da7219_mx98357a" }, - { .name = "cml_da7219_mx98357a" }, - { } -}; -MODULE_DEVICE_TABLE(platform, bxt_board_ids); - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -module_platform_driver(broxton_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>"); -MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c deleted file mode 100644 index c0eb65c14aa9..000000000000 --- a/sound/soc/intel/boards/bxt_rt298.c +++ /dev/null @@ -1,669 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Broxton-P I2S Machine Driver - * - * Copyright (C) 2014-2016, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt298.h" -#include "hda_dsp_common.h" - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack broxton_headset; -static struct snd_soc_jack broxton_hdmi[3]; - -struct bxt_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct bxt_rt286_private { - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -enum { - BXT_DPCM_AUDIO_PB = 0, - BXT_DPCM_AUDIO_CP, - BXT_DPCM_AUDIO_REF_CP, - BXT_DPCM_AUDIO_DMIC_CP, - BXT_DPCM_AUDIO_HDMI1_PB, - BXT_DPCM_AUDIO_HDMI2_PB, - BXT_DPCM_AUDIO_HDMI3_PB, -}; - -static struct snd_soc_jack_pin broxton_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new broxton_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget broxton_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), -}; - -static const struct snd_soc_dapm_route broxton_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp5 Tx"}, - { "ssp5 Tx", NULL, "codec0_out"}, - { "ssp5 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp5 Rx" }, - { "ssp5 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static const struct snd_soc_dapm_route geminilake_rt298_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack detect */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI2", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp2 Tx"}, - { "ssp2 Tx", NULL, "codec0_out"}, - { "ssp2 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp2 Rx" }, - { "ssp2 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, - - { "dmic_voice", NULL, "DMIC16k Rx" }, - { "DMIC16k Rx", NULL, "Capture" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int ret = 0; - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &broxton_headset, - broxton_headset_pins, ARRAY_SIZE(broxton_headset_pins)); - - if (ret) - return ret; - - snd_soc_component_set_jack(component, &broxton_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct bxt_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = BXT_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int broxton_ssp5_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP5 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT298_SCLK_S_PLL, - 19200000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - return ret; -} - -static const struct snd_soc_ops broxton_rt298_ops = { - .hw_params = broxton_rt298_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 1, 2, 3, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int broxton_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops broxton_dmic_ops = { - .startup = broxton_dmic_startup, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int bxt_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support: - * 48Khz - * stereo - * 16-bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops broxton_rt286_fe_ops = { - .startup = bxt_fe_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp5_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP5 Pin"))); -SND_SOC_DAILINK_DEF(ssp5_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", - "rt298-aif1"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", - "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); - -/* broxton digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link broxton_rt298_dais[] = { - /* Front End DAI links */ - [BXT_DPCM_AUDIO_PB] = - { - .name = "Bxt Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = broxton_rt298_fe_init, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_CP] = - { - .name = "Bxt Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &broxton_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [BXT_DPCM_AUDIO_REF_CP] = - { - .name = "Bxt Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [BXT_DPCM_AUDIO_DMIC_CP] = - { - .name = "Bxt Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &broxton_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI1_PB] = - { - .name = "Bxt HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI2_PB] = - { - .name = "Bxt HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [BXT_DPCM_AUDIO_HDMI3_PB] = - { - .name = "Bxt HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP5 - Codec */ - .name = "SSP5-Codec", - .id = 0, - .no_pcm = 1, - .init = broxton_rt298_codec_init, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = broxton_ssp5_fixup, - .ops = &broxton_rt298_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .be_hw_params_fixup = broxton_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = broxton_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int bxt_card_late_probe(struct snd_soc_card *card) -{ - struct bxt_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct bxt_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct bxt_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &broxton_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &broxton_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - - -/* broxton audio machine driver for SPT + RT298S */ -static struct snd_soc_card broxton_rt298 = { - .name = "broxton-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = broxton_rt298_map, - .num_dapm_routes = ARRAY_SIZE(broxton_rt298_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, - -}; - -static struct snd_soc_card geminilake_rt298 = { - .name = "geminilake-rt298", - .owner = THIS_MODULE, - .dai_link = broxton_rt298_dais, - .num_links = ARRAY_SIZE(broxton_rt298_dais), - .controls = broxton_controls, - .num_controls = ARRAY_SIZE(broxton_controls), - .dapm_widgets = broxton_widgets, - .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), - .dapm_routes = geminilake_rt298_map, - .num_dapm_routes = ARRAY_SIZE(geminilake_rt298_map), - .fully_routed = true, - .late_probe = bxt_card_late_probe, -}; - -static int broxton_audio_probe(struct platform_device *pdev) -{ - struct bxt_rt286_private *ctx; - struct snd_soc_card *card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret; - int i; - - for (i = 0; i < ARRAY_SIZE(broxton_rt298_dais); i++) { - if (card->dai_link[i].codecs->name && - !strncmp(card->dai_link[i].codecs->name, "i2c-INT343A:00", - I2C_NAME_SIZE)) { - if (!strncmp(card->name, "broxton-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP5-Codec"; - card->dai_link[i].cpus->dai_name = "SSP5 Pin"; - } else if (!strncmp(card->name, "geminilake-rt298", - PLATFORM_NAME_SIZE)) { - card->dai_link[i].name = "SSP2-Codec"; - card->dai_link[i].cpus->dai_name = "SSP2 Pin"; - } - } - } - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); - - /* override platform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(card, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id bxt_board_ids[] = { - { .name = "bxt_alc298s_i2s", .driver_data = - (unsigned long)&broxton_rt298 }, - { .name = "glk_alc298s_i2s", .driver_data = - (unsigned long)&geminilake_rt298 }, - {} -}; -MODULE_DEVICE_TABLE(platform, bxt_board_ids); - -static struct platform_driver broxton_audio = { - .probe = broxton_audio_probe, - .driver = { - .name = "bxt_alc298s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = bxt_board_ids, -}; -module_platform_driver(broxton_audio) - -/* Module information */ -MODULE_AUTHOR("Ramesh Babu <Ramesh.Babu@intel.com>"); -MODULE_AUTHOR("Senthilnathan Veppur <senthilnathanx.veppur@intel.com>"); -MODULE_DESCRIPTION("Intel SST Audio for Broxton"); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/bytcht_cx2072x.c b/sound/soc/intel/boards/bytcht_cx2072x.c index c014d85a08b2..68a3d345dc25 100644 --- a/sound/soc/intel/boards/bytcht_cx2072x.c +++ b/sound/soc/intel/boards/bytcht_cx2072x.c @@ -175,8 +175,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -185,7 +183,7 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_cx2072x_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -198,8 +196,6 @@ static struct snd_soc_dai_link byt_cht_cx2072x_dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = byt_cht_cx2072x_init, .be_hw_params_fixup = byt_cht_cx2072x_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2, cx2072x, platform), }, }; @@ -241,7 +237,7 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_cx2072x_dais); i++) { - if (byt_cht_cx2072x_dais[i].codecs->name && + if (byt_cht_cx2072x_dais[i].num_codecs && !strcmp(byt_cht_cx2072x_dais[i].codecs->name, "i2c-14F10720:00")) { dai_index = i; @@ -255,7 +251,11 @@ static int snd_byt_cht_cx2072x_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); byt_cht_cx2072x_dais[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* override platform name, if required */ diff --git a/sound/soc/intel/boards/bytcht_da7213.c b/sound/soc/intel/boards/bytcht_da7213.c index f4ac3ddd148b..31141d4b6b25 100644 --- a/sound/soc/intel/boards/bytcht_da7213.c +++ b/sound/soc/intel/boards/bytcht_da7213.c @@ -174,8 +174,6 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -184,7 +182,7 @@ static struct snd_soc_dai_link dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -197,8 +195,6 @@ static struct snd_soc_dai_link dailink[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -245,7 +241,7 @@ static int bytcht_da7213_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(dailink); i++) { - if (dailink[i].codecs->name && + if (dailink[i].num_codecs && !strcmp(dailink[i].codecs->name, "i2c-DLGS7213:00")) { dai_index = i; break; @@ -258,7 +254,11 @@ static int bytcht_da7213_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "i2c-%s", acpi_dev_name(adev)); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* override platform name, if required */ diff --git a/sound/soc/intel/boards/bytcht_es8316.c b/sound/soc/intel/boards/bytcht_es8316.c index 2fcec2e02bb5..62594e7966ab 100644 --- a/sound/soc/intel/boards/bytcht_es8316.c +++ b/sound/soc/intel/boards/bytcht_es8316.c @@ -315,8 +315,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -326,7 +324,7 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_cht_es8316_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -339,8 +337,6 @@ static struct snd_soc_dai_link byt_cht_es8316_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_cht_es8316_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_cht_es8316_init, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -546,7 +542,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { - if (byt_cht_es8316_dais[i].codecs->name && + if (byt_cht_es8316_dais[i].num_codecs && !strcmp(byt_cht_es8316_dais[i].codecs->name, "i2c-ESSX8316:00")) { dai_index = i; @@ -562,7 +558,7 @@ static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) byt_cht_es8316_dais[dai_index].codecs->name = codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -709,7 +705,7 @@ static struct platform_driver snd_byt_cht_es8316_mc_driver = { .name = "bytcht_es8316", }, .probe = snd_byt_cht_es8316_mc_probe, - .remove_new = snd_byt_cht_es8316_mc_remove, + .remove = snd_byt_cht_es8316_mc_remove, }; module_platform_driver(snd_byt_cht_es8316_mc_driver); diff --git a/sound/soc/intel/boards/bytcht_nocodec.c b/sound/soc/intel/boards/bytcht_nocodec.c index 4a957d1cece3..fec23bda9e64 100644 --- a/sound/soc/intel/boards/bytcht_nocodec.c +++ b/sound/soc/intel/boards/bytcht_nocodec.c @@ -119,8 +119,6 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -130,7 +128,7 @@ static struct snd_soc_dai_link dais[] = { .ignore_suspend = 1, .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -144,8 +142,6 @@ static struct snd_soc_dai_link dais[] = { | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = codec_fixup, .ignore_suspend = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp2_port, dummy, platform), }, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 05f38d1f7d82..0f3b8f44e701 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -17,6 +17,7 @@ #include <linux/acpi.h> #include <linux/clk.h> #include <linux/device.h> +#include <linux/device/bus.h> #include <linux/dmi.h> #include <linux/gpio/consumer.h> #include <linux/gpio/machine.h> @@ -32,6 +33,8 @@ #include "../atom/sst-atom-controls.h" #include "../common/soc-intel-quirks.h" +#define BYT_RT5640_FALLBACK_CODEC_DEV_NAME "i2c-rt5640" + enum { BYT_RT5640_DMIC1_MAP, BYT_RT5640_DMIC2_MAP, @@ -573,6 +576,19 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { /* Acer Aspire SW3-013 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW3-013"), + }, + .driver_data = (void *)(BYT_RT5640_DMIC1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), @@ -613,6 +629,17 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { { .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 101 CESIUM"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ARCHOS"), DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "ARCHOS 140 CESIUM"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | @@ -636,28 +663,30 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_USE_AMCR0F28), }, { + /* Asus T100TAF, unlike other T100TA* models this one has a mono speaker */ .matches = { DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TA"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_JD_SRC_JD2_IN4N | BYT_RT5640_OVCD_TH_2000UA | BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_MONO_SPEAKER | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, { + /* Asus T100TA and T100TAM, must come after T100TAF (mono spk) match */ .matches = { - DMI_EXACT_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "T100TAF"), + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), }, .driver_data = (void *)(BYT_RT5640_IN1_MAP | BYT_RT5640_JD_SRC_JD2_IN4N | BYT_RT5640_OVCD_TH_2000UA | BYT_RT5640_OVCD_SF_0P75 | - BYT_RT5640_MONO_SPEAKER | - BYT_RT5640_DIFF_MIC | - BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, { @@ -1116,6 +1145,36 @@ static const struct dmi_system_id byt_rt5640_quirk_table[] = { BYT_RT5640_SSP0_AIF2 | BYT_RT5640_MCLK_EN), }, + { + /* Vexia Edu Atla 10 tablet 5V version */ + .matches = { + /* Having all 3 of these not set is somewhat unique */ + DMI_MATCH(DMI_SYS_VENDOR, "To be filled by O.E.M."), + DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."), + DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "05/14/2015"), + }, + .driver_data = (void *)(BYTCR_INPUT_DEFAULTS | + BYT_RT5640_JD_NOT_INV | + BYT_RT5640_SSP0_AIF1 | + BYT_RT5640_MCLK_EN), + }, + { /* Vexia Edu Atla 10 tablet 9V version */ + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + /* Above strings are too generic, also match on BIOS date */ + DMI_MATCH(DMI_BIOS_DATE, "08/25/2014"), + }, + .driver_data = (void *)(BYT_RT5640_IN1_MAP | + BYT_RT5640_JD_SRC_JD2_IN4N | + BYT_RT5640_OVCD_TH_2000UA | + BYT_RT5640_OVCD_SF_0P75 | + BYT_RT5640_DIFF_MIC | + BYT_RT5640_SSP0_AIF2 | + BYT_RT5640_MCLK_EN), + }, { /* Voyo Winpad A15 */ .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), @@ -1533,8 +1592,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -1543,7 +1600,7 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5640_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -1555,8 +1612,6 @@ static struct snd_soc_dai_link byt_rt5640_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5640_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5640_init, .exit = byt_rt5640_exit, .ops = &byt_rt5640_be_ssp2_ops, @@ -1664,7 +1719,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5640_dais); i++) { - if (byt_rt5640_dais[i].codecs->name && + if (byt_rt5640_dais[i].num_codecs && !strcmp(byt_rt5640_dais[i].codecs->name, "i2c-10EC5640:00")) { dai_index = i; @@ -1680,14 +1735,38 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) byt_rt5640_dais[dai_index].codecs->name = byt_rt5640_codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); acpi_dev_put(adev); - if (!codec_dev) - return -EPROBE_DEFER; - priv->codec_dev = get_device(codec_dev); + + if (codec_dev) { + priv->codec_dev = get_device(codec_dev); + } else { + /* + * Special case for Android tablets where the codec i2c_client + * has been manually instantiated by x86_android_tablets.ko due + * to a broken DSDT. + */ + codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, + BYT_RT5640_FALLBACK_CODEC_DEV_NAME); + if (!codec_dev) + return -EPROBE_DEFER; + + if (!i2c_verify_client(codec_dev)) { + dev_err(dev, "Error '%s' is not an i2c_client\n", + BYT_RT5640_FALLBACK_CODEC_DEV_NAME); + put_device(codec_dev); + } + + /* fixup codec name */ + strscpy(byt_rt5640_codec_name, BYT_RT5640_FALLBACK_CODEC_DEV_NAME, + sizeof(byt_rt5640_codec_name)); + + /* bus_find_device() returns a reference no need to get() */ + priv->codec_dev = codec_dev; + } /* * swap SSP0 if bytcr is detected @@ -1905,7 +1984,7 @@ static struct platform_driver snd_byt_rt5640_mc_driver = { .name = "bytcr_rt5640", }, .probe = snd_byt_rt5640_mc_probe, - .remove_new = snd_byt_rt5640_mc_remove, + .remove = snd_byt_rt5640_mc_remove, }; module_platform_driver(snd_byt_rt5640_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 80c841b000a3..67c62844ca2a 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -770,8 +770,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -780,7 +778,7 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_rt5651_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -793,8 +791,6 @@ static struct snd_soc_dai_link byt_rt5651_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_rt5651_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_rt5651_init, .ops = &byt_rt5651_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), @@ -910,7 +906,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) /* fix index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_rt5651_dais); i++) { - if (byt_rt5651_dais[i].codecs->name && + if (byt_rt5651_dais[i].num_codecs && !strcmp(byt_rt5651_dais[i].codecs->name, "i2c-10EC5651:00")) { dai_index = i; @@ -926,7 +922,7 @@ static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) byt_rt5651_dais[dai_index].codecs->name = byt_rt5651_codec_name; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -1142,7 +1138,7 @@ static struct platform_driver snd_byt_rt5651_mc_driver = { .name = "bytcr_rt5651", }, .probe = snd_byt_rt5651_mc_probe, - .remove_new = snd_byt_rt5651_mc_remove, + .remove = snd_byt_rt5651_mc_remove, }; module_platform_driver(snd_byt_rt5651_mc_driver); diff --git a/sound/soc/intel/boards/bytcr_wm5102.c b/sound/soc/intel/boards/bytcr_wm5102.c index cccb5e90c0fe..a6dfbcfdf74e 100644 --- a/sound/soc/intel/boards/bytcr_wm5102.c +++ b/sound/soc/intel/boards/bytcr_wm5102.c @@ -462,8 +462,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Baytrail Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), @@ -473,7 +471,7 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &byt_wm5102_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -490,8 +488,6 @@ static struct snd_soc_dai_link byt_wm5102_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC, .be_hw_params_fixup = byt_wm5102_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .init = byt_wm5102_init, SND_SOC_DAILINK_REG(ssp0_port, ssp0_codec, platform), }, @@ -605,7 +601,7 @@ static int snd_byt_wm5102_mc_probe(struct platform_device *pdev) /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(byt_wm5102_dais); i++) { - if (byt_wm5102_dais[i].codecs->name && + if (byt_wm5102_dais[i].num_codecs && !strcmp(byt_wm5102_dais[i].codecs->name, "wm5102-codec")) { dai_index = i; @@ -663,7 +659,7 @@ static struct platform_driver snd_byt_wm5102_mc_driver = { .name = "bytcr_wm5102", }, .probe = snd_byt_wm5102_mc_probe, - .remove_new = snd_byt_wm5102_mc_remove, + .remove = snd_byt_wm5102_mc_remove, }; module_platform_driver(snd_byt_wm5102_mc_driver); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index f43bc20d6aae..36984de8a067 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -351,8 +351,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -361,7 +359,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -374,8 +372,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -637,7 +633,7 @@ static struct platform_driver snd_cht_mc_driver = { .name = "cht-bsw-max98090", }, .probe = snd_cht_mc_probe, - .remove_new = snd_cht_mc_remove, + .remove = snd_cht_mc_remove, }; module_platform_driver(snd_cht_mc_driver) diff --git a/sound/soc/intel/boards/cht_bsw_nau8824.c b/sound/soc/intel/boards/cht_bsw_nau8824.c index 7651b83632fa..4afb292d4f13 100644 --- a/sound/soc/intel/boards/cht_bsw_nau8824.c +++ b/sound/soc/intel/boards/cht_bsw_nau8824.c @@ -193,8 +193,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -217,8 +215,6 @@ static struct snd_soc_dai_link cht_dailink[] = { | SND_SOC_DAIFMT_CBC_CFC, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index eb41b7115d01..b977a2db73a3 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -448,8 +448,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -458,7 +456,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -470,8 +468,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -569,7 +565,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) /* set correct codec name */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) - if (cht_dailink[i].codecs->name && + if (cht_dailink[i].num_codecs && !strcmp(cht_dailink[i].codecs->name, "i2c-10EC5645:00")) { dai_index = i; @@ -582,7 +578,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snprintf(cht_rt5645_codec_name, sizeof(cht_rt5645_codec_name), "i2c-%s", acpi_dev_name(adev)); cht_dailink[dai_index].codecs->name = cht_rt5645_codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + /* acpi_get_first_physical_node() returns a borrowed ref, no need to deref */ codec_dev = acpi_get_first_physical_node(adev); acpi_dev_put(adev); diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index be2d1a8dbca8..aaef212cf44e 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -358,8 +358,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(media, dummy, platform), }, @@ -368,7 +366,7 @@ static struct snd_soc_dai_link cht_dailink[] = { .stream_name = "Deep-Buffer Audio", .nonatomic = true, .dynamic = 1, - .dpcm_playback = 1, + .playback_only = 1, .ops = &cht_aif1_ops, SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), }, @@ -381,8 +379,6 @@ static struct snd_soc_dai_link cht_dailink[] = { .no_pcm = 1, .init = cht_codec_init, .be_hw_params_fixup = cht_codec_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &cht_be_ssp2_ops, SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), }, @@ -466,7 +462,7 @@ static int snd_cht_mc_probe(struct platform_device *pdev) /* find index of codec dai */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { - if (cht_dailink[i].codecs->name && + if (cht_dailink[i].num_codecs && !strcmp(cht_dailink[i].codecs->name, RT5672_I2C_DEFAULT)) { dai_index = i; break; @@ -479,7 +475,11 @@ static int snd_cht_mc_probe(struct platform_device *pdev) snprintf(drv->codec_name, sizeof(drv->codec_name), "i2c-%s", acpi_dev_name(adev)); cht_dailink[dai_index].codecs->name = drv->codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); /* Use SSP0 on Bay Trail CR devices */ diff --git a/sound/soc/intel/boards/cml_rt1011_rt5682.c b/sound/soc/intel/boards/cml_rt1011_rt5682.c deleted file mode 100644 index 679a09b63ea5..000000000000 --- a/sound/soc/intel/boards/cml_rt1011_rt5682.c +++ /dev/null @@ -1,609 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2019 Intel Corporation. - -/* - * Intel Cometlake I2S Machine driver for RT1011 + RT5682 codec - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/dmi.h> -#include <linux/slab.h> -#include <linux/acpi.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/rt5682.h> -#include <sound/soc-acpi.h> -#include "../../codecs/rt1011.h" -#include "../../codecs/rt5682.h" -#include "../../codecs/hdac_hdmi.h" -#include "hda_dsp_common.h" - -/* The platform clock outputs 24Mhz clock to codec as I2S MCLK */ -#define CML_PLAT_CLK 24000000 -#define CML_RT1011_CODEC_DAI "rt1011-aif" -#define CML_RT5682_CODEC_DAI "rt5682-aif1" -#define NAME_SIZE 32 - -#define SOF_RT1011_SPEAKER_WL BIT(0) -#define SOF_RT1011_SPEAKER_WR BIT(1) -#define SOF_RT1011_SPEAKER_TL BIT(2) -#define SOF_RT1011_SPEAKER_TR BIT(3) - -/* Default: Woofer speakers */ -static unsigned long sof_rt1011_quirk = SOF_RT1011_SPEAKER_WL | - SOF_RT1011_SPEAKER_WR; - -static int sof_rt1011_quirk_cb(const struct dmi_system_id *id) -{ - sof_rt1011_quirk = (unsigned long)id->driver_data; - return 1; -} - -static const struct dmi_system_id sof_rt1011_quirk_table[] = { - { - .callback = sof_rt1011_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_PRODUCT_NAME, "Helios"), - }, - .driver_data = (void *)(SOF_RT1011_SPEAKER_WL | SOF_RT1011_SPEAKER_WR | - SOF_RT1011_SPEAKER_TL | SOF_RT1011_SPEAKER_TR), - }, - { - } -}; - -static struct snd_soc_jack hdmi_jack[3]; - -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct card_private { - char codec_name[SND_ACPI_I2C_ID_LEN]; - struct snd_soc_jack headset; - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; -}; - -static const struct snd_kcontrol_new cml_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("WL Ext Spk"), - SOC_DAPM_PIN_SWITCH("WR Ext Spk"), -}; - -static const struct snd_kcontrol_new cml_rt1011_tt_controls[] = { - SOC_DAPM_PIN_SWITCH("TL Ext Spk"), - SOC_DAPM_PIN_SWITCH("TR Ext Spk"), -}; - -static const struct snd_soc_dapm_widget cml_rt1011_rt5682_widgets[] = { - SND_SOC_DAPM_SPK("WL Ext Spk", NULL), - SND_SOC_DAPM_SPK("WR Ext Spk", NULL), - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_widget cml_rt1011_tt_widgets[] = { - SND_SOC_DAPM_SPK("TL Ext Spk", NULL), - SND_SOC_DAPM_SPK("TR Ext Spk", NULL), -}; - -static const struct snd_soc_dapm_route cml_rt1011_rt5682_map[] = { - /*WL/WR speaker*/ - {"WL Ext Spk", NULL, "WL SPO"}, - {"WR Ext Spk", NULL, "WR SPO"}, - - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* other jacks */ - { "IN1P", NULL, "Headset Mic" }, - - /* DMIC */ - {"DMic", NULL, "SoC DMIC"}, -}; - -static const struct snd_soc_dapm_route cml_rt1011_tt_map[] = { - /*TL/TR speaker*/ - {"TL Ext Spk", NULL, "TL SPO" }, - {"TR Ext Spk", NULL, "TR SPO" }, -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static int cml_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - int ret; - - /* need to enable ASRC function for 24MHz mclk rate */ - rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | - RT5682_AD_STEREO1_FILTER, - RT5682_CLK_SEL_I2S1_ASRC); - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) - dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); - - return ret; -}; - -static void cml_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - - snd_soc_component_set_jack(component, NULL, NULL); -} - -static int cml_rt1011_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret = 0; - struct snd_soc_card *card = rtd->card; - - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - - ret = snd_soc_add_card_controls(card, cml_rt1011_tt_controls, - ARRAY_SIZE(cml_rt1011_tt_controls)); - if (ret) - return ret; - - ret = snd_soc_dapm_new_controls(&card->dapm, - cml_rt1011_tt_widgets, - ARRAY_SIZE(cml_rt1011_tt_widgets)); - if (ret) - return ret; - - ret = snd_soc_dapm_add_routes(&card->dapm, cml_rt1011_tt_map, - ARRAY_SIZE(cml_rt1011_tt_map)); - - if (ret) - return ret; - } - - return ret; -} - -static int cml_rt5682_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out, ret; - - clk_id = RT5682_PLL1_S_MCLK; - clk_freq = CML_PLAT_CLK; - - pll_out = params_rate(params) * 512; - - ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (ret < 0) - dev_warn(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, - pll_out, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_warn(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - /* - * slot_width should be equal or large than data length, set them - * be the same - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, - params_width(params)); - if (ret < 0) - dev_warn(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; -} - -static int cml_rt1011_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - struct snd_soc_card *card = rtd->card; - int srate, i, ret = 0; - - srate = params_rate(params); - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - - /* 100 Fs to drive 24 bit data */ - ret = snd_soc_dai_set_pll(codec_dai, 0, RT1011_PLL1_S_BCLK, - 100 * srate, 256 * srate); - if (ret < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT1011_FS_SYS_PRE_S_PLL1, - 256 * srate, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "codec_dai clock not set\n"); - return ret; - } - - /* - * Codec TDM is configured as 24 bit capture/ playback. - * 2 CH PB is done over 4 codecs - 2 Woofers and 2 Tweeters. - * The Left woofer and tweeter plays the Left playback data - * and similar by the Right. - * Hence 2 codecs (1 T and 1 W pair) share same Rx slot. - * The feedback is captured for each codec individually. - * Hence all 4 codecs use 1 Tx slot each for feedback. - */ - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_WL | - SOF_RT1011_SPEAKER_WR)) { - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:00")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x4, 0x1, 4, 24); - if (ret < 0) - break; - } - - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:01")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x8, 0x2, 4, 24); - if (ret < 0) - break; - } - } - - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:02")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x1, 0x1, 4, 24); - if (ret < 0) - break; - } - - if (!strcmp(codec_dai->component->name, "i2c-10EC1011:03")) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x2, 0x2, 4, 24); - if (ret < 0) - break; - } - } - } - if (ret < 0) - dev_err(rtd->dev, - "set codec TDM slot for %s failed with error %d\n", - codec_dai->component->name, ret); - return ret; -} - -static struct snd_soc_ops cml_rt5682_ops = { - .hw_params = cml_rt5682_hw_params, -}; - -static const struct snd_soc_ops cml_rt1011_ops = { - .hw_params = cml_rt1011_hw_params, -}; - -static int sof_card_late_probe(struct snd_soc_card *card) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - char jack_name[NAME_SIZE]; - struct hdmi_pcm *pcm; - int ret, i = 0; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - ret = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &hdmi_jack[i]); - if (ret) - return ret; - - ret = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &hdmi_jack[i]); - if (ret < 0) - return ret; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -/* Cometlake digital audio interface glue - connects codec <--> CPU */ - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", - CML_RT5682_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec_2spk, - DAILINK_COMP_ARRAY( - /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), - /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI))); -SND_SOC_DAILINK_DEF(ssp1_codec_4spk, - DAILINK_COMP_ARRAY( - /* WL */ COMP_CODEC("i2c-10EC1011:00", CML_RT1011_CODEC_DAI), - /* WR */ COMP_CODEC("i2c-10EC1011:01", CML_RT1011_CODEC_DAI), - /* TL */ COMP_CODEC("i2c-10EC1011:02", CML_RT1011_CODEC_DAI), - /* TR */ COMP_CODEC("i2c-10EC1011:03", CML_RT1011_CODEC_DAI))); - - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -static struct snd_soc_dai_link cml_rt1011_rt5682_dailink[] = { - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .init = cml_rt5682_codec_init, - .exit = cml_rt5682_codec_exit, - .ignore_pmdown_time = 1, - .ops = &cml_rt5682_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - /* - * SSP1 - Codec : added to end of list ensuring - * reuse of common topologies for other end points - * and changing only SSP1's codec - */ - .name = "SSP1-Codec", - .id = 6, - .dpcm_playback = 1, - .dpcm_capture = 1, /* Capture stream provides Feedback */ - .no_pcm = 1, - .init = cml_rt1011_spk_init, - .ops = &cml_rt1011_ops, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec_2spk, platform), - }, -}; - -static struct snd_soc_codec_conf rt1011_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:00"), - .name_prefix = "WL", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:01"), - .name_prefix = "WR", - }, - /* single configuration structure for 2 and 4 channels */ - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:02"), - .name_prefix = "TL", - }, - { - .dlc = COMP_CODEC_CONF("i2c-10EC1011:03"), - .name_prefix = "TR", - }, -}; - -/* Cometlake audio machine driver for RT1011 and RT5682 */ -static struct snd_soc_card snd_soc_card_cml = { - .name = "cml_rt1011_rt5682", - .owner = THIS_MODULE, - .dai_link = cml_rt1011_rt5682_dailink, - .num_links = ARRAY_SIZE(cml_rt1011_rt5682_dailink), - .codec_conf = rt1011_conf, - .num_configs = ARRAY_SIZE(rt1011_conf), - .dapm_widgets = cml_rt1011_rt5682_widgets, - .num_dapm_widgets = ARRAY_SIZE(cml_rt1011_rt5682_widgets), - .dapm_routes = cml_rt1011_rt5682_map, - .num_dapm_routes = ARRAY_SIZE(cml_rt1011_rt5682_map), - .controls = cml_controls, - .num_controls = ARRAY_SIZE(cml_controls), - .fully_routed = true, - .late_probe = sof_card_late_probe, -}; - -static int snd_cml_rt1011_probe(struct platform_device *pdev) -{ - struct snd_soc_dai_link *dai_link; - struct card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - int ret, i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = pdev->dev.platform_data; - snd_soc_card_cml.dev = &pdev->dev; - platform_name = mach->mach_params.platform; - - dmi_check_system(sof_rt1011_quirk_table); - - dev_dbg(&pdev->dev, "sof_rt1011_quirk = %lx\n", sof_rt1011_quirk); - - /* when 4 speaker is available, update codec config */ - if (sof_rt1011_quirk & (SOF_RT1011_SPEAKER_TL | - SOF_RT1011_SPEAKER_TR)) { - for_each_card_prelinks(&snd_soc_card_cml, i, dai_link) { - if (!strcmp(dai_link->codecs[0].dai_name, - CML_RT1011_CODEC_DAI)) { - dai_link->codecs = ssp1_codec_4spk; - dai_link->num_codecs = ARRAY_SIZE(ssp1_codec_4spk); - } - } - } - - /* set platform name for each dailink */ - ret = snd_soc_fixup_dai_links_platform_name(&snd_soc_card_cml, - platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - snd_soc_card_set_drvdata(&snd_soc_card_cml, ctx); - - return devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cml); -} - -static struct platform_driver snd_cml_rt1011_rt5682_driver = { - .probe = snd_cml_rt1011_probe, - .driver = { - .name = "cml_rt1011_rt5682", - .pm = &snd_soc_pm_ops, - }, -}; -module_platform_driver(snd_cml_rt1011_rt5682_driver); - -/* Module information */ -MODULE_DESCRIPTION("Cometlake Audio Machine driver - RT1011 and RT5682 in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); -MODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:cml_rt1011_rt5682"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/ehl_rt5660.c b/sound/soc/intel/boards/ehl_rt5660.c index 686e60321224..5c7b218f22b7 100644 --- a/sound/soc/intel/boards/ehl_rt5660.c +++ b/sound/soc/intel/boards/ehl_rt5660.c @@ -132,7 +132,7 @@ static int rt5660_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rt5660_ops = { +static const struct snd_soc_ops rt5660_ops = { .hw_params = rt5660_hw_params, }; @@ -178,8 +178,6 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "SSP0-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &rt5660_ops, SND_SOC_DAILINK_REG(ssp0_pin, rt5660_codec, platform), }, @@ -187,7 +185,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic48k", .id = 1, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), }, @@ -195,7 +193,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "dmic16k", .id = 2, .ignore_suspend = 1, - .dpcm_capture = 1, + .capture_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), }, @@ -203,7 +201,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp1", .id = 5, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), }, @@ -211,7 +209,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp2", .id = 6, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), }, @@ -219,7 +217,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp3", .id = 7, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), }, @@ -227,7 +225,7 @@ static struct snd_soc_dai_link ehl_rt5660_dailink[] = { .name = "iDisp4", .id = 8, .init = hdmi_init, - .dpcm_playback = 1, + .playback_only = 1, .no_pcm = 1, SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), }, @@ -256,8 +254,7 @@ static void hdmi_link_init(struct snd_soc_card *card, { int i; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) { + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) { ctx->idisp_codec = true; return; } @@ -316,4 +313,4 @@ module_platform_driver(snd_ehl_rt5660_driver); MODULE_DESCRIPTION("ASoC Intel(R) Elkhartlake + rt5660 Machine driver"); MODULE_AUTHOR("libin.yang@intel.com"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/glk_rt5682_max98357a.c b/sound/soc/intel/boards/glk_rt5682_max98357a.c deleted file mode 100644 index 657e4658234c..000000000000 --- a/sound/soc/intel/boards/glk_rt5682_max98357a.c +++ /dev/null @@ -1,691 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018 Intel Corporation. - -/* - * Intel Geminilake I2S Machine Driver with MAX98357A & RT5682 Codecs - * - * Modified from: - * Intel Apollolake I2S Machine driver - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5682.h" -#include "../../codecs/rt5682s.h" -#include "../../codecs/hdac_hdmi.h" -#include "hda_dsp_common.h" - -/* The platform clock outputs 19.2Mhz clock to codec as I2S MCLK */ -#define GLK_PLAT_CLK_FREQ 19200000 -#define RT5682_PLL_FREQ (48000 * 512) -#define RT5682_DAI_NAME "rt5682-aif1" -#define RT5682S_DAI_NAME "rt5682s-aif1" -#define GLK_MAXIM_CODEC_DAI "HiFi" -#define RT5682_DEV0_NAME "i2c-10EC5682:00" -#define RT5682S_DEV0_NAME "i2c-RTL5682:00" -#define MAXIM_DEV0_NAME "MX98357A:00" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 -#define NAME_SIZE 32 - -static struct snd_soc_jack geminilake_hdmi[3]; - -struct glk_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct glk_card_private { - struct snd_soc_jack geminilake_headset; - struct list_head hdmi_pcm_list; - bool common_hdmi_codec_drv; - int is_rt5682s; -}; - -enum { - GLK_DPCM_AUDIO_PB = 0, - GLK_DPCM_AUDIO_CP, - GLK_DPCM_AUDIO_HS_PB, - GLK_DPCM_AUDIO_ECHO_REF_CP, - GLK_DPCM_AUDIO_REF_CP, - GLK_DPCM_AUDIO_DMIC_CP, - GLK_DPCM_AUDIO_HDMI1_PB, - GLK_DPCM_AUDIO_HDMI2_PB, - GLK_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new geminilake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget geminilake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route geminilake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "IN1P", NULL, "Headset Mic" }, - - /* digital mics */ - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec0_out" }, - - { "AIF1 Playback", NULL, "ssp2 Tx" }, - { "ssp2 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp2 Rx" }, - { "ssp2 Rx", NULL, "AIF1 Capture" }, - - { "HDMI1", NULL, "hif5-0 Output" }, - { "HDMI2", NULL, "hif6-0 Output" }, - { "HDMI2", NULL, "hif7-0 Output" }, - - { "hifi3", NULL, "iDisp3 Tx" }, - { "iDisp3 Tx", NULL, "iDisp3_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, -}; - -static int geminilake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int geminilake_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_jack *jack; - int pll_id, pll_source, clk_id, ret; - - if (ctx->is_rt5682s) { - pll_id = RT5682S_PLL2; - pll_source = RT5682S_PLL_S_MCLK; - clk_id = RT5682S_SCLK_S_PLL2; - } else { - pll_id = RT5682_PLL1; - pll_source = RT5682_PLL1_S_MCLK; - clk_id = RT5682_SCLK_S_PLL1; - } - - ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, - GLK_PLAT_CLK_FREQ, RT5682_PLL_FREQ); - if (ret < 0) { - dev_err(rtd->dev, "can't set codec pll: %d\n", ret); - return ret; - } - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, clk_id, - RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->geminilake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->geminilake_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) { - dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); - return ret; - } - - return ret; -}; - -static int geminilake_rt5682_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - /* Set valid bitmask & configuration for I2S in 24 bit */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 24); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - - return ret; -} - -static struct snd_soc_ops geminilake_rt5682_ops = { - .hw_params = geminilake_rt5682_hw_params, -}; - -static int geminilake_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct glk_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = GLK_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int geminilake_rt5682_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - struct snd_soc_dapm_context *dapm; - int ret; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) { - dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int geminilake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - chan->min = chan->max = 4; - - return 0; -} - -static int geminilake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops geminilake_dmic_ops = { - .startup = geminilake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static int geminilake_refcap_startup(struct snd_pcm_substream *substream) -{ - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -}; - -static const struct snd_soc_ops geminilake_refcap_ops = { - .startup = geminilake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME, - GLK_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); -SND_SOC_DAILINK_DEF(ssp2_codec_5682, - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682_DEV0_NAME, - RT5682_DAI_NAME))); -SND_SOC_DAILINK_DEF(ssp2_codec_5682s, - DAILINK_COMP_ARRAY(COMP_CODEC(RT5682S_DEV0_NAME, - RT5682S_DAI_NAME))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:0e.0"))); - -/* geminilake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link geminilake_dais[] = { - /* Front End DAI links */ - [GLK_DPCM_AUDIO_PB] = { - .name = "Glk Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = geminilake_rt5682_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [GLK_DPCM_AUDIO_CP] = { - .name = "Glk Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [GLK_DPCM_AUDIO_HS_PB] = { - .name = "Glk Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [GLK_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Glk Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [GLK_DPCM_AUDIO_REF_CP] = { - .name = "Glk Audio Reference cap", - .stream_name = "Refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &geminilake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [GLK_DPCM_AUDIO_DMIC_CP] = { - .name = "Glk Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &geminilake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI1_PB] = { - .name = "Glk HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI2_PB] = { - .name = "Glk HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [GLK_DPCM_AUDIO_HDMI3_PB] = { - .name = "Glk HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - /* Back End DAI links */ - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = geminilake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - /* SSP2 - Codec */ - .name = "SSP2-Codec", - .id = 1, - .no_pcm = 1, - .init = geminilake_rt5682_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = geminilake_ssp_fixup, - .ops = &geminilake_rt5682_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp2_pin, ssp2_codec_5682, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = geminilake_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = geminilake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static int glk_card_late_probe(struct snd_soc_card *card) -{ - struct glk_card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - char jack_name[NAME_SIZE]; - struct glk_hdmi_pcm *pcm; - int err; - int i = 0; - - if (list_empty(&ctx->hdmi_pcm_list)) - return -EINVAL; - - if (ctx->common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct glk_hdmi_pcm, - head); - component = pcm->codec_dai->component; - return hda_dsp_hdmi_build_controls(card, component); - } - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &geminilake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &geminilake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* geminilake audio machine driver for SPT + RT5682 */ -static struct snd_soc_card glk_audio_card_rt5682_m98357a = { - .name = "glkrt5682max", - .owner = THIS_MODULE, - .dai_link = geminilake_dais, - .num_links = ARRAY_SIZE(geminilake_dais), - .controls = geminilake_controls, - .num_controls = ARRAY_SIZE(geminilake_controls), - .dapm_widgets = geminilake_widgets, - .num_dapm_widgets = ARRAY_SIZE(geminilake_widgets), - .dapm_routes = geminilake_map, - .num_dapm_routes = ARRAY_SIZE(geminilake_map), - .fully_routed = true, - .late_probe = glk_card_late_probe, -}; - -static int geminilake_audio_probe(struct platform_device *pdev) -{ - struct glk_card_private *ctx; - struct snd_soc_acpi_mach *mach; - const char *platform_name; - struct snd_soc_card *card; - int ret, i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - /* Detect the headset codec variant */ - if (acpi_dev_present("RTL5682", NULL, -1)) { - /* ALC5682I-VS is detected */ - ctx->is_rt5682s = 1; - - for (i = 0; i < glk_audio_card_rt5682_m98357a.num_links; i++) { - if (strcmp(geminilake_dais[i].name, "SSP2-Codec")) - continue; - - /* update the dai link to use rt5682s codec */ - geminilake_dais[i].codecs = ssp2_codec_5682s; - geminilake_dais[i].num_codecs = ARRAY_SIZE(ssp2_codec_5682s); - break; - } - } - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - card = &glk_audio_card_rt5682_m98357a; - card->dev = &pdev->dev; - snd_soc_card_set_drvdata(card, ctx); - - /* override platform name, if required */ - mach = pdev->dev.platform_data; - platform_name = mach->mach_params.platform; - - ret = snd_soc_fixup_dai_links_platform_name(card, platform_name); - if (ret) - return ret; - - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - - return devm_snd_soc_register_card(&pdev->dev, card); -} - -static const struct platform_device_id glk_board_ids[] = { - { - .name = "glk_rt5682_mx98357a", - .driver_data = - (kernel_ulong_t)&glk_audio_card_rt5682_m98357a, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, glk_board_ids); - -static struct platform_driver geminilake_audio = { - .probe = geminilake_audio_probe, - .driver = { - .name = "glk_rt5682_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = glk_board_ids, -}; -module_platform_driver(geminilake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Geminilake Audio Machine driver-RT5682 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); diff --git a/sound/soc/intel/boards/hda_dsp_common.c b/sound/soc/intel/boards/hda_dsp_common.c index 04b7d4f7f9e2..86e541a2c204 100644 --- a/sound/soc/intel/boards/hda_dsp_common.c +++ b/sound/soc/intel/boards/hda_dsp_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2019 Intel Corporation. All rights reserved. +// Copyright(c) 2019 Intel Corporation #include <linux/module.h> #include <sound/pcm.h> @@ -83,7 +83,7 @@ int hda_dsp_hdmi_build_controls(struct snd_soc_card *card, return err; } -EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, SND_SOC_INTEL_HDA_DSP_COMMON); +EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, "SND_SOC_INTEL_HDA_DSP_COMMON"); #endif diff --git a/sound/soc/intel/boards/hsw_rt5640.c b/sound/soc/intel/boards/hsw_rt5640.c index 2a2fe27dff0e..9bb2822ba63e 100644 --- a/sound/soc/intel/boards/hsw_rt5640.c +++ b/sound/soc/intel/boards/hsw_rt5640.c @@ -2,7 +2,7 @@ /* * Sound card driver for Intel Haswell Lynx Point with Realtek 5640 * - * Copyright (C) 2013, Intel Corporation. All rights reserved. + * Copyright (C) 2013, Intel Corporation */ #include <linux/module.h> @@ -85,8 +85,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(system, dummy, platform), }, { @@ -95,7 +93,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload0, dummy, platform), }, { @@ -104,7 +102,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, + .playback_only = 1, SND_SOC_DAILINK_REG(offload1, dummy, platform), }, { @@ -113,7 +111,7 @@ static struct snd_soc_dai_link card_dai_links[] = { .nonatomic = 1, .dynamic = 1, .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, + .capture_only = 1, SND_SOC_DAILINK_REG(loopback, dummy, platform), }, /* Back End DAI links */ @@ -127,8 +125,6 @@ static struct snd_soc_dai_link card_dai_links[] = { .ignore_pmdown_time = 1, .be_hw_params_fixup = codec_link_hw_params_fixup, .ops = &codec_link_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, SND_SOC_DAILINK_REG(ssp0_port, codec, platform), }, }; diff --git a/sound/soc/intel/boards/kbl_da7219_max98357a.c b/sound/soc/intel/boards/kbl_da7219_max98357a.c deleted file mode 100644 index a5d8965303a8..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98357a.c +++ /dev/null @@ -1,687 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2017-18 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98357A & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define KBL_MAXIM_CODEC_DAI "HiFi" -#define MAXIM_DEV0_NAME "MX98357A:00" -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, - 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_jack *jack; - int ret; - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(MAXIM_DEV0_NAME, - KBL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", - "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kabylake_audio_card_da7219_m98357a = { - .name = "kblda7219max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_mx98357a", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_da7219_m98357a, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Naveen Manohar <naveen.m@intel.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_da7219_max98927.c b/sound/soc/intel/boards/kbl_da7219_max98927.c deleted file mode 100644 index 98c11ec0adc0..000000000000 --- a/sound/soc/intel/boards/kbl_da7219_max98927.c +++ /dev/null @@ -1,1171 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018 Intel Corporation. - -/* - * Intel Kabylake I2S Machine Driver with MAX98927, MAX98373 & DA7219 Codecs - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAX98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include "../../codecs/da7219.h" -#include "../../codecs/hdac_hdmi.h" - -#define KBL_DIALOG_CODEC_DAI "da7219-hifi" -#define MAX98927_CODEC_DAI "max98927-aif1" -#define MAX98927_DEV0_NAME "i2c-MX98927:00" -#define MAX98927_DEV1_NAME "i2c-MX98927:01" - -#define MAX98373_CODEC_DAI "max98373-aif1" -#define MAX98373_DEV0_NAME "i2c-MX98373:00" -#define MAX98373_DEV1_NAME "i2c-MX98373:01" - - -#define DUAL_CHANNEL 2 -#define QUAD_CHANNEL 4 -#define NAME_SIZE 32 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack kabylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_CP, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret = 0; - - codec_dai = snd_soc_card_get_codec_dai(card, KBL_DIALOG_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); - return -EIO; - } - - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24576000, - SND_SOC_CLOCK_IN); - if (ret) { - dev_err(card->dev, "can't set codec sysclk configuration\n"); - return ret; - } - - if (SND_SOC_DAPM_EVENT_OFF(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, - DA7219_SYSCLK_MCLK, 0, 0); - if (ret) - dev_err(card->dev, "failed to stop PLL: %d\n", ret); - } else if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, - 0, DA7219_PLL_FREQ_OUT_98304); - if (ret) - dev_err(card->dev, "failed to start PLL: %d\n", ret); - } - - return ret; -} - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Line Out", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* AEC capture path */ - { "echo_ref_out", NULL, "ssp0 Rx" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static const struct snd_soc_dapm_route kabylake_ssp1_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret, j; - - for_each_rtd_codec_dais(runtime, j, codec_dai) { - - if (!strcmp(codec_dai->component->name, MAX98927_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98927_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, - "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX98373_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, - 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(runtime->dev, - "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - - return 0; -} - -static int kabylake_ssp0_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int j, ret; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - const char *name = codec_dai->component->name; - struct snd_soc_component *component = codec_dai->component; - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(component); - char pin_name[20]; - - if (strcmp(name, MAX98927_DEV0_NAME) && - strcmp(name, MAX98927_DEV1_NAME) && - strcmp(name, MAX98373_DEV0_NAME) && - strcmp(name, MAX98373_DEV1_NAME)) - continue; - - snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", - codec_dai->component->name_prefix); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = snd_soc_dapm_enable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to enable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = snd_soc_dapm_disable_pin(dapm, pin_name); - if (ret) { - dev_err(rtd->dev, "failed to disable %s: %d\n", - pin_name, ret); - return ret; - } - snd_soc_dapm_sync(dapm); - break; - } - } - - return 0; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, - .trigger = kabylake_ssp0_trigger, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - struct snd_soc_card *card = rtd->card; - int ret; - - - ret = snd_soc_dapm_add_routes(&card->dapm, - kabylake_ssp1_map, - ARRAY_SIZE(kabylake_ssp1_map)); - - if (ret) - return ret; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - return 0; -} - -static int kabylake_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) - dev_err(rtd->dev, "SoC DMIC - Ignore suspend failed %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static unsigned int channels_quad[] = { - QUAD_CHANNEL, -}; - -static struct snd_pcm_hw_constraint_list constraints_channels_quad = { - .count = ARRAY_SIZE(channels_quad), - .list = channels_quad, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_da7219_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - /* - * set BE channel constraint as user FE channels - */ - - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels_quad); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - - -static struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98927_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_codec_conf max98373_codec_conf[] = { - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV0_NAME), - .name_prefix = "Right", - }, - - { - .dlc = COMP_CODEC_CONF(MAX98373_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static struct snd_soc_dai_link_component max98373_ssp0_codec_components[] = { - { /* Left */ - .name = MAX98373_DEV0_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - - { /* For Right */ - .name = MAX98373_DEV1_NAME, - .dai_name = MAX98373_CODEC_DAI, - }, - -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAX98927_DEV0_NAME, MAX98927_CODEC_DAI), - /* For Right */ COMP_CODEC(MAX98927_DEV1_NAME, MAX98927_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", - KBL_DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_da7219_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_max98_927_373_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_da7219_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_da7219_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec), - }, - { - .name = "dmic01", - .id = 1, - .init = kabylake_dmic_init, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_dapm_context *dapm = &card->dapm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &kabylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &kabylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - - err = hdac_hdmi_jack_port_init(component, &card->dapm); - - if (err < 0) - return err; - - err = snd_soc_dapm_disable_pin(dapm, "Left Spk"); - if (err) { - dev_err(card->dev, "failed to disable Left Spk: %d\n", err); - return err; - } - - err = snd_soc_dapm_disable_pin(dapm, "Right Spk"); - if (err) { - dev_err(card->dev, "failed to disable Right Spk: %d\n", err); - return err; - } - - return snd_soc_dapm_sync(dapm); -} - -/* kabylake audio machine driver for SPT + DA7219 */ -static struct snd_soc_card kbl_audio_card_da7219_m98927 = { - .name = "kblda7219m98927", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for Maxim98927 */ -static struct snd_soc_card kbl_audio_card_max98927 = { - .name = "kblmax98927", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_da7219_m98373 = { - .name = "kblda7219m98373", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static struct snd_soc_card kbl_audio_card_max98373 = { - .name = "kblmax98373", - .owner = THIS_MODULE, - .dai_link = kabylake_max98_927_373_dais, - .num_links = ARRAY_SIZE(kabylake_max98_927_373_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_dai_link *kbl_dai_link; - struct snd_soc_dai_link_component **codecs; - int i; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kbl_dai_link = kabylake_audio_card->dai_link; - - /* Update codecs for SSP0 with max98373 codec info */ - if (!strcmp(pdev->name, "kbl_da7219_max98373") || - (!strcmp(pdev->name, "kbl_max98373"))) { - for (i = 0; i < kabylake_audio_card->num_links; ++i) { - if (strcmp(kbl_dai_link[i].name, "SSP0-Codec")) - continue; - - codecs = &(kbl_dai_link[i].codecs); - *codecs = max98373_ssp0_codec_components; - kbl_dai_link[i].num_codecs = - ARRAY_SIZE(max98373_ssp0_codec_components); - break; - } - } - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_da7219_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98927, - }, - { - .name = "kbl_max98927", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98927, - }, - { - .name = "kbl_da7219_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_da7219_m98373, - }, - { - .name = "kbl_max98373", - .driver_data = - (kernel_ulong_t)&kbl_audio_card_max98373, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_da7219_max98_927_373", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio KabyLake Machine driver for MAX98927/MAX98373 & DA7219"); -MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5660.c b/sound/soc/intel/boards/kbl_rt5660.c deleted file mode 100644 index 30e0aca161cd..000000000000 --- a/sound/soc/intel/boards/kbl_rt5660.c +++ /dev/null @@ -1,566 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2018-19 Canonical Corporation. - -/* - * Intel Kabylake I2S Machine Driver with RT5660 Codec - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98357a and - * DA7219 codecs - * Also referred to: - * Intel Broadwell I2S Machine driver supporting RT5677 codec - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/gpio/consumer.h> -#include <linux/acpi.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> - -#include "../../codecs/hdac_hdmi.h" -#include "../../codecs/rt5660.h" - -#define KBL_RT5660_CODEC_DAI "rt5660-aif1" -#define DUAL_CHANNEL 2 - -static struct snd_soc_card *kabylake_audio_card; -static struct snd_soc_jack skylake_hdmi[3]; -static struct snd_soc_jack lineout_jack; -static struct snd_soc_jack mic_jack; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct gpio_desc *gpio_lo_mute; - struct list_head hdmi_pcm_list; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -#define GPIO_LINEOUT_MUTE_INDEX 0 -#define GPIO_LINEOUT_DET_INDEX 3 -#define GPIO_LINEIN_DET_INDEX 4 - -static const struct acpi_gpio_params lineout_mute_gpio = { GPIO_LINEOUT_MUTE_INDEX, 0, true }; -static const struct acpi_gpio_params lineout_det_gpio = { GPIO_LINEOUT_DET_INDEX, 0, false }; -static const struct acpi_gpio_params mic_det_gpio = { GPIO_LINEIN_DET_INDEX, 0, false }; - - -static const struct acpi_gpio_mapping acpi_rt5660_gpios[] = { - { "lineout-mute-gpios", &lineout_mute_gpio, 1 }, - { "lineout-det-gpios", &lineout_det_gpio, 1 }, - { "mic-det-gpios", &mic_det_gpio, 1 }, - { NULL }, -}; - -static struct snd_soc_jack_pin lineout_jack_pin = { - .pin = "Line Out", - .mask = SND_JACK_LINEOUT, -}; - -static struct snd_soc_jack_pin mic_jack_pin = { - .pin = "Line In", - .mask = SND_JACK_MICROPHONE, -}; - -static struct snd_soc_jack_gpio lineout_jack_gpio = { - .name = "lineout-det", - .report = SND_JACK_LINEOUT, - .debounce_time = 200, -}; - -static struct snd_soc_jack_gpio mic_jack_gpio = { - .name = "mic-det", - .report = SND_JACK_MICROPHONE, - .debounce_time = 200, -}; - -static int kabylake_5660_event_lineout(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(dapm->card); - - gpiod_set_value_cansleep(priv->gpio_lo_mute, - !(SND_SOC_DAPM_EVENT_ON(event))); - - return 0; -} - -static const struct snd_kcontrol_new kabylake_rt5660_controls[] = { - SOC_DAPM_PIN_SWITCH("Line In"), - SOC_DAPM_PIN_SWITCH("Line Out"), -}; - -static const struct snd_soc_dapm_widget kabylake_rt5660_widgets[] = { - SND_SOC_DAPM_MIC("Line In", NULL), - SND_SOC_DAPM_LINE("Line Out", kabylake_5660_event_lineout), -}; - -static const struct snd_soc_dapm_route kabylake_rt5660_map[] = { - /* other jacks */ - {"IN1P", NULL, "Line In"}, - {"IN2P", NULL, "Line In"}, - {"Line Out", NULL, "LOUTR"}, - {"Line Out", NULL, "LOUTL"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, -}; - -static int kabylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = DUAL_CHANNEL; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int kabylake_rt5660_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - - ret = devm_acpi_dev_add_driver_gpios(component->dev, acpi_rt5660_gpios); - if (ret) - dev_warn(component->dev, "Failed to add driver gpios\n"); - - /* Request rt5660 GPIO for lineout mute control, return if fails */ - ctx->gpio_lo_mute = gpiod_get(component->dev, "lineout-mute", - GPIOD_OUT_HIGH); - if (IS_ERR(ctx->gpio_lo_mute)) { - dev_err(component->dev, "Can't find GPIO_MUTE# gpio\n"); - return PTR_ERR(ctx->gpio_lo_mute); - } - - /* Create and initialize headphone jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Lineout Jack", - SND_JACK_LINEOUT, &lineout_jack, - &lineout_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create Lineout jack\n"); - else { - lineout_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&lineout_jack, 1, - &lineout_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add Lineout jack gpio\n"); - } - - /* Create and initialize mic jack, this jack is not mandatory, don't return if fails */ - ret = snd_soc_card_jack_new_pins(rtd->card, "Mic Jack", - SND_JACK_MICROPHONE, &mic_jack, - &mic_jack_pin, 1); - if (ret) - dev_warn(component->dev, "Can't create mic jack\n"); - else { - mic_jack_gpio.gpiod_dev = component->dev; - ret = snd_soc_jack_add_gpios(&mic_jack, 1, &mic_jack_gpio); - if (ret) - dev_warn(component->dev, "Can't add mic jack gpio\n"); - } - - /* Here we enable some dapms in advance to reduce the pop noise for recording via line-in */ - snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); - snd_soc_dapm_force_enable_pin(dapm, "BST1"); - snd_soc_dapm_force_enable_pin(dapm, "BST2"); - - return 0; -} - -static void kabylake_rt5660_codec_exit(struct snd_soc_pcm_runtime *rtd) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - - /* - * The .exit() can be reached without going through the .init() - * so explicitly test if the gpiod is valid - */ - if (!IS_ERR_OR_NULL(ctx->gpio_lo_mute)) - gpiod_put(ctx->gpio_lo_mute); -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_rt5660_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5660_SCLK_S_PLL1, params_rate(params) * 512, - SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_pll(codec_dai, 0, - RT5660_PLL1_S_BCLK, - params_rate(params) * 50, - params_rate(params) * 512); - if (ret < 0) - dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5660_ops = { - .hw_params = kabylake_rt5660_hw_params, -}; - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - DUAL_CHANNEL, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = DUAL_CHANNEL; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5660_fe_ops = { - .startup = kbl_fe_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC3277:00", KBL_RT5660_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects rt5660 codec <--> CPU */ -static struct snd_soc_dai_link kabylake_rt5660_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5660_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5660_codec_init, - .exit = kabylake_rt5660_codec_exit, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp0_fixup, - .ops = &kabylake_rt5660_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for rt5660 */ -static struct snd_soc_card kabylake_audio_card_rt5660 = { - .name = "kblrt5660", - .owner = THIS_MODULE, - .dai_link = kabylake_rt5660_dais, - .num_links = ARRAY_SIZE(kabylake_rt5660_dais), - .controls = kabylake_rt5660_controls, - .num_controls = ARRAY_SIZE(kabylake_rt5660_controls), - .dapm_widgets = kabylake_rt5660_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_rt5660_widgets), - .dapm_routes = kabylake_rt5660_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_rt5660_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5660", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5660, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5660", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5660 in I2S mode"); -MODULE_AUTHOR("Hui Wang <hui.wang@canonical.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5663_max98927.c b/sound/soc/intel/boards/kbl_rt5663_max98927.c deleted file mode 100644 index 9071b1f1cbd0..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_max98927.c +++ /dev/null @@ -1,1071 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine driver - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define DMIC_CH(p) p->list[p->count-1] -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" - -static struct snd_soc_card *kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_rt5663_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, - KBL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_rt5663_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -enum { - KBL_DPCM_AUDIO_5663_PB = 0, - KBL_DPCM_AUDIO_5663_CP, - KBL_DPCM_AUDIO_5663_HDMI1_PB, - KBL_DPCM_AUDIO_5663_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_5663_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static const struct snd_soc_dapm_widget kabylake_5663_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_5663_map[] = { - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - {"HDMI1", NULL, "hif5-0 Output"}, - {"HDMI2", NULL, "hif6-0 Output"}, - {"HDMI3", NULL, "hif7-0 Output"}, - - /* CODEC BE connections */ - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) { - dev_err(rtd->dev, "Ref Cap ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - return ret; -} - -static int kabylake_rt5663_max98927_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - ret = kabylake_rt5663_codec_init(rtd); - if (ret) - return ret; - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - if (ret) { - dev_err(rtd->dev, "SoC DMIC ignore suspend failed %d\n", ret); - return ret; - } - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static int kabylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI3_PB); -} - -static int kabylake_5663_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI1_PB); -} - -static int kabylake_5663_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_5663_HDMI2_PB); -} - -static unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - /* - * Use channel 4 and 5 for the first amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - /* - * Use channel 6 and 7 for the second amp - */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static unsigned int channels_dmic[] = { - 2, 4, -}; - -static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -static unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int kabylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static struct snd_soc_ops skylake_refcap_ops = { - .startup = kabylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5663:00", - KBL_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_REF_CP] = { - .name = "Kbl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Kbl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_max98927_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = kabylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = kabylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -static struct snd_soc_dai_link kabylake_5663_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_5663_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_5663_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .init = kabylake_rt5663_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .init = kabylake_5663_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .init = kabylake_5663_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_rt5663_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* kabylake audio machine driver for SPT + RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663_m98927 = { - .name = "kblrt5663max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -/* kabylake audio machine driver for RT5663 */ -static struct snd_soc_card kabylake_audio_card_rt5663 = { - .name = "kblrt5663", - .owner = THIS_MODULE, - .dai_link = kabylake_5663_dais, - .num_links = ARRAY_SIZE(kabylake_5663_dais), - .controls = kabylake_5663_controls, - .num_controls = ARRAY_SIZE(kabylake_5663_controls), - .dapm_widgets = kabylake_5663_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_5663_widgets), - .dapm_routes = kabylake_5663_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_5663_map), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_rt5663_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card = - (struct snd_soc_card *)pdev->id_entry->driver_data; - - kabylake_audio_card->dev = &pdev->dev; - snd_soc_card_set_drvdata(kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { - .name = "kbl_rt5663", - .driver_data = (kernel_ulong_t)&kabylake_audio_card_rt5663, - }, - { - .name = "kbl_rt5663_m98927", - .driver_data = - (kernel_ulong_t)&kabylake_audio_card_rt5663_m98927, - }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_rt5663_m98927", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 & MAX98927 in I2S mode"); -MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c b/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c deleted file mode 100644 index 178fe9c37df6..000000000000 --- a/sound/soc/intel/boards/kbl_rt5663_rt5514_max98927.c +++ /dev/null @@ -1,868 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Kabylake I2S Machine Driver with MAXIM98927 - * RT5514 and RT5663 Codecs - * - * Copyright (C) 2017, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Kabylake I2S Machine driver supporting MAXIM98927 and - * RT5663 codecs - */ - -#include <linux/input.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/rt5514.h" -#include "../../codecs/rt5663.h" -#include "../../codecs/hdac_hdmi.h" -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> - -#define KBL_REALTEK_CODEC_DAI "rt5663-aif" -#define KBL_REALTEK_DMIC_CODEC_DAI "rt5514-aif1" -#define KBL_MAXIM_CODEC_DAI "max98927-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98927:00" -#define MAXIM_DEV1_NAME "i2c-MX98927:01" -#define RT5514_DEV_NAME "i2c-10EC5514:00" -#define RT5663_DEV_NAME "i2c-10EC5663:00" -#define RT5514_AIF1_BCLK_FREQ (48000 * 8 * 16) -#define RT5514_AIF1_SYSCLK_FREQ 12288000 -#define NAME_SIZE 32 - -#define DMIC_CH(p) p->list[p->count-1] - - -static struct snd_soc_card kabylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; - -struct kbl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct kbl_codec_private { - struct snd_soc_jack kabylake_headset; - struct list_head hdmi_pcm_list; - struct snd_soc_jack kabylake_hdmi[2]; - struct clk *mclk; - struct clk *sclk; -}; - -enum { - KBL_DPCM_AUDIO_PB = 0, - KBL_DPCM_AUDIO_CP, - KBL_DPCM_AUDIO_HS_PB, - KBL_DPCM_AUDIO_ECHO_REF_CP, - KBL_DPCM_AUDIO_DMIC_CP, - KBL_DPCM_AUDIO_RT5514_DSP, - KBL_DPCM_AUDIO_HDMI1_PB, - KBL_DPCM_AUDIO_HDMI2_PB, -}; - -static const struct snd_kcontrol_new kabylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - SOC_DAPM_PIN_SWITCH("DMIC"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - /* - * MCLK/SCLK need to be ON early for a successful synchronization of - * codec internal clock. And the clocks are turned off during - * POST_PMD after the stream is stopped. - */ - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - /* Enable MCLK */ - ret = clk_set_rate(priv->mclk, 24000000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", ret); - return ret; - } - - /* Enable SCLK */ - ret = clk_set_rate(priv->sclk, 3072000); - if (ret < 0) { - dev_err(card->dev, "Can't set rate for sclk, err: %d\n", - ret); - clk_disable_unprepare(priv->mclk); - return ret; - } - - ret = clk_prepare_enable(priv->sclk); - if (ret < 0) { - dev_err(card->dev, "Can't enable sclk, err: %d\n", ret); - clk_disable_unprepare(priv->mclk); - } - break; - case SND_SOC_DAPM_POST_PMD: - clk_disable_unprepare(priv->mclk); - clk_disable_unprepare(priv->sclk); - break; - default: - return 0; - } - - return 0; -} - -static const struct snd_soc_dapm_widget kabylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_MIC("DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), - -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route kabylake_map[] = { - /* Headphones */ - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* other jacks */ - { "Headset Mic", NULL, "Platform Clock" }, - { "IN1P", NULL, "Headset Mic" }, - { "IN1N", NULL, "Headset Mic" }, - - /* CODEC BE connections */ - { "Left HiFi Playback", NULL, "ssp0 Tx" }, - { "Right HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "spk_out" }, - - { "AIF Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "hs_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "AIF Capture" }, - - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - /* IV feedback path */ - { "codec0_fb_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left HiFi Capture" }, - { "ssp0 Rx", NULL, "Right HiFi Capture" }, - - /* DMIC */ - { "DMIC1L", NULL, "DMIC" }, - { "DMIC1R", NULL, "DMIC" }, - { "DMIC2L", NULL, "DMIC" }, - { "DMIC2R", NULL, "DMIC" }, - - { "hifi2", NULL, "iDisp2 Tx" }, - { "iDisp2 Tx", NULL, "iDisp2_out" }, - { "hifi1", NULL, "iDisp1 Tx" }, - { "iDisp1 Tx", NULL, "iDisp1_out" }, -}; - -static struct snd_soc_codec_conf max98927_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, -}; - - -static int kabylake_rt5663_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - int ret; - - dapm = snd_soc_component_get_dapm(component); - ret = snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - if (ret) - dev_err(rtd->dev, "Ref Cap -Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_rt5663_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct snd_soc_jack *jack; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(&kabylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - &ctx->kabylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - jack = &ctx->kabylake_headset; - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - snd_soc_component_set_jack(component, &ctx->kabylake_headset, NULL); - - ret = snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "DMIC"); - if (ret) - dev_err(rtd->dev, "DMIC - Ignore suspend failed = %d\n", ret); - - return ret; -} - -static int kabylake_hdmi_init(struct snd_soc_pcm_runtime *rtd, int device) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct kbl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = device; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int kabylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI1_PB); -} - -static int kabylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - return kabylake_hdmi_init(rtd, KBL_DPCM_AUDIO_HDMI2_PB); -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int kbl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops kabylake_rt5663_fe_ops = { - .startup = kbl_fe_startup, -}; - -static int kabylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - struct snd_soc_dpcm *dpcm, *rtd_dpcm = NULL; - - /* - * The following loop will be called only for playback stream - * In this platform, there is only one playback device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_PLAYBACK, dpcm) { - rtd_dpcm = dpcm; - break; - } - - /* - * This following loop will be called only for capture stream - * In this platform, there is only one capture device on every SSP - */ - for_each_dpcm_fe(rtd, SNDRV_PCM_STREAM_CAPTURE, dpcm) { - rtd_dpcm = dpcm; - break; - } - - if (!rtd_dpcm) - return -EINVAL; - - /* - * The above 2 loops are mutually exclusive based on the stream direction, - * thus rtd_dpcm variable will never be overwritten - */ - - /* - * The ADSP will convert the FE rate to 48k, stereo, 24 bit - */ - if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Port") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Headset Playback") || - !strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio Capture Port")) { - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - } else if (!strcmp(rtd_dpcm->fe->dai_link->name, "Kbl Audio DMIC cap")) { - if (params_channels(params) == 2 || - DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - } - /* - * The speaker on the SSP0 supports S16_LE and not S24_LE. - * thus changing the mask here - */ - if (!strcmp(rtd_dpcm->be->dai_link->name, "SSP0-Codec")) - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); - - return 0; -} - -static int kabylake_rt5663_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - /* use ASRC for internal clocks, as PLL rate isn't multiple of BCLK */ - rt5663_sel_asrc_clk_src(codec_dai->component, - RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER, - RT5663_CLK_SEL_I2S1_ASRC); - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5663_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static struct snd_soc_ops kabylake_rt5663_ops = { - .hw_params = kabylake_rt5663_hw_params, -}; - -static int kabylake_ssp0_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - int ret = 0, j; - - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, RT5514_DEV_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "set TDM slot err:%d\n", ret); - return ret; - } - - ret = snd_soc_dai_set_sysclk(codec_dai, - RT5514_SCLK_S_MCLK, 24576000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(rtd->dev, "set sysclk err: %d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x30, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC0, 3, 8, 16); - if (ret < 0) { - dev_err(rtd->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } - return ret; -} - -static struct snd_soc_ops kabylake_ssp0_ops = { - .hw_params = kabylake_ssp0_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int kabylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static struct snd_soc_ops kabylake_dmic_ops = { - .startup = kabylake_dmic_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(system2, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin2"))); - -SND_SOC_DAILINK_DEF(echoref, - DAILINK_COMP_ARRAY(COMP_CPU("Echoref Pin"))); - -SND_SOC_DAILINK_DEF(spi_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("spi-PRP0001:00"))); -SND_SOC_DAILINK_DEF(spi_platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("spi-PRP0001:00"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, KBL_MAXIM_CODEC_DAI), - /* Right */COMP_CODEC(MAXIM_DEV1_NAME, KBL_MAXIM_CODEC_DAI), - /* dmic */ COMP_CODEC(RT5514_DEV_NAME, KBL_REALTEK_DMIC_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC(RT5663_DEV_NAME, KBL_REALTEK_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* kabylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link kabylake_dais[] = { - /* Front End DAI links */ - [KBL_DPCM_AUDIO_PB] = { - .name = "Kbl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = kabylake_rt5663_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_CP] = { - .name = "Kbl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &kabylake_rt5663_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [KBL_DPCM_AUDIO_HS_PB] = { - .name = "Kbl Audio Headset Playback", - .stream_name = "Headset Audio", - .dpcm_playback = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(system2, dummy, platform), - }, - [KBL_DPCM_AUDIO_ECHO_REF_CP] = { - .name = "Kbl Audio Echo Reference cap", - .stream_name = "Echoreference Capture", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - SND_SOC_DAILINK_REG(echoref, dummy, platform), - }, - [KBL_DPCM_AUDIO_RT5514_DSP] = { - .name = "rt5514 dsp", - .stream_name = "Wake on Voice", - SND_SOC_DAILINK_REG(spi_cpu, dummy, spi_platform), - }, - [KBL_DPCM_AUDIO_DMIC_CP] = { - .name = "Kbl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &kabylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Kbl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [KBL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Kbl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - /* Back End DAI links */ - /* single Back end dai for both max speakers and dmic */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - .ops = &kabylake_ssp0_ops, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = kabylake_rt5663_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = kabylake_ssp_fixup, - .ops = &kabylake_rt5663_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = kabylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = kabylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, -}; - -static int kabylake_set_bias_level(struct snd_soc_card *card, - struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) -{ - struct snd_soc_component *component = dapm->component; - struct kbl_codec_private *priv = snd_soc_card_get_drvdata(card); - int ret = 0; - - if (!component || strcmp(component->name, RT5514_DEV_NAME)) - return 0; - - if (IS_ERR(priv->mclk)) - return 0; - - /* - * It's required to control mclk directly in the set_bias_level - * function for rt5514 codec or the recording function could - * break. - */ - switch (level) { - case SND_SOC_BIAS_PREPARE: - if (dapm->bias_level == SND_SOC_BIAS_ON) { - if (!__clk_is_enabled(priv->mclk)) - return 0; - dev_dbg(card->dev, "Disable mclk"); - clk_disable_unprepare(priv->mclk); - } else { - dev_dbg(card->dev, "Enable mclk"); - ret = clk_set_rate(priv->mclk, 24000000); - if (ret) { - dev_err(card->dev, "Can't set rate for mclk, err: %d\n", - ret); - return ret; - } - - ret = clk_prepare_enable(priv->mclk); - if (ret) { - dev_err(card->dev, "Can't enable mclk, err: %d\n", - ret); - - /* mclk is already enabled in FW */ - ret = 0; - } - } - break; - default: - break; - } - - return ret; -} - -static int kabylake_card_late_probe(struct snd_soc_card *card) -{ - struct kbl_codec_private *ctx = snd_soc_card_get_drvdata(card); - struct kbl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP,pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &ctx->kabylake_hdmi[i]); - - if (err) - return err; - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &ctx->kabylake_hdmi[i]); - if (err < 0) - return err; - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* - * kabylake audio machine driver for MAX98927 + RT5514 + RT5663 - */ -static struct snd_soc_card kabylake_audio_card = { - .name = "kbl-r5514-5663-max", - .owner = THIS_MODULE, - .dai_link = kabylake_dais, - .num_links = ARRAY_SIZE(kabylake_dais), - .set_bias_level = kabylake_set_bias_level, - .controls = kabylake_controls, - .num_controls = ARRAY_SIZE(kabylake_controls), - .dapm_widgets = kabylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(kabylake_widgets), - .dapm_routes = kabylake_map, - .num_dapm_routes = ARRAY_SIZE(kabylake_map), - .codec_conf = max98927_codec_conf, - .num_configs = ARRAY_SIZE(max98927_codec_conf), - .fully_routed = true, - .late_probe = kabylake_card_late_probe, -}; - -static int kabylake_audio_probe(struct platform_device *pdev) -{ - struct kbl_codec_private *ctx; - struct snd_soc_acpi_mach *mach; - int ret; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - kabylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&kabylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - ctx->mclk = devm_clk_get(&pdev->dev, "ssp1_mclk"); - if (IS_ERR(ctx->mclk)) { - ret = PTR_ERR(ctx->mclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_mclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_mclk with err:%d\n", - ret); - return ret; - } - - ctx->sclk = devm_clk_get(&pdev->dev, "ssp1_sclk"); - if (IS_ERR(ctx->sclk)) { - ret = PTR_ERR(ctx->sclk); - if (ret == -ENOENT) { - dev_info(&pdev->dev, - "Failed to get ssp1_sclk, defer probe\n"); - return -EPROBE_DEFER; - } - - dev_err(&pdev->dev, "Failed to get ssp1_sclk with err:%d\n", - ret); - return ret; - } - - return devm_snd_soc_register_card(&pdev->dev, &kabylake_audio_card); -} - -static const struct platform_device_id kbl_board_ids[] = { - { .name = "kbl_r5514_5663_max" }, - { } -}; -MODULE_DEVICE_TABLE(platform, kbl_board_ids); - -static struct platform_driver kabylake_audio = { - .probe = kabylake_audio_probe, - .driver = { - .name = "kbl_r5514_5663_max", - .pm = &snd_soc_pm_ops, - }, - .id_table = kbl_board_ids, -}; - -module_platform_driver(kabylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-RT5663 RT5514 & MAX98927"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.c b/sound/soc/intel/boards/skl_hda_dsp_common.c deleted file mode 100644 index e9cefa4ae56d..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.c +++ /dev/null @@ -1,168 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2015-18 Intel Corporation. - -/* - * Common functions used in different Intel machine drivers - */ -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -#include <sound/hda_codec.h> -#include "../../codecs/hdac_hda.h" - -#define NAME_SIZE 32 - -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hda_hdmi_pcm *pcm; - char dai_name[NAME_SIZE]; - - pcm = devm_kzalloc(card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - snprintf(dai_name, sizeof(dai_name), "intel-hdmi-hifi%d", - ctx->dai_index); - pcm->codec_dai = snd_soc_card_get_codec_dai(card, dai_name); - if (!pcm->codec_dai) - return -EINVAL; - - pcm->device = device; - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -SND_SOC_DAILINK_DEF(idisp1_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(analog_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); -SND_SOC_DAILINK_DEF(analog_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); - -SND_SOC_DAILINK_DEF(digital_cpu, - DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); -SND_SOC_DAILINK_DEF(digital_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); - -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skl_hda_digital audio interface glue - connects codec <--> CPU */ -struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS] = { - /* Back End DAI links */ - { - .name = "iDisp1", - .id = 1, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_cpu, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 2, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_cpu, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 3, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_cpu, idisp3_codec, platform), - }, - { - .name = "Analog Playback and Capture", - .id = 4, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(analog_cpu, analog_codec, platform), - }, - { - .name = "Digital Playback and Capture", - .id = 5, - .dpcm_playback = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(digital_cpu, digital_codec, platform), - }, - { - .name = "dmic01", - .id = 6, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 7, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k, dmic_codec, platform), - }, -}; - -int skl_hda_hdmi_jack_init(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component = NULL; - struct skl_hda_hdmi_pcm *pcm; - char jack_name[NAME_SIZE]; - int err; - - if (ctx->common_hdmi_codec_drv) - return skl_hda_hdmi_build_controls(card); - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &pcm->hdmi_jack); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &pcm->hdmi_jack); - if (err < 0) - return err; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} diff --git a/sound/soc/intel/boards/skl_hda_dsp_common.h b/sound/soc/intel/boards/skl_hda_dsp_common.h deleted file mode 100644 index 4b0b3959182e..000000000000 --- a/sound/soc/intel/boards/skl_hda_dsp_common.h +++ /dev/null @@ -1,66 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2015-18 Intel Corporation. - */ - -/* - * This file defines data structures used in Machine Driver for Intel - * platforms with HDA Codecs. - */ - -#ifndef __SKL_HDA_DSP_COMMON_H -#define __SKL_HDA_DSP_COMMON_H -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/hda_codec.h> -#include "../../codecs/hdac_hda.h" -#include "hda_dsp_common.h" - -#define HDA_DSP_MAX_BE_DAI_LINKS 7 - -struct skl_hda_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - struct snd_soc_jack hdmi_jack; - int device; -}; - -struct skl_hda_private { - struct list_head hdmi_pcm_list; - int pcm_count; - int dai_index; - const char *platform_name; - bool common_hdmi_codec_drv; - bool idisp_codec; -}; - -extern struct snd_soc_dai_link skl_hda_be_dai_links[HDA_DSP_MAX_BE_DAI_LINKS]; -int skl_hda_hdmi_jack_init(struct snd_soc_card *card); -int skl_hda_hdmi_add_pcm(struct snd_soc_card *card, int device); - -/* - * Search card topology and register HDMI PCM related controls - * to codec driver. - */ -static inline int skl_hda_hdmi_build_controls(struct snd_soc_card *card) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_component *component; - struct skl_hda_hdmi_pcm *pcm; - - /* HDMI disabled, do not create controls */ - if (list_empty(&ctx->hdmi_pcm_list)) - return 0; - - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct skl_hda_hdmi_pcm, - head); - component = pcm->codec_dai->component; - if (!component) - return -EINVAL; - - return hda_dsp_hdmi_build_controls(card, component); -} - -#endif /* __SOUND_SOC_HDA_DSP_COMMON_H */ diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 6e172719c979..0554c7e2cb34 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -8,170 +8,23 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <sound/core.h> +#include <sound/hda_codec.h> #include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/soc-acpi.h> -#include "../../codecs/hdac_hdmi.h" -#include "skl_hda_dsp_common.h" - -static const struct snd_soc_dapm_widget skl_hda_widgets[] = { - SND_SOC_DAPM_HP("Analog Out", NULL), - SND_SOC_DAPM_MIC("Analog In", NULL), - SND_SOC_DAPM_HP("Alt Analog Out", NULL), - SND_SOC_DAPM_MIC("Alt Analog In", NULL), - SND_SOC_DAPM_SPK("Digital Out", NULL), - SND_SOC_DAPM_MIC("Digital In", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route skl_hda_map[] = { - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Analog Out", NULL, "Codec Output Pin1" }, - { "Digital Out", NULL, "Codec Output Pin2" }, - { "Alt Analog Out", NULL, "Codec Output Pin3" }, - - { "Codec Input Pin1", NULL, "Analog In" }, - { "Codec Input Pin2", NULL, "Digital In" }, - { "Codec Input Pin3", NULL, "Alt Analog In" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Analog Codec Playback", NULL, "Analog CPU Playback" }, - { "Analog CPU Playback", NULL, "codec0_out" }, - { "Digital Codec Playback", NULL, "Digital CPU Playback" }, - { "Digital CPU Playback", NULL, "codec1_out" }, - { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, - { "Alt Analog CPU Playback", NULL, "codec2_out" }, - - { "codec0_in", NULL, "Analog CPU Capture" }, - { "Analog CPU Capture", NULL, "Analog Codec Capture" }, - { "codec1_in", NULL, "Digital CPU Capture" }, - { "Digital CPU Capture", NULL, "Digital Codec Capture" }, - { "codec2_in", NULL, "Alt Analog CPU Capture" }, - { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, -}; +#include "../../codecs/hdac_hda.h" +#include "../../sof/intel/hda.h" +#include "sof_board_helpers.h" static int skl_hda_card_late_probe(struct snd_soc_card *card) { - return skl_hda_hdmi_jack_init(card); -} - -static int -skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) -{ - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - int ret = 0; - - dev_dbg(card->dev, "dai link name - %s\n", link->name); - link->platforms->name = ctx->platform_name; - link->nonatomic = 1; - - if (!ctx->idisp_codec) - return 0; - - if (strstr(link->name, "HDMI")) { - ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); - - if (ret < 0) - return ret; - - ctx->dai_index++; - } - - ctx->pcm_count++; - return ret; + return sof_intel_board_card_late_probe(card); } -static struct snd_soc_card hda_soc_card = { - .name = "hda-dsp", - .owner = THIS_MODULE, - .dai_link = skl_hda_be_dai_links, - .dapm_widgets = skl_hda_widgets, - .dapm_routes = skl_hda_map, - .add_dai_link = skl_hda_add_dai_link, - .fully_routed = true, - .late_probe = skl_hda_card_late_probe, -}; - -static char hda_soc_components[30]; - -#define IDISP_DAI_COUNT 3 -#define HDAC_DAI_COUNT 2 -#define DMIC_DAI_COUNT 2 - -/* there are two routes per iDisp output */ -#define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) -#define IDISP_CODEC_MASK 0x4 - #define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 -static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) -{ - struct snd_soc_card *card = &hda_soc_card; - struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai_link *dai_link; - u32 codec_count, codec_mask; - int i, num_links, num_route; - - codec_mask = mach_params->codec_mask; - codec_count = hweight_long(codec_mask); - ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK); - - if (!codec_count || codec_count > 2 || - (codec_count == 2 && !ctx->idisp_codec)) - return -EINVAL; - - if (codec_mask == IDISP_CODEC_MASK) { - /* topology with iDisp as the only HDA codec */ - num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT; - num_route = IDISP_ROUTE_COUNT; - - /* - * rearrange the dai link array and make the - * dmic dai links follow idsp dai links for only - * num_links of dai links need to be registered - * to ASoC. - */ - for (i = 0; i < DMIC_DAI_COUNT; i++) { - skl_hda_be_dai_links[IDISP_DAI_COUNT + i] = - skl_hda_be_dai_links[IDISP_DAI_COUNT + - HDAC_DAI_COUNT + i]; - } - } else { - /* topology with external and iDisp HDA codecs */ - num_links = ARRAY_SIZE(skl_hda_be_dai_links); - num_route = ARRAY_SIZE(skl_hda_map); - card->dapm_widgets = skl_hda_widgets; - card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); - if (!ctx->idisp_codec) { - card->dapm_routes = &skl_hda_map[IDISP_ROUTE_COUNT]; - num_route -= IDISP_ROUTE_COUNT; - for (i = 0; i < IDISP_DAI_COUNT; i++) { - skl_hda_be_dai_links[i].codecs = &snd_soc_dummy_dlc; - skl_hda_be_dai_links[i].num_codecs = 1; - } - } - } - - card->num_links = num_links; - card->num_dapm_routes = num_route; - - for_each_card_prelinks(card, i, dai_link) - dai_link->platforms->name = mach_params->platform; - - return 0; -} - static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) { struct snd_soc_pcm_runtime *rtd; @@ -195,48 +48,101 @@ static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) } } +#define IDISP_HDMI_BE_ID 1 +#define HDA_BE_ID 4 +#define DMIC01_BE_ID 6 +#define DMIC16K_BE_ID 7 +#define BT_OFFLOAD_BE_ID 8 + +#define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \ + SOF_LINK_HDA, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \ + HDA_BE_ID, \ + DMIC01_BE_ID, \ + DMIC16K_BE_ID, \ + BT_OFFLOAD_BE_ID, \ + 0, \ + 0) + +static unsigned long +skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) +{ + unsigned long board_quirk = 0; + int ssp_bt; + + if (hweight_long(mach_params->bt_link_mask) == 1) { + ssp_bt = fls(mach_params->bt_link_mask) - 1; + board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) | + SOF_BT_OFFLOAD_PRESENT; + } + + return board_quirk; +} + static int skl_hda_audio_probe(struct platform_device *pdev) { - struct snd_soc_acpi_mach *mach; - struct skl_hda_private *ctx; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct sof_card_private *ctx; + struct snd_soc_card *card; + unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params); int ret; - dev_dbg(&pdev->dev, "entry\n"); + card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->name = "hda-dsp"; + card->owner = THIS_MODULE; + card->fully_routed = true; + card->late_probe = skl_hda_card_late_probe; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); if (!ctx) return -ENOMEM; - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); + if (HDA_EXT_CODEC(mach->mach_params.codec_mask)) + ctx->hda_codec_present = true; - mach = pdev->dev.platform_data; - if (!mach) - return -EINVAL; + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; - snd_soc_card_set_drvdata(&hda_soc_card, ctx); + ctx->link_order_overwrite = HDA_LINK_ORDER; + ctx->link_id_overwrite = HDA_LINK_IDS; - ret = skl_hda_fill_card_info(&mach->mach_params); - if (ret < 0) { - dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); + /* update dai_link */ + ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx); + if (ret) return ret; - } - - ctx->pcm_count = hda_soc_card.num_links; - ctx->dai_index = 1; /* hdmi codec dai name starts from index 1 */ - ctx->platform_name = mach->mach_params.platform; - ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; - hda_soc_card.dev = &pdev->dev; + card->dev = &pdev->dev; if (mach->mach_params.dmic_num > 0) { - snprintf(hda_soc_components, sizeof(hda_soc_components), - "cfg-dmics:%d", mach->mach_params.dmic_num); - hda_soc_card.components = hda_soc_components; + card->components = devm_kasprintf(card->dev, GFP_KERNEL, + "cfg-dmics:%d", + mach->mach_params.dmic_num); + if (!card->components) + return -ENOMEM; } - ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); + ret = snd_soc_fixup_dai_links_platform_name(card, + mach->mach_params.platform); + if (ret) + return ret; + + snd_soc_card_set_drvdata(card, ctx); + + ret = devm_snd_soc_register_card(&pdev->dev, card); if (!ret) - skl_set_hda_codec_autosuspend_delay(&hda_soc_card); + skl_set_hda_codec_autosuspend_delay(card); return ret; } @@ -256,4 +162,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c deleted file mode 100644 index 0e7025834594..000000000000 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ /dev/null @@ -1,703 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver with MAXIM98357A - * and NAU88L25 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/jack.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_MAXIM_CODEC_DAI "HiFi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau8825_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - - return ret; -} - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Spk", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - { "Headphone Jack", NULL, "HPOL" }, - { "Headphone Jack", NULL, "HPOR" }, - - /* speaker */ - { "Spk", NULL, "Speaker" }, - - /* other jacks */ - { "MIC", NULL, "Headset Mic" }, - { "DMic", NULL, "SoC DMIC" }, - - /* CODEC BE connections */ - { "HiFi Playback", NULL, "ssp0 Tx" }, - { "ssp0 Tx", NULL, "codec0_out" }, - - { "Playback", NULL, "ssp1 Tx" }, - { "ssp1 Tx", NULL, "codec1_out" }, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - - return 0; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - - /* - * Headset buttons map to the google Reference headset. - * These can be configured by userspace. - */ - ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * On this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", SKL_MAXIM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", - SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .dpcm_playback = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau8825_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, - &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825max", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .fully_routed = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau8825_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_m98357a" }, - { .name = "kbl_n88l25_m98357a" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_m98357a", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); -MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c deleted file mode 100644 index fadc25a536b4..000000000000 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ /dev/null @@ -1,751 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567 - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/nau8825.h" -#include "../../codecs/hdac_hdmi.h" - -#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" -#define SKL_SSM_CODEC_DAI "ssm4567-hifi" -#define DMIC_CH(p) p->list[p->count-1] - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_card skylake_audio_card; -static const struct snd_pcm_hw_constraint_list *dmic_constraints; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_nau88125_private { - struct list_head hdmi_pcm_list; -}; -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Speaker"), - SOC_DAPM_PIN_SWITCH("Right Speaker"), -}; - -static int platform_clock_control(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct snd_soc_card *card = dapm->card; - struct snd_soc_dai *codec_dai; - int ret; - - codec_dai = snd_soc_card_get_codec_dai(card, SKL_NUVOTON_CODEC_DAI); - if (!codec_dai) { - dev_err(card->dev, "Codec dai not found\n"); - return -EIO; - } - - if (SND_SOC_DAPM_EVENT_ON(event)) { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); - if (ret < 0) { - dev_err(card->dev, "set sysclk err = %d\n", ret); - return -EIO; - } - } - return ret; -} - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Speaker", NULL), - SND_SOC_DAPM_SPK("Right Speaker", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("DP1", NULL), - SND_SOC_DAPM_SPK("DP2", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_PRE_PMU | - SND_SOC_DAPM_POST_PMD), -}; - -static struct snd_soc_jack_pin jack_pins[] = { - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const struct snd_soc_dapm_route skylake_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone Jack", NULL, "HPOL"}, - {"Headphone Jack", NULL, "HPOR"}, - - /* speaker */ - {"Left Speaker", NULL, "Left OUT"}, - {"Right Speaker", NULL, "Right OUT"}, - - /* other jacks */ - {"MIC", NULL, "Headset Mic"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "Left Playback", NULL, "ssp0 Tx"}, - { "Right Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - - /* IV feedback path */ - { "codec0_lp_in", NULL, "ssp0 Rx"}, - { "ssp0 Rx", NULL, "Left Capture Sense" }, - { "ssp0 Rx", NULL, "Right Capture Sense" }, - - { "Playback", NULL, "ssp1 Tx"}, - { "ssp1 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp1 Rx" }, - { "ssp1 Rx", NULL, "Capture" }, - - /* DMIC */ - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, -}; - -static struct snd_soc_codec_conf ssm4567_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:00"), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF("i2c-INT343B:01"), - .name_prefix = "Right", - }, -}; - -static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - - /* Slot 1 for left */ - ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 0), 0x01, 0x01, 2, 48); - if (ret < 0) - return ret; - - /* Slot 2 for right */ - ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_codec(rtd, 1), 0x02, 0x02, 2, 48); - if (ret < 0) - return ret; - - return ret; -} - -static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - int ret; - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - - /* - * 4 buttons here map to the google Reference headset - * The use of these buttons can be decided by the user space. - */ - ret = snd_soc_card_jack_new_pins(&skylake_audio_card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, - jack_pins, - ARRAY_SIZE(jack_pins)); - if (ret) { - dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); - return ret; - } - - nau8825_enable_jack_detect(component, &skylake_headset); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return ret; -} - -static int skylake_hdmi1_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_hdmi2_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI2_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - - -static int skylake_hdmi3_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI3_PB; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_nau8825_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The ADSP will convert the FE rate to 48k, stereo */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, - NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); - - if (ret < 0) - dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_nau8825_ops = { - .hw_params = skylake_nau8825_hw_params, -}; - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static const unsigned int dmic_2ch[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { - .count = ARRAY_SIZE(dmic_2ch), - .list = dmic_2ch, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = DMIC_CH(dmic_constraints); - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - dmic_constraints); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -static const unsigned int rates_16000[] = { - 16000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_16000 = { - .count = ARRAY_SIZE(rates_16000), - .list = rates_16000, -}; - -static const unsigned int ch_mono[] = { - 1, -}; - -static const struct snd_pcm_hw_constraint_list constraints_refcap = { - .count = ARRAY_SIZE(ch_mono), - .list = ch_mono, -}; - -static int skylake_refcap_startup(struct snd_pcm_substream *substream) -{ - substream->runtime->hw.channels_max = 1; - snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_refcap); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, - &constraints_16000); -} - -static const struct snd_soc_ops skylake_refcap_ops = { - .startup = skylake_refcap_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC("i2c-INT343B:00", SKL_SSM_CODEC_DAI), - /* Right */ COMP_CODEC("i2c-INT343B:01", SKL_SSM_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10508825:00", SKL_NUVOTON_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .dynamic = 1, - .nonatomic = 1, - .init = skylake_nau8825_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .dynamic = 1, - .nonatomic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_capture = 1, - .ops = &skylake_nau8825_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "Wake on Voice", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_refcap_ops, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .init = skylake_ssm4567_codec_init, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - /* SSP1 - Codec */ - .name = "SSP1-Codec", - .id = 1, - .no_pcm = 1, - .init = skylake_nau8825_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp_fixup, - .ops = &skylake_nau8825_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .dpcm_playback = 1, - .init = skylake_hdmi1_init, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = skylake_hdmi2_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = skylake_hdmi3_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_nau88125_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, - &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + NAU88L25 */ -static struct snd_soc_card skylake_audio_card = { - .name = "sklnau8825adi", - .owner = THIS_MODULE, - .dai_link = skylake_dais, - .num_links = ARRAY_SIZE(skylake_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_map, - .num_dapm_routes = ARRAY_SIZE(skylake_map), - .codec_conf = ssm4567_codec_conf, - .num_configs = ARRAY_SIZE(ssm4567_codec_conf), - .fully_routed = true, - .disable_route_checks = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_nau88125_private *ctx; - struct snd_soc_acpi_mach *mach; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_audio_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_audio_card, ctx); - - mach = pdev->dev.platform_data; - if (mach) - dmic_constraints = mach->mach_params.dmic_num == 2 ? - &constraints_dmic_2ch : &constraints_dmic_channels; - - return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_n88l25_s4567" }, - { .name = "kbl_n88l25_s4567" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_n88l25_s4567", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); -MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); -MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); -MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); -MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); -MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c deleted file mode 100644 index c59c60e28091..000000000000 --- a/sound/soc/intel/boards/skl_rt286.c +++ /dev/null @@ -1,567 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Skylake I2S Machine Driver - * - * Copyright (C) 2014-2015, Intel Corporation. All rights reserved. - * - * Modified from: - * Intel Broadwell Wildcatpoint SST Audio - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#include <linux/module.h> -#include <linux/platform_device.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/soc.h> -#include <sound/jack.h> -#include <sound/pcm_params.h> -#include "../../codecs/rt286.h" -#include "../../codecs/hdac_hdmi.h" - -static struct snd_soc_jack skylake_headset; -static struct snd_soc_jack skylake_hdmi[3]; - -struct skl_hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; - -struct skl_rt286_private { - struct list_head hdmi_pcm_list; -}; - -enum { - SKL_DPCM_AUDIO_PB = 0, - SKL_DPCM_AUDIO_DB_PB, - SKL_DPCM_AUDIO_CP, - SKL_DPCM_AUDIO_REF_CP, - SKL_DPCM_AUDIO_DMIC_CP, - SKL_DPCM_AUDIO_HDMI1_PB, - SKL_DPCM_AUDIO_HDMI2_PB, - SKL_DPCM_AUDIO_HDMI3_PB, -}; - -/* Headset jack detection DAPM pins */ -static struct snd_soc_jack_pin skylake_headset_pins[] = { - { - .pin = "Mic Jack", - .mask = SND_JACK_MICROPHONE, - }, - { - .pin = "Headphone Jack", - .mask = SND_JACK_HEADPHONE, - }, -}; - -static const struct snd_kcontrol_new skylake_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Mic Jack"), -}; - -static const struct snd_soc_dapm_widget skylake_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), - SND_SOC_DAPM_MIC("Mic Jack", NULL), - SND_SOC_DAPM_MIC("DMIC2", NULL), - SND_SOC_DAPM_MIC("SoC DMIC", NULL), - SND_SOC_DAPM_SPK("HDMI1", NULL), - SND_SOC_DAPM_SPK("HDMI2", NULL), - SND_SOC_DAPM_SPK("HDMI3", NULL), -}; - -static const struct snd_soc_dapm_route skylake_rt286_map[] = { - /* speaker */ - {"Speaker", NULL, "SPOR"}, - {"Speaker", NULL, "SPOL"}, - - /* HP jack connectors - unknown if we have jack deteck */ - {"Headphone Jack", NULL, "HPO Pin"}, - - /* other jacks */ - {"MIC1", NULL, "Mic Jack"}, - - /* digital mics */ - {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMic", NULL, "SoC DMIC"}, - - /* CODEC BE connections */ - { "AIF1 Playback", NULL, "ssp0 Tx"}, - { "ssp0 Tx", NULL, "codec0_out"}, - { "ssp0 Tx", NULL, "codec1_out"}, - - { "codec0_in", NULL, "ssp0 Rx" }, - { "codec1_in", NULL, "ssp0 Rx" }, - { "ssp0 Rx", NULL, "AIF1 Capture" }, - - { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "DMIC AIF" }, - - { "hifi3", NULL, "iDisp3 Tx"}, - { "iDisp3 Tx", NULL, "iDisp3_out"}, - { "hifi2", NULL, "iDisp2 Tx"}, - { "iDisp2 Tx", NULL, "iDisp2_out"}, - { "hifi1", NULL, "iDisp1 Tx"}, - { "iDisp1 Tx", NULL, "iDisp1_out"}, - -}; - -static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dapm_context *dapm; - struct snd_soc_component *component = snd_soc_rtd_to_cpu(rtd, 0)->component; - - dapm = snd_soc_component_get_dapm(component); - snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); - - return 0; -} - -static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - int ret; - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", - SND_JACK_HEADSET | SND_JACK_BTN_0, - &skylake_headset, - skylake_headset_pins, ARRAY_SIZE(skylake_headset_pins)); - - if (ret) - return ret; - - snd_soc_component_set_jack(component, &skylake_headset, NULL); - - snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); - - return 0; -} - -static int skylake_hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; - - pcm->device = SKL_DPCM_AUDIO_HDMI1_PB + dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); - - return 0; -} - -static const unsigned int rates[] = { - 48000, -}; - -static const struct snd_pcm_hw_constraint_list constraints_rates = { - .count = ARRAY_SIZE(rates), - .list = rates, - .mask = 0, -}; - -static const unsigned int channels[] = { - 2, -}; - -static const struct snd_pcm_hw_constraint_list constraints_channels = { - .count = ARRAY_SIZE(channels), - .list = channels, - .mask = 0, -}; - -static int skl_fe_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - /* - * on this platform for PCM device we support, - * 48Khz - * stereo - * 16 bit audio - */ - - runtime->hw.channels_max = 2; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); - - runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; - snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); - - snd_pcm_hw_constraint_list(runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); - - return 0; -} - -static const struct snd_soc_ops skylake_rt286_fe_ops = { - .startup = skl_fe_startup, -}; - -static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); - - /* The output is 48KHz, stereo, 16bits */ - rate->min = rate->max = 48000; - chan->min = chan->max = 2; - - /* set SSP0 to 24 bit */ - snd_mask_none(fmt); - snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); - return 0; -} - -static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int ret; - - ret = snd_soc_dai_set_sysclk(codec_dai, RT286_SCLK_S_PLL, 24000000, - SND_SOC_CLOCK_IN); - if (ret < 0) - dev_err(rtd->dev, "set codec sysclk failed: %d\n", ret); - - return ret; -} - -static const struct snd_soc_ops skylake_rt286_ops = { - .hw_params = skylake_rt286_hw_params, -}; - -static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *chan = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - if (params_channels(params) == 2) - chan->min = chan->max = 2; - else - chan->min = chan->max = 4; - - return 0; -} - -static const unsigned int channels_dmic[] = { - 2, 4, -}; - -static const struct snd_pcm_hw_constraint_list constraints_dmic_channels = { - .count = ARRAY_SIZE(channels_dmic), - .list = channels_dmic, - .mask = 0, -}; - -static int skylake_dmic_startup(struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - - runtime->hw.channels_max = 4; - snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_dmic_channels); - - return snd_pcm_hw_constraint_list(substream->runtime, 0, - SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -} - -static const struct snd_soc_ops skylake_dmic_ops = { - .startup = skylake_dmic_startup, -}; - -SND_SOC_DAILINK_DEF(dummy, - DAILINK_COMP_ARRAY(COMP_DUMMY())); - -SND_SOC_DAILINK_DEF(system, - DAILINK_COMP_ARRAY(COMP_CPU("System Pin"))); - -SND_SOC_DAILINK_DEF(deepbuffer, - DAILINK_COMP_ARRAY(COMP_CPU("Deepbuffer Pin"))); - -SND_SOC_DAILINK_DEF(reference, - DAILINK_COMP_ARRAY(COMP_CPU("Reference Pin"))); - -SND_SOC_DAILINK_DEF(dmic, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC Pin"))); - -SND_SOC_DAILINK_DEF(hdmi1, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI1 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi2, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI2 Pin"))); - -SND_SOC_DAILINK_DEF(hdmi3, - DAILINK_COMP_ARRAY(COMP_CPU("HDMI3 Pin"))); - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-INT343A:00", "rt286-aif1"))); - -SND_SOC_DAILINK_DEF(dmic01_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(platform, - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -/* skylake digital audio interface glue - connects codec <--> CPU */ -static struct snd_soc_dai_link skylake_rt286_dais[] = { - /* Front End DAI links */ - [SKL_DPCM_AUDIO_PB] = { - .name = "Skl Audio Port", - .stream_name = "Audio", - .nonatomic = 1, - .dynamic = 1, - .init = skylake_rt286_fe_init, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_DB_PB] = { - .name = "Skl Deepbuffer Port", - .stream_name = "Deep Buffer Audio", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_playback = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), - }, - [SKL_DPCM_AUDIO_CP] = { - .name = "Skl Audio Capture Port", - .stream_name = "Audio Record", - .nonatomic = 1, - .dynamic = 1, - .trigger = { - SND_SOC_DPCM_TRIGGER_POST, - SND_SOC_DPCM_TRIGGER_POST - }, - .dpcm_capture = 1, - .ops = &skylake_rt286_fe_ops, - SND_SOC_DAILINK_REG(system, dummy, platform), - }, - [SKL_DPCM_AUDIO_REF_CP] = { - .name = "Skl Audio Reference cap", - .stream_name = "refcap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(reference, dummy, platform), - }, - [SKL_DPCM_AUDIO_DMIC_CP] = { - .name = "Skl Audio DMIC cap", - .stream_name = "dmiccap", - .init = NULL, - .dpcm_capture = 1, - .nonatomic = 1, - .dynamic = 1, - .ops = &skylake_dmic_ops, - SND_SOC_DAILINK_REG(dmic, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI1_PB] = { - .name = "Skl HDMI Port1", - .stream_name = "Hdmi1", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi1, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI2_PB] = { - .name = "Skl HDMI Port2", - .stream_name = "Hdmi2", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi2, dummy, platform), - }, - [SKL_DPCM_AUDIO_HDMI3_PB] = { - .name = "Skl HDMI Port3", - .stream_name = "Hdmi3", - .dpcm_playback = 1, - .init = NULL, - .nonatomic = 1, - .dynamic = 1, - SND_SOC_DAILINK_REG(hdmi3, dummy, platform), - }, - - /* Back End DAI links */ - { - /* SSP0 - Codec */ - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = skylake_rt286_codec_init, - .dai_fmt = SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBC_CFC, - .ignore_pmdown_time = 1, - .be_hw_params_fixup = skylake_ssp0_fixup, - .ops = &skylake_rt286_ops, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .be_hw_params_fixup = skylake_dmic_fixup, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic01_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 2, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 3, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 4, - .init = skylake_hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, -}; - -#define NAME_SIZE 32 -static int skylake_card_late_probe(struct snd_soc_card *card) -{ - struct skl_rt286_private *ctx = snd_soc_card_get_drvdata(card); - struct skl_hdmi_pcm *pcm; - struct snd_soc_component *component = NULL; - int err, i = 0; - char jack_name[NAME_SIZE]; - - list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { - component = pcm->codec_dai->component; - snprintf(jack_name, sizeof(jack_name), - "HDMI/DP, pcm=%d Jack", pcm->device); - err = snd_soc_card_jack_new(card, jack_name, - SND_JACK_AVOUT, &skylake_hdmi[i]); - - if (err) - return err; - - err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, - &skylake_hdmi[i]); - if (err < 0) - return err; - - i++; - } - - if (!component) - return -EINVAL; - - return hdac_hdmi_jack_port_init(component, &card->dapm); -} - -/* skylake audio machine driver for SPT + RT286S */ -static struct snd_soc_card skylake_rt286 = { - .name = "skylake-rt286", - .owner = THIS_MODULE, - .dai_link = skylake_rt286_dais, - .num_links = ARRAY_SIZE(skylake_rt286_dais), - .controls = skylake_controls, - .num_controls = ARRAY_SIZE(skylake_controls), - .dapm_widgets = skylake_widgets, - .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), - .dapm_routes = skylake_rt286_map, - .num_dapm_routes = ARRAY_SIZE(skylake_rt286_map), - .fully_routed = true, - .late_probe = skylake_card_late_probe, -}; - -static int skylake_audio_probe(struct platform_device *pdev) -{ - struct skl_rt286_private *ctx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - - skylake_rt286.dev = &pdev->dev; - snd_soc_card_set_drvdata(&skylake_rt286, ctx); - - return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); -} - -static const struct platform_device_id skl_board_ids[] = { - { .name = "skl_alc286s_i2s" }, - { .name = "kbl_alc286s_i2s" }, - { } -}; -MODULE_DEVICE_TABLE(platform, skl_board_ids); - -static struct platform_driver skylake_audio = { - .probe = skylake_audio_probe, - .driver = { - .name = "skl_alc286s_i2s", - .pm = &snd_soc_pm_ops, - }, - .id_table = skl_board_ids, - -}; - -module_platform_driver(skylake_audio) - -/* Module information */ -MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); -MODULE_DESCRIPTION("Intel SST Audio for Skylake"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/boards/sof_board_helpers.c b/sound/soc/intel/boards/sof_board_helpers.c index 088894ff4165..2ea1dda446ec 100644 --- a/sound/soc/intel/boards/sof_board_helpers.c +++ b/sound/soc/intel/boards/sof_board_helpers.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2023 Intel Corporation. All rights reserved. +// Copyright(c) 2023 Intel Corporation #include <sound/soc.h> #include "../common/soc-intel-quirks.h" @@ -35,7 +35,7 @@ int sof_intel_board_card_late_probe(struct snd_soc_card *card) return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); } -EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); /* * DMIC DAI Link @@ -71,9 +71,77 @@ static int dmic_init(struct snd_soc_pcm_runtime *rtd) } /* + * HDA External Codec DAI Link + */ +static const struct snd_soc_dapm_widget hda_widgets[] = { + SND_SOC_DAPM_MIC("Analog In", NULL), + SND_SOC_DAPM_MIC("Digital In", NULL), + SND_SOC_DAPM_MIC("Alt Analog In", NULL), + + SND_SOC_DAPM_HP("Analog Out", NULL), + SND_SOC_DAPM_SPK("Digital Out", NULL), + SND_SOC_DAPM_HP("Alt Analog Out", NULL), +}; + +static const struct snd_soc_dapm_route hda_routes[] = { + { "Codec Input Pin1", NULL, "Analog In" }, + { "Codec Input Pin2", NULL, "Digital In" }, + { "Codec Input Pin3", NULL, "Alt Analog In" }, + + { "Analog Out", NULL, "Codec Output Pin1" }, + { "Digital Out", NULL, "Codec Output Pin2" }, + { "Alt Analog Out", NULL, "Codec Output Pin3" }, + + /* CODEC BE connections */ + { "codec0_in", NULL, "Analog CPU Capture" }, + { "Analog CPU Capture", NULL, "Analog Codec Capture" }, + { "codec1_in", NULL, "Digital CPU Capture" }, + { "Digital CPU Capture", NULL, "Digital Codec Capture" }, + { "codec2_in", NULL, "Alt Analog CPU Capture" }, + { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, + + { "Analog Codec Playback", NULL, "Analog CPU Playback" }, + { "Analog CPU Playback", NULL, "codec0_out" }, + { "Digital Codec Playback", NULL, "Digital CPU Playback" }, + { "Digital CPU Playback", NULL, "codec1_out" }, + { "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" }, + { "Alt Analog CPU Playback", NULL, "codec2_out" }, +}; + +static int hda_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + int ret; + + ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets, + ARRAY_SIZE(hda_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes, + ARRAY_SIZE(hda_routes)); + if (ret) + dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret); + + return ret; +} + +/* * DAI Link Helpers */ +enum sof_dmic_be_type { + SOF_DMIC_01, + SOF_DMIC_16K, +}; + +enum sof_hda_be_type { + SOF_HDA_ANALOG, + SOF_HDA_DIGITAL, +}; + /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */ #define DEFAULT_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_CODEC, \ SOF_LINK_DMIC01, \ @@ -90,6 +158,16 @@ static struct snd_soc_dai_link_component dmic_component[] = { } }; +SND_SOC_DAILINK_DEF(hda_analog_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_analog_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI"))); + +SND_SOC_DAILINK_DEF(hda_digital_cpus, + DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI"))); +SND_SOC_DAILINK_DEF(hda_digital_codecs, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI"))); + static struct snd_soc_dai_link_component platform_component[] = { { /* name might be overridden during probe */ @@ -97,14 +175,14 @@ static struct snd_soc_dai_link_component platform_component[] = { } }; -int sof_intel_board_set_codec_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec codec_type, int ssp_codec) +static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum snd_soc_acpi_intel_codec codec_type, + int ssp_codec) { struct snd_soc_dai_link_component *cpus; - dev_dbg(dev, "link %d: codec %s, ssp %d\n", be_id, - sof_ssp_get_codec_name(codec_type), ssp_codec); + dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id, + snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec); /* link name */ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec); @@ -139,16 +217,12 @@ int sof_intel_board_set_codec_link(struct device *dev, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_codec_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_dmic_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_dmic_be_type be_type) +static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum sof_dmic_be_type be_type) { struct snd_soc_dai_link_component *cpus; @@ -192,20 +266,18 @@ int sof_intel_board_set_dmic_link(struct device *dev, link->init = dmic_init; link->ignore_suspend = 1; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_dmic_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_intel_hdmi_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int hdmi_id, bool idisp_codec) +static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int hdmi_id, bool idisp_codec) { struct snd_soc_dai_link_component *cpus, *codecs; - dev_dbg(dev, "link %d: intel hdmi, hdmi id %d, idisp codec %d\n", - be_id, hdmi_id, idisp_codec); + dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id, + idisp_codec); /* link name */ link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id); @@ -252,20 +324,19 @@ int sof_intel_board_set_intel_hdmi_link(struct device *dev, link->id = be_id; link->init = (hdmi_id == 1) ? hdmi_init : NULL; link->no_pcm = 1; - link->dpcm_playback = 1; + link->playback_only = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_intel_hdmi_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_ssp_amp_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec amp_type, int ssp_amp) +static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum snd_soc_acpi_intel_codec amp_type, + int ssp_amp) { struct snd_soc_dai_link_component *cpus; dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id, - sof_ssp_get_codec_name(amp_type), ssp_amp); + snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp); /* link name */ link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp); @@ -288,21 +359,18 @@ int sof_intel_board_set_ssp_amp_link(struct device *dev, /* codecs - caller to handle */ /* platforms */ + /* feedback stream or firmware-generated echo reference */ link->platforms = platform_component; link->num_platforms = ARRAY_SIZE(platform_component); link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */ - link->dpcm_playback = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_ssp_amp_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_bt_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_bt) +static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int ssp_bt) { struct snd_soc_dai_link_component *cpus; @@ -336,16 +404,12 @@ int sof_intel_board_set_bt_link(struct device *dev, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; - link->dpcm_playback = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_bt_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); -int sof_intel_board_set_hdmi_in_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_hdmi) +static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, int ssp_hdmi) { struct snd_soc_dai_link_component *cpus; @@ -379,11 +443,57 @@ int sof_intel_board_set_hdmi_in_link(struct device *dev, link->id = be_id; link->no_pcm = 1; - link->dpcm_capture = 1; + link->capture_only = 1; + + return 0; +} + +static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link, + int be_id, enum sof_hda_be_type be_type) +{ + switch (be_type) { + case SOF_HDA_ANALOG: + dev_dbg(dev, "link %d: hda analog\n", be_id); + + link->name = "Analog Playback and Capture"; + + /* cpus */ + link->cpus = hda_analog_cpus; + link->num_cpus = ARRAY_SIZE(hda_analog_cpus); + + /* codecs */ + link->codecs = hda_analog_codecs; + link->num_codecs = ARRAY_SIZE(hda_analog_codecs); + break; + case SOF_HDA_DIGITAL: + dev_dbg(dev, "link %d: hda digital\n", be_id); + + link->name = "Digital Playback and Capture"; + + /* cpus */ + link->cpus = hda_digital_cpus; + link->num_cpus = ARRAY_SIZE(hda_digital_cpus); + + /* codecs */ + link->codecs = hda_digital_codecs; + link->num_codecs = ARRAY_SIZE(hda_digital_codecs); + break; + default: + dev_err(dev, "invalid be type %d\n", be_type); + return -EINVAL; + } + + /* platforms */ + link->platforms = platform_component; + link->num_platforms = ARRAY_SIZE(platform_component); + + link->id = be_id; + if (be_type == SOF_HDA_ANALOG) + link->init = hda_init; + link->no_pcm = 1; return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_hdmi_in_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); static int calculate_num_links(struct sof_card_private *ctx) { @@ -414,6 +524,10 @@ static int calculate_num_links(struct sof_card_private *ctx) /* HDMI-In */ num_links += hweight32(ctx->ssp_mask_hdmi_in); + /* HDA external codec */ + if (ctx->hda_codec_present) + num_links += 2; + return num_links; } @@ -427,6 +541,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, int ret; int ssp_hdmi_in = 0; unsigned long link_order, link; + unsigned long link_ids, be_id; num_links = calculate_num_links(ctx); @@ -440,22 +555,34 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, else link_order = DEFAULT_LINK_ORDER; - dev_dbg(dev, "create dai links, link_order 0x%lx\n", link_order); + if (ctx->link_id_overwrite) + link_ids = ctx->link_id_overwrite; + else + link_ids = 0; + + dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n", + link_order, link_ids); while (link_order) { link = link_order & SOF_LINK_ORDER_MASK; link_order >>= SOF_LINK_ORDER_SHIFT; + if (ctx->link_id_overwrite) { + be_id = link_ids & SOF_LINK_IDS_MASK; + link_ids >>= SOF_LINK_IDS_SHIFT; + } else { + /* use array index as link id */ + be_id = idx; + } + switch (link) { case SOF_LINK_CODEC: /* headphone codec */ if (ctx->codec_type == CODEC_NONE) continue; - ret = sof_intel_board_set_codec_link(dev, &links[idx], - idx, - ctx->codec_type, - ctx->ssp_codec); + ret = set_ssp_codec_link(dev, &links[idx], be_id, + ctx->codec_type, ctx->ssp_codec); if (ret) { dev_err(dev, "fail to set codec link, ret %d\n", ret); @@ -471,8 +598,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, continue; /* at least we have dmic01 */ - ret = sof_intel_board_set_dmic_link(dev, &links[idx], - idx, SOF_DMIC_01); + ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01); if (ret) { dev_err(dev, "fail to set dmic01 link, ret %d\n", ret); @@ -487,8 +613,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, continue; /* set up 2 BE links at most */ - ret = sof_intel_board_set_dmic_link(dev, &links[idx], - idx, SOF_DMIC_16K); + ret = set_dmic_link(dev, &links[idx], be_id, + SOF_DMIC_16K); if (ret) { dev_err(dev, "fail to set dmic16k link, ret %d\n", ret); @@ -500,10 +626,9 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, case SOF_LINK_IDISP_HDMI: /* idisp HDMI */ for (i = 1; i <= ctx->hdmi_num; i++) { - ret = sof_intel_board_set_intel_hdmi_link(dev, - &links[idx], - idx, i, - ctx->hdmi.idisp_codec); + ret = set_idisp_hdmi_link(dev, &links[idx], + be_id, i, + ctx->hdmi.idisp_codec); if (ret) { dev_err(dev, "fail to set hdmi link, ret %d\n", ret); @@ -511,6 +636,7 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, } idx++; + be_id++; } break; case SOF_LINK_AMP: @@ -518,10 +644,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, if (ctx->amp_type == CODEC_NONE) continue; - ret = sof_intel_board_set_ssp_amp_link(dev, &links[idx], - idx, - ctx->amp_type, - ctx->ssp_amp); + ret = set_ssp_amp_link(dev, &links[idx], be_id, + ctx->amp_type, ctx->ssp_amp); if (ret) { dev_err(dev, "fail to set amp link, ret %d\n", ret); @@ -536,8 +660,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, if (!ctx->bt_offload_present) continue; - ret = sof_intel_board_set_bt_link(dev, &links[idx], idx, - ctx->ssp_bt); + ret = set_bt_offload_link(dev, &links[idx], be_id, + ctx->ssp_bt); if (ret) { dev_err(dev, "fail to set bt link, ret %d\n", ret); @@ -549,10 +673,8 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, case SOF_LINK_HDMI_IN: /* HDMI-In */ for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) { - ret = sof_intel_board_set_hdmi_in_link(dev, - &links[idx], - idx, - ssp_hdmi_in); + ret = set_hdmi_in_link(dev, &links[idx], be_id, + ssp_hdmi_in); if (ret) { dev_err(dev, "fail to set hdmi-in link, ret %d\n", ret); @@ -560,8 +682,35 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, } idx++; + be_id++; } break; + case SOF_LINK_HDA: + /* HDA external codec */ + if (!ctx->hda_codec_present) + continue; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_ANALOG); + if (ret) { + dev_err(dev, "fail to set hda analog link, ret %d\n", + ret); + return ret; + } + + idx++; + be_id++; + + ret = set_hda_codec_link(dev, &links[idx], be_id, + SOF_HDA_DIGITAL); + if (ret) { + dev_err(dev, "fail to set hda digital link, ret %d\n", + ret); + return ret; + } + + idx++; + break; case SOF_LINK_NONE: /* caught here if it's not used as terminator in macro */ fallthrough; @@ -582,28 +731,53 @@ int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], int num_dais) +struct sof_card_private * +sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk) { - struct snd_soc_dai *dai; - int index; - int i; + struct sof_card_private *ctx; - for (index = 0; index < num_dais; index++) - for_each_rtd_codec_dais(rtd, i, dai) - if (strstr(dai->name, dai_name[index])) { - dev_dbg(rtd->card->dev, "get dai %s\n", dai->name); - return dai; - } + dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk); + + ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL); + if (!ctx) + return NULL; + + ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev); + ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev); + + ctx->dmic_be_num = 2; + ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >> + SOF_NUM_IDISP_HDMI_SHIFT; + /* default number of HDMI DAI's */ + if (!ctx->hdmi_num) + ctx->hdmi_num = 3; + + /* port number/mask of peripherals attached to ssp interface */ + if (ctx->codec_type != CODEC_NONE) + ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >> + SOF_SSP_PORT_CODEC_SHIFT; + + if (ctx->amp_type != CODEC_NONE) + ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >> + SOF_SSP_PORT_AMP_SHIFT; + + if (board_quirk & SOF_BT_OFFLOAD_PRESENT) { + ctx->bt_offload_present = true; + ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >> + SOF_SSP_PORT_BT_OFFLOAD_SHIFT; + } + + ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >> + SOF_SSP_MASK_HDMI_CAPTURE_SHIFT; - return NULL; + return ctx; } -EXPORT_SYMBOL_NS(get_codec_dai_by_name, SND_SOC_INTEL_SOF_BOARD_HELPERS); +EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS"); MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH"); diff --git a/sound/soc/intel/boards/sof_board_helpers.h b/sound/soc/intel/boards/sof_board_helpers.h index f42d5d640321..33a9601b770c 100644 --- a/sound/soc/intel/boards/sof_board_helpers.h +++ b/sound/soc/intel/boards/sof_board_helpers.h @@ -7,8 +7,46 @@ #define __SOF_INTEL_BOARD_HELPERS_H #include <sound/soc.h> +#include <sound/soc-acpi-intel-ssp-common.h> #include "sof_hdmi_common.h" -#include "sof_ssp_common.h" + +/* + * Common board quirks: from bit 8 to 31, LSB 8 bits reserved for machine + * drivers + */ + +/* SSP port number for headphone codec: 3 bits */ +#define SOF_SSP_PORT_CODEC_SHIFT 8 +#define SOF_SSP_PORT_CODEC_MASK (GENMASK(10, 8)) +#define SOF_SSP_PORT_CODEC(quirk) \ + (((quirk) << SOF_SSP_PORT_CODEC_SHIFT) & SOF_SSP_PORT_CODEC_MASK) + +/* SSP port number for speaker amplifier: 3 bits */ +#define SOF_SSP_PORT_AMP_SHIFT 11 +#define SOF_SSP_PORT_AMP_MASK (GENMASK(13, 11)) +#define SOF_SSP_PORT_AMP(quirk) \ + (((quirk) << SOF_SSP_PORT_AMP_SHIFT) & SOF_SSP_PORT_AMP_MASK) + +/* SSP port number for BT audio offload: 3 bits */ +#define SOF_SSP_PORT_BT_OFFLOAD_SHIFT 14 +#define SOF_SSP_PORT_BT_OFFLOAD_MASK (GENMASK(16, 14)) +#define SOF_SSP_PORT_BT_OFFLOAD(quirk) \ + (((quirk) << SOF_SSP_PORT_BT_OFFLOAD_SHIFT) & SOF_SSP_PORT_BT_OFFLOAD_MASK) + +/* SSP port mask for HDMI capture: 6 bits */ +#define SOF_SSP_MASK_HDMI_CAPTURE_SHIFT 17 +#define SOF_SSP_MASK_HDMI_CAPTURE_MASK (GENMASK(22, 17)) +#define SOF_SSP_MASK_HDMI_CAPTURE(quirk) \ + (((quirk) << SOF_SSP_MASK_HDMI_CAPTURE_SHIFT) & SOF_SSP_MASK_HDMI_CAPTURE_MASK) + +/* Number of idisp HDMI BE link: 3 bits */ +#define SOF_NUM_IDISP_HDMI_SHIFT 23 +#define SOF_NUM_IDISP_HDMI_MASK (GENMASK(25, 23)) +#define SOF_NUM_IDISP_HDMI(quirk) \ + (((quirk) << SOF_NUM_IDISP_HDMI_SHIFT) & SOF_NUM_IDISP_HDMI_MASK) + +/* Board uses BT audio offload */ +#define SOF_BT_OFFLOAD_PRESENT BIT(26) enum { SOF_LINK_NONE = 0, @@ -19,6 +57,7 @@ enum { SOF_LINK_AMP, SOF_LINK_BT_OFFLOAD, SOF_LINK_HDMI_IN, + SOF_LINK_HDA, }; #define SOF_LINK_ORDER_MASK (0xF) @@ -33,15 +72,40 @@ enum { (((k6) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 5)) | \ (((k7) & SOF_LINK_ORDER_MASK) << (SOF_LINK_ORDER_SHIFT * 6))) +#define SOF_LINK_IDS_MASK (0xF) +#define SOF_LINK_IDS_SHIFT (4) + +#define SOF_LINK_IDS(k1, k2, k3, k4, k5, k6, k7) \ + ((((k1) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 0)) | \ + (((k2) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 1)) | \ + (((k3) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 2)) | \ + (((k4) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 3)) | \ + (((k5) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 4)) | \ + (((k6) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 5)) | \ + (((k7) & SOF_LINK_IDS_MASK) << (SOF_LINK_IDS_SHIFT * 6))) + +/* + * sof_da7219_private: private data for da7219 machine driver + * + * @mclk_en: true for mclk pin is connected + * @pll_bypass: true for PLL bypass mode + */ +struct sof_da7219_private { + bool mclk_en; + bool pll_bypass; +}; + /* * sof_rt5682_private: private data for rt5682 machine driver * * @mclk: mclk clock data * @is_legacy_cpu: true for BYT/CHT boards + * @mclk_en: true for mclk pin is connected */ struct sof_rt5682_private { struct clk *mclk; bool is_legacy_cpu; + bool mclk_en; }; /* @@ -58,17 +122,20 @@ struct sof_rt5682_private { * @ssp_bt: ssp port number of BT offload BE link * @ssp_mask_hdmi_in: ssp port mask of HDMI-IN BE link * @bt_offload_present: true to create BT offload BE link + * @hda_codec_present: true to create HDA codec BE links * @codec_link: pointer to headset codec dai link * @amp_link: pointer to speaker amplifier dai link * @link_order_overwrite: custom DAI link order + * @link_id_overwrite: custom DAI link ID + * @da7219: private data for da7219 machine driver * @rt5682: private data for rt5682 machine driver */ struct sof_card_private { struct snd_soc_jack headset_jack; struct sof_hdmi_private hdmi; - enum sof_ssp_codec codec_type; - enum sof_ssp_codec amp_type; + enum snd_soc_acpi_intel_codec codec_type; + enum snd_soc_acpi_intel_codec amp_type; int dmic_be_num; int hdmi_num; @@ -79,46 +146,28 @@ struct sof_card_private { unsigned long ssp_mask_hdmi_in; bool bt_offload_present; + bool hda_codec_present; struct snd_soc_dai_link *codec_link; struct snd_soc_dai_link *amp_link; unsigned long link_order_overwrite; + /* + * A variable stores id for all BE DAI links, use SOF_LINK_IDS macro to + * build the value; use DAI link array index as id if zero. + */ + unsigned long link_id_overwrite; union { + struct sof_da7219_private da7219; struct sof_rt5682_private rt5682; }; }; -enum sof_dmic_be_type { - SOF_DMIC_01, - SOF_DMIC_16K, -}; - int sof_intel_board_card_late_probe(struct snd_soc_card *card); int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card, struct sof_card_private *ctx); - -int sof_intel_board_set_codec_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec codec_type, int ssp_codec); -int sof_intel_board_set_dmic_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_dmic_be_type be_type); -int sof_intel_board_set_intel_hdmi_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int hdmi_id, bool idisp_codec); -int sof_intel_board_set_ssp_amp_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - enum sof_ssp_codec amp_type, int ssp_amp); -int sof_intel_board_set_bt_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_bt); -int sof_intel_board_set_hdmi_in_link(struct device *dev, - struct snd_soc_dai_link *link, int be_id, - int ssp_hdmi); - -struct snd_soc_dai *get_codec_dai_by_name(struct snd_soc_pcm_runtime *rtd, - const char * const dai_name[], int num_dais); +struct sof_card_private * +sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk); #endif /* __SOF_INTEL_BOARD_HELPERS_H */ diff --git a/sound/soc/intel/boards/sof_cirrus_common.c b/sound/soc/intel/boards/sof_cirrus_common.c index e71e09124b34..8db7695b9747 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.c +++ b/sound/soc/intel/boards/sof_cirrus_common.c @@ -193,14 +193,14 @@ void cs35l41_set_dai_link(struct snd_soc_dai_link *link) link->init = cs35l41_init; link->ops = &cs35l41_ops; } -EXPORT_SYMBOL_NS(cs35l41_set_dai_link, SND_SOC_INTEL_SOF_CIRRUS_COMMON); +EXPORT_SYMBOL_NS(cs35l41_set_dai_link, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); void cs35l41_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = cs35l41_codec_conf; card->num_configs = ARRAY_SIZE(cs35l41_codec_conf); } -EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, SND_SOC_INTEL_SOF_CIRRUS_COMMON); +EXPORT_SYMBOL_NS(cs35l41_set_codec_conf, "SND_SOC_INTEL_SOF_CIRRUS_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Cirrus Logic helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_cirrus_common.h b/sound/soc/intel/boards/sof_cirrus_common.h index d4ecf8d023d1..1c87637b9ef7 100644 --- a/sound/soc/intel/boards/sof_cirrus_common.h +++ b/sound/soc/intel/boards/sof_cirrus_common.h @@ -9,7 +9,7 @@ #define __SOF_CIRRUS_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Cirrus Logic CS35L41/CS35L53 diff --git a/sound/soc/intel/boards/sof_cs42l42.c b/sound/soc/intel/boards/sof_cs42l42.c index 323b86c42ef9..455c5bc8c634 100644 --- a/sound/soc/intel/boards/sof_cs42l42.c +++ b/sound/soc/intel/boards/sof_cs42l42.c @@ -22,23 +22,6 @@ #include "../common/soc-intel-quirks.h" #include "sof_board_helpers.h" #include "sof_maxim_common.h" -#include "sof_ssp_common.h" - -#define SOF_CS42L42_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_CS42L42_SSP_CODEC_MASK (GENMASK(2, 0)) -#define SOF_CS42L42_SSP_AMP_SHIFT 4 -#define SOF_CS42L42_SSP_AMP_MASK (GENMASK(6, 4)) -#define SOF_CS42L42_SSP_AMP(quirk) \ - (((quirk) << SOF_CS42L42_SSP_AMP_SHIFT) & SOF_CS42L42_SSP_AMP_MASK) -#define SOF_CS42L42_NUM_HDMIDEV_SHIFT 7 -#define SOF_CS42L42_NUM_HDMIDEV_MASK (GENMASK(9, 7)) -#define SOF_CS42L42_NUM_HDMIDEV(quirk) \ - (((quirk) << SOF_CS42L42_NUM_HDMIDEV_SHIFT) & SOF_CS42L42_NUM_HDMIDEV_MASK) -#define SOF_BT_OFFLOAD_PRESENT BIT(25) -#define SOF_CS42L42_SSP_BT_SHIFT 26 -#define SOF_CS42L42_SSP_BT_MASK (GENMASK(28, 26)) -#define SOF_CS42L42_SSP_BT(quirk) \ - (((quirk) << SOF_CS42L42_SSP_BT_SHIFT) & SOF_CS42L42_SSP_BT_MASK) static struct snd_soc_jack_pin jack_pins[] = { { @@ -52,7 +35,7 @@ static struct snd_soc_jack_pin jack_pins[] = { }; /* Default: SSP2 */ -static unsigned long sof_cs42l42_quirk = SOF_CS42L42_SSP_CODEC(2); +static unsigned long sof_cs42l42_quirk = SOF_SSP_PORT_CODEC(2); static int sof_cs42l42_init(struct snd_soc_pcm_runtime *rtd) { @@ -229,48 +212,26 @@ static int sof_audio_probe(struct platform_device *pdev) struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_cs42l42_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_cs42l42_quirk); + if (!ctx) + return -ENOMEM; if (soc_intel_is_glk()) { ctx->dmic_be_num = 1; - ctx->hdmi_num = 3; /* overwrite the DAI link order for GLK boards */ ctx->link_order_overwrite = GLK_LINK_ORDER; - } else { - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_cs42l42_quirk & SOF_CS42L42_NUM_HDMIDEV_MASK) >> - SOF_CS42L42_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; } if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - dev_dbg(&pdev->dev, "sof_cs42l42_quirk = %lx\n", sof_cs42l42_quirk); - - /* port number of peripherals attached to ssp interface */ - ctx->ssp_bt = (sof_cs42l42_quirk & SOF_CS42L42_SSP_BT_MASK) >> - SOF_CS42L42_SSP_BT_SHIFT; - - ctx->ssp_amp = (sof_cs42l42_quirk & SOF_CS42L42_SSP_AMP_MASK) >> - SOF_CS42L42_SSP_AMP_SHIFT; - - ctx->ssp_codec = sof_cs42l42_quirk & SOF_CS42L42_SSP_CODEC_MASK; - - if (sof_cs42l42_quirk & SOF_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; - /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_cs42l42, ctx); if (ret) @@ -293,21 +254,36 @@ static int sof_audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { .name = "glk_cs4242_mx98357a", - .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(2) | - SOF_CS42L42_SSP_AMP(1)), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), }, { .name = "jsl_cs4242_mx98360a", - .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) | - SOF_CS42L42_SSP_AMP(1)), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "adl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(2)), + }, + { + .name = "rpl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(2)), }, { - .name = "adl_mx98360a_cs4242", - .driver_data = (kernel_ulong_t)(SOF_CS42L42_SSP_CODEC(0) | - SOF_CS42L42_SSP_AMP(1) | - SOF_CS42L42_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_PRESENT | - SOF_CS42L42_SSP_BT(2)), + .name = "mtl_cs42l42_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_BT_OFFLOAD_PRESENT | + SOF_SSP_PORT_BT_OFFLOAD(1)), }, { } }; @@ -327,6 +303,5 @@ module_platform_driver(sof_audio) MODULE_DESCRIPTION("SOF Audio Machine driver for CS42L42"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_da7219.c b/sound/soc/intel/boards/sof_da7219.c index 6eb5a6144e97..9b7082b239c1 100644 --- a/sound/soc/intel/boards/sof_da7219.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -15,35 +15,27 @@ #include <sound/soc-acpi.h> #include <sound/sof.h> #include "../../codecs/da7219.h" -#include "hda_dsp_common.h" -#include "sof_hdmi_common.h" +#include "sof_board_helpers.h" #include "sof_maxim_common.h" -#include "sof_ssp_common.h" -/* Board Quirks */ +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_DA7219_GLK_BOARD BIT(0) +#define SOF_DA7219_CML_BOARD BIT(1) #define SOF_DA7219_JSL_BOARD BIT(2) +#define SOF_DA7219_MCLK_EN BIT(3) #define DIALOG_CODEC_DAI "da7219-hifi" -struct card_private { - struct snd_soc_jack headset_jack; - struct sof_hdmi_private hdmi; - enum sof_ssp_codec codec_type; - enum sof_ssp_codec amp_type; - - unsigned int pll_bypass:1; -}; - static int platform_clock_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *k, int event) { struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; - struct card_private *ctx = snd_soc_card_get_drvdata(card); + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai *codec_dai; int ret = 0; - if (ctx->pll_bypass) + if (ctx->da7219.pll_bypass) return ret; /* PLL SRM mode */ @@ -74,8 +66,6 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), SOC_DAPM_PIN_SWITCH("Line Out"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), }; static const struct snd_soc_dapm_widget widgets[] = { @@ -83,14 +73,9 @@ static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_MIC("Headset Mic", NULL), SND_SOC_DAPM_LINE("Line Out", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, platform_clock_control, SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), - - SND_SOC_DAPM_MIC("SoC DMIC", NULL), }; static const struct snd_soc_dapm_route audio_map[] = { @@ -102,9 +87,6 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headphone Jack", NULL, "Platform Clock" }, { "Headset Mic", NULL, "Platform Clock" }, { "Line Out", NULL, "Platform Clock" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, }; static struct snd_soc_jack_pin jack_pins[] = { @@ -124,7 +106,7 @@ static struct snd_soc_jack_pin jack_pins[] = { static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; struct snd_soc_jack *jack = &ctx->headset_jack; @@ -147,7 +129,8 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) * Use PLL bypass mode if MCLK is available, be sure to set the * frequency of MCLK to 12.288 or 24.576MHz on topology side. */ - if (mclk_rate == 12288000 || mclk_rate == 24576000) { + if (ctx->da7219.mclk_en && + (mclk_rate == 12288000 || mclk_rate == 24576000)) { /* PLL bypass mode */ dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate); @@ -157,7 +140,7 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } - ctx->pll_bypass = 1; + ctx->da7219.pll_bypass = true; } /* @@ -188,248 +171,30 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) return ret; } -static int max98373_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) +static void da7219_codec_exit(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); - int ret, j; - - for (j = 0; j < runtime->dai_link->num_codecs; j++) { - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, j); - - if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { - /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV0 TDM slot err:%d\n", ret); - return ret; - } - } - if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { - /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16); - if (ret < 0) { - dev_err(runtime->dev, "DEV1 TDM slot err:%d\n", ret); - return ret; - } - } - } + struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - return 0; -} - -static const struct snd_soc_ops max98373_ops = { - .hw_params = max98373_hw_params, -}; - -static int hdmi_init(struct snd_soc_pcm_runtime *rtd) -{ - struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - - ctx->hdmi.hdmi_comp = dai->component; - - return 0; + snd_soc_component_set_jack(component, NULL, NULL); } static int card_late_probe(struct snd_soc_card *card) { - struct card_private *ctx = snd_soc_card_get_drvdata(card); - - if (!ctx->hdmi.idisp_codec) - return 0; - - if (!ctx->hdmi.hdmi_comp) - return -EINVAL; - - return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); -} - -SND_SOC_DAILINK_DEF(ssp0_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); -SND_SOC_DAILINK_DEF(ssp0_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("i2c-DLGS7219:00", DIALOG_CODEC_DAI))); - -SND_SOC_DAILINK_DEF(ssp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); - -SND_SOC_DAILINK_DEF(ssp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); -SND_SOC_DAILINK_DEF(dummy_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai"))); - -SND_SOC_DAILINK_DEF(dmic_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); -SND_SOC_DAILINK_DEF(dmic_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("dmic-codec", "dmic-hifi"))); - -SND_SOC_DAILINK_DEF(dmic16k_pin, - DAILINK_COMP_ARRAY(COMP_CPU("DMIC16k Pin"))); - -SND_SOC_DAILINK_DEF(idisp1_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp1 Pin"))); -SND_SOC_DAILINK_DEF(idisp1_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi1"))); - -SND_SOC_DAILINK_DEF(idisp2_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp2 Pin"))); -SND_SOC_DAILINK_DEF(idisp2_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi2"))); - -SND_SOC_DAILINK_DEF(idisp3_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp3 Pin"))); -SND_SOC_DAILINK_DEF(idisp3_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); - -SND_SOC_DAILINK_DEF(idisp4_pin, - DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin"))); -SND_SOC_DAILINK_DEF(idisp4_codec, - DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); - -SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */ - DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); - -static struct snd_soc_dai_link jsl_dais[] = { - /* Back End DAI links */ - { - .name = "SSP1-Codec", - .id = 0, - .ignore_pmdown_time = 1, - .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, /* IV feedback */ - SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform), - }, - { - .name = "SSP0-Codec", - .id = 1, - .no_pcm = 1, - .init = da7219_codec_init, - .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 2, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .name = "dmic16k", - .id = 6, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), + struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_dapm_context *dapm = &card->dapm; + int err; + + if (ctx->amp_type == CODEC_MAX98373) { + /* Disable Left and Right Spk pin after boot */ + snd_soc_dapm_disable_pin(dapm, "Left Spk"); + snd_soc_dapm_disable_pin(dapm, "Right Spk"); + err = snd_soc_dapm_sync(dapm); + if (err < 0) + return err; } -}; -static struct snd_soc_dai_link adl_dais[] = { - /* Back End DAI links */ - { - .name = "SSP0-Codec", - .id = 0, - .no_pcm = 1, - .init = da7219_codec_init, - .ignore_pmdown_time = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), - }, - { - .name = "dmic01", - .id = 1, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), - }, - { - .name = "dmic16k", - .id = 2, - .ignore_suspend = 1, - .dpcm_capture = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), - }, - { - .name = "iDisp1", - .id = 3, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), - }, - { - .name = "iDisp2", - .id = 4, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), - }, - { - .name = "iDisp3", - .id = 5, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), - }, - { - .name = "iDisp4", - .id = 6, - .init = hdmi_init, - .dpcm_playback = 1, - .no_pcm = 1, - SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), - }, - { - .name = "SSP1-Codec", - .id = 7, - .no_pcm = 1, - .dpcm_playback = 1, - /* feedback stream or firmware-generated echo reference */ - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform), - }, - { - .name = "SSP2-BT", - .id = 8, - .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, - SND_SOC_DAILINK_REG(ssp2_pin, dummy_codec, platform), - }, -}; + return sof_intel_board_card_late_probe(card); +} static struct snd_soc_card card_da7219 = { .name = "da7219", /* the sof- prefix is added by the core */ @@ -444,82 +209,208 @@ static struct snd_soc_card card_da7219 = { .late_probe = card_late_probe, }; +static struct snd_soc_dai_link_component da7219_component[] = { + { + .name = "i2c-DLGS7219:00", + .dai_name = DIALOG_CODEC_DAI, + } +}; + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) +{ + int ret; + + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; + + if (!ctx->codec_link) { + dev_err(dev, "codec link not available"); + return -EINVAL; + } + + /* codec-specific fields for headphone codec */ + ctx->codec_link->codecs = da7219_component; + ctx->codec_link->num_codecs = ARRAY_SIZE(da7219_component); + ctx->codec_link->init = da7219_codec_init; + ctx->codec_link->exit = da7219_codec_exit; + + if (ctx->amp_type == CODEC_NONE) + return 0; + + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; + } + + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + max_98357a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98360A: + max_98360a_dai_link(ctx->amp_link); + break; + case CODEC_MAX98373: + max_98373_dai_link(dev, ctx->amp_link); + break; + case CODEC_MAX98390: + max_98390_dai_link(dev, ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } + + return 0; +} + +#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define CML_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + +#define JSL_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + static int audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; - struct card_private *ctx; + struct sof_card_private *ctx; + char *card_name; unsigned long board_quirk = 0; - int ret, amp_idx; - - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; + int ret; if (pdev->id_entry && pdev->id_entry->driver_data) board_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); + if (!ctx) + return -ENOMEM; if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - if (board_quirk & SOF_DA7219_JSL_BOARD) { + if (board_quirk & SOF_DA7219_GLK_BOARD) { + /* dmic16k not support */ + ctx->dmic_be_num = 1; + + /* overwrite the DAI link order for GLK boards */ + ctx->link_order_overwrite = GLK_LINK_ORDER; + /* backward-compatible with existing devices */ switch (ctx->amp_type) { - case CODEC_MAX98360A: - card_da7219.name = devm_kstrdup(&pdev->dev, - "da7219max98360a", - GFP_KERNEL); + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "glkda7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; break; - case CODEC_MAX98373: - card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max", - GFP_KERNEL); + default: + break; + } + } else if (board_quirk & SOF_DA7219_CML_BOARD) { + /* overwrite the DAI link order for CML boards */ + ctx->link_order_overwrite = CML_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "cmlda7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; + break; + case CODEC_MAX98390: + card_name = devm_kstrdup(&pdev->dev, + "cml_max98390_da7219", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + card_da7219.name = card_name; break; default: break; } + } else if (board_quirk & SOF_DA7219_JSL_BOARD) { + /* overwrite the DAI link order for JSL boards */ + ctx->link_order_overwrite = JSL_LINK_ORDER; - dai_links = jsl_dais; - amp_idx = 0; + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + card_name = devm_kstrdup(&pdev->dev, "da7219max98360a", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; - card_da7219.num_links = ARRAY_SIZE(jsl_dais); - } else { - dai_links = adl_dais; - amp_idx = 7; + card_da7219.name = card_name; + break; + case CODEC_MAX98373: + card_name = devm_kstrdup(&pdev->dev, "da7219max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; - card_da7219.num_links = ARRAY_SIZE(adl_dais); + card_da7219.name = card_name; + break; + default: + break; + } } - dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + if (board_quirk & SOF_DA7219_MCLK_EN) + ctx->da7219.mclk_en = true; - /* speaker amp */ + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &card_da7219, ctx); + if (ret) + return ret; + + /* update codec_conf */ switch (ctx->amp_type) { - case CODEC_MAX98360A: - max_98360a_dai_link(&dai_links[amp_idx]); - break; case CODEC_MAX98373: - dai_links[amp_idx].codecs = max_98373_components; - dai_links[amp_idx].num_codecs = ARRAY_SIZE(max_98373_components); - dai_links[amp_idx].init = max_98373_spk_codec_init; - if (board_quirk & SOF_DA7219_JSL_BOARD) { - dai_links[amp_idx].ops = &max98373_ops; /* use local ops */ - } else { - /* TBD: implement the amp for later platform */ - dev_err(&pdev->dev, "max98373 not support yet\n"); - return -EINVAL; - } - max_98373_set_codec_conf(&card_da7219); break; + case CODEC_MAX98390: + max_98390_set_codec_conf(&pdev->dev, &card_da7219); + break; + case CODEC_MAX98357A: + case CODEC_MAX98360A: + case CODEC_NONE: + /* no codec conf required */ + break; default: dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); return -EINVAL; } - card_da7219.dai_link = dai_links; - card_da7219.dev = &pdev->dev; ret = snd_soc_fixup_dai_links_platform_name(&card_da7219, @@ -534,16 +425,48 @@ static int audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { - .name = "jsl_mx98373_da7219", - .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), + .name = "glk_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_GLK_BOARD | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "cml_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_CML_BOARD | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "jsl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "adl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { - .name = "jsl_mx98360_da7219", - .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), + .name = "rpl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { - .name = "adl_mx98360_da7219", - /* no quirk needed for this board */ + .name = "mtl_da7219_def", + .driver_data = (kernel_ulong_t)(SOF_DA7219_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT), }, { } }; @@ -564,6 +487,5 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); diff --git a/sound/soc/intel/boards/sof_es8336.c b/sound/soc/intel/boards/sof_es8336.c index c1fcc156a575..a0b3679b17b4 100644 --- a/sound/soc/intel/boards/sof_es8336.c +++ b/sound/soc/intel/boards/sof_es8336.c @@ -371,7 +371,7 @@ static int sof_es8336_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops sof_es8336_ops = { +static const struct snd_soc_ops sof_es8336_ops = { .hw_params = sof_es8336_hw_params, .trigger = sof_8336_trigger, }; @@ -455,8 +455,6 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].exit = sof_es8316_exit; links[id].ops = &sof_es8336_ops; links[id].nonatomic = true; - links[id].dpcm_playback = 1; - links[id].dpcm_capture = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -496,7 +494,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; @@ -539,7 +537,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; @@ -569,7 +567,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_codecs = 1; links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; links[id].num_cpus = 1; id++; @@ -681,7 +679,7 @@ static int sof_es8336_probe(struct platform_device *pdev) dai_links[0].codecs->dai_name = "ES8326 HiFi"; } else { dev_err(dev, "Error cannot find '%s' dev\n", mach->id); - return -ENXIO; + return -ENOENT; } codec_dev = acpi_get_first_physical_node(adev); @@ -818,6 +816,16 @@ static const struct platform_device_id board_ids[] = { SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | SOF_ES8336_JD_INVERTED), }, + { + .name = "arl_es83x6_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_ES8336_SSP_CODEC(1) | + SOF_NO_OF_HDMI_CAPTURE_SSP(2) | + SOF_HDMI_CAPTURE_1_SSP(0) | + SOF_HDMI_CAPTURE_2_SSP(2) | + SOF_SSP_HDMI_CAPTURE_PRESENT | + SOF_ES8336_SPEAKERS_EN_GPIO1_QUIRK | + SOF_ES8336_JD_INVERTED), + }, { } }; MODULE_DEVICE_TABLE(platform, board_ids); @@ -828,11 +836,11 @@ static struct platform_driver sof_es8336_driver = { .pm = &snd_soc_pm_ops, }, .probe = sof_es8336_probe, - .remove_new = sof_es8336_remove, + .remove = sof_es8336_remove, .id_table = board_ids, }; module_platform_driver(sof_es8336_driver); MODULE_DESCRIPTION("ASoC Intel(R) SOF + ES8336 Machine driver"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_maxim_common.c b/sound/soc/intel/boards/sof_maxim_common.c index cf2974718271..c98a67ae5e66 100644 --- a/sound/soc/intel/boards/sof_maxim_common.c +++ b/sound/soc/intel/boards/sof_maxim_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation #include <linux/module.h> #include <linux/string.h> #include <sound/pcm.h> @@ -9,9 +9,25 @@ #include <sound/soc-acpi.h> #include <sound/soc-dai.h> #include <sound/soc-dapm.h> +#include <sound/sof.h> #include <uapi/sound/asound.h> +#include "../common/soc-intel-quirks.h" #include "sof_maxim_common.h" +/* + * Common structures and functions + */ +static const struct snd_kcontrol_new maxim_2spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + +}; + +static const struct snd_soc_dapm_widget maxim_2spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + /* helper function to get the number of specific codec */ static unsigned int get_num_codecs(const char *hid) { @@ -24,14 +40,16 @@ static unsigned int get_num_codecs(const char *hid) return dev_num; } +/* + * Maxim MAX98373 + */ #define MAX_98373_PIN_NAME 16 -const struct snd_soc_dapm_route max_98373_dapm_routes[] = { +static const struct snd_soc_dapm_route max_98373_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Left BE_OUT" }, { "Right Spk", NULL, "Right BE_OUT" }, }; -EXPORT_SYMBOL_NS(max_98373_dapm_routes, SND_SOC_INTEL_SOF_MAXIM_COMMON); static struct snd_soc_codec_conf max_98373_codec_conf[] = { { @@ -44,7 +62,7 @@ static struct snd_soc_codec_conf max_98373_codec_conf[] = { }, }; -struct snd_soc_dai_link_component max_98373_components[] = { +static struct snd_soc_dai_link_component max_98373_components[] = { { /* For Right */ .name = MAX_98373_DEV0_NAME, .dai_name = MAX_98373_CODEC_DAI, @@ -54,34 +72,122 @@ struct snd_soc_dai_link_component max_98373_components[] = { .dai_name = MAX_98373_CODEC_DAI, }, }; -EXPORT_SYMBOL_NS(max_98373_components, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +/* + * According to the definition of 'DAI Sel Mux' mixer in max98373.c, rx mask + * should choose two channels from TDM slots, the LSB of rx mask is left channel + * and the other one is right channel. + */ +static const struct { + unsigned int rx; +} max_98373_tdm_mask[] = { + {.rx = 0x3}, + {.rx = 0x3}, +}; + +/* + * The tx mask indicates which channel(s) contains output IV-sense data and + * others should set to Hi-Z. Here we get the channel number from codec's ACPI + * device property "maxim,vmon-slot-no" and "maxim,imon-slot-no" to generate the + * mask. Refer to the max98373_slot_config() function in max98373.c codec driver. + */ +static unsigned int max_98373_get_tx_mask(struct device *dev) +{ + int vmon_slot; + int imon_slot; + + if (device_property_read_u32(dev, "maxim,vmon-slot-no", &vmon_slot)) + vmon_slot = 0; + + if (device_property_read_u32(dev, "maxim,imon-slot-no", &imon_slot)) + imon_slot = 1; + + dev_dbg(dev, "vmon_slot %d imon_slot %d\n", vmon_slot, imon_slot); + + return (0x1 << vmon_slot) | (0x1 << imon_slot); +} static int max_98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; + int i; + int tdm_slots; + unsigned int tx_mask; + unsigned int tx_mask_used = 0x0; int ret = 0; - int j; - for_each_rtd_codec_dais(rtd, j, codec_dai) { - if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { - /* DEV0 tdm slot configuration */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x03, 3, 8, 32); - } else if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { - /* DEV1 tdm slot configuration */ - ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0C, 3, 8, 32); + for_each_rtd_codec_dais(rtd, i, codec_dai) { + if (i >= ARRAY_SIZE(max_98373_tdm_mask)) { + dev_err(codec_dai->dev, "only 2 amps are supported\n"); + return -EINVAL; } - if (ret < 0) { - dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", - ret); - return ret; + + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* get the tplg configured tdm slot number */ + tdm_slots = sof_dai_get_tdm_slots(rtd); + if (tdm_slots <= 0) { + dev_err(rtd->dev, "invalid tdm slots %d\n", + tdm_slots); + return -EINVAL; + } + + /* get the tx mask from ACPI device properties */ + tx_mask = max_98373_get_tx_mask(codec_dai->dev); + if (!tx_mask) + return -EINVAL; + + if (tx_mask & tx_mask_used) { + dev_err(codec_dai->dev, "invalid tx mask 0x%x, used 0x%x\n", + tx_mask, tx_mask_used); + return -EINVAL; + } + + tx_mask_used |= tx_mask; + + /* + * check if tdm slot number is too small for channel + * allocation + */ + if (fls(tx_mask) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, tx %d slots %d\n", + fls(tx_mask), tdm_slots); + return -EINVAL; + } + + if (fls(max_98373_tdm_mask[i].rx) > tdm_slots) { + dev_err(codec_dai->dev, "slot mismatch, rx %d slots %d\n", + fls(max_98373_tdm_mask[i].rx), tdm_slots); + return -EINVAL; + } + + dev_dbg(codec_dai->dev, "set tdm slot: tx 0x%x rx 0x%x slots %d width %d\n", + tx_mask, max_98373_tdm_mask[i].rx, + tdm_slots, params_width(params)); + + ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_mask, + max_98373_tdm_mask[i].rx, + tdm_slots, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; } } return 0; } -int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) +static int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *codec_dai; @@ -124,33 +230,67 @@ int max_98373_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } -EXPORT_SYMBOL_NS(max_98373_trigger, SND_SOC_INTEL_SOF_MAXIM_COMMON); -struct snd_soc_ops max_98373_ops = { +static const struct snd_soc_ops max_98373_ops = { .hw_params = max_98373_hw_params, .trigger = max_98373_trigger, }; -EXPORT_SYMBOL_NS(max_98373_ops, SND_SOC_INTEL_SOF_MAXIM_COMMON); -int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) +static int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(MAX_98373_ACPI_HID); int ret; - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, - ARRAY_SIZE(max_98373_dapm_routes)); - if (ret) - dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + switch (num_codecs) { + case 2: + ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ARRAY_SIZE(maxim_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols, + ARRAY_SIZE(maxim_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, + ARRAY_SIZE(max_98373_dapm_routes)); + if (ret) { + dev_err(rtd->dev, "fail to add max98373 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "max98373: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + return ret; } -EXPORT_SYMBOL_NS(max_98373_spk_codec_init, SND_SOC_INTEL_SOF_MAXIM_COMMON); + +void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link) +{ + link->codecs = max_98373_components; + link->num_codecs = ARRAY_SIZE(max_98373_components); + link->init = max_98373_spk_codec_init; + link->ops = &max_98373_ops; +} +EXPORT_SYMBOL_NS(max_98373_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98373_set_codec_conf(struct snd_soc_card *card) { card->codec_conf = max_98373_codec_conf; card->num_configs = ARRAY_SIZE(max_98373_codec_conf); } -EXPORT_SYMBOL_NS(max_98373_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98373_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); /* * Maxim MAX98390 @@ -177,6 +317,17 @@ static const struct snd_soc_dapm_route max_98390_tt_dapm_routes[] = { { "TR Spk", NULL, "Tweeter Right BE_OUT" }, }; +static struct snd_soc_codec_conf max_98390_cml_codec_conf[] = { + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), + .name_prefix = "Left", + }, + { + .dlc = COMP_CODEC_CONF(MAX_98390_DEV1_NAME), + .name_prefix = "Right", + }, +}; + static struct snd_soc_codec_conf max_98390_codec_conf[] = { { .dlc = COMP_CODEC_CONF(MAX_98390_DEV0_NAME), @@ -229,6 +380,7 @@ static int max_98390_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *codec_dai; int i, ret; @@ -238,13 +390,24 @@ static int max_98390_hw_params(struct snd_pcm_substream *substream, return -ENODEV; } - ret = snd_soc_dai_set_tdm_slot(codec_dai, max_98390_tdm_mask[i].tx, - max_98390_tdm_mask[i].rx, 4, - params_width(params)); - if (ret < 0) { - dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", - ret); - return ret; + switch (dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + case SND_SOC_DAIFMT_DSP_B: + /* 4-slot TDM */ + ret = snd_soc_dai_set_tdm_slot(codec_dai, + max_98390_tdm_mask[i].tx, + max_98390_tdm_mask[i].rx, + 4, + params_width(params)); + if (ret < 0) { + dev_err(codec_dai->dev, "fail to set tdm slot, ret %d\n", + ret); + return ret; + } + break; + default: + dev_dbg(codec_dai->dev, "codec is in I2S mode\n"); + break; } } return 0; @@ -287,6 +450,22 @@ static int max_98390_init(struct snd_soc_pcm_runtime *rtd) fallthrough; case 2: /* add regular speakers dapm route */ + ret = snd_soc_dapm_new_controls(&card->dapm, maxim_2spk_widgets, + ARRAY_SIZE(maxim_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add max98390 woofer widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, maxim_2spk_kcontrols, + ARRAY_SIZE(maxim_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add max98390 woofer kcontrols, ret %d\n", + ret); + return ret; + } + ret = snd_soc_dapm_add_routes(&card->dapm, max_98390_dapm_routes, ARRAY_SIZE(max_98390_dapm_routes)); if (ret) { @@ -327,7 +506,7 @@ void max_98390_dai_link(struct device *dev, struct snd_soc_dai_link *link) link->init = max_98390_init; link->ops = &max_98390_ops; } -EXPORT_SYMBOL_NS(max_98390_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98390_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) { @@ -337,6 +516,10 @@ void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) switch (num_codecs) { case 2: + if (soc_intel_is_cml()) + card->codec_conf = max_98390_cml_codec_conf; + + fallthrough; case 4: card->num_configs = num_codecs; break; @@ -346,7 +529,7 @@ void max_98390_set_codec_conf(struct device *dev, struct snd_soc_card *card) break; } } -EXPORT_SYMBOL_NS(max_98390_set_codec_conf, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98390_set_codec_conf, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); /* * Maxim MAX98357A/MAX98360A @@ -413,7 +596,7 @@ void max_98357a_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(max_98357a_components); link->init = max_98357a_init; } -EXPORT_SYMBOL_NS(max_98357a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98357a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); void max_98360a_dai_link(struct snd_soc_dai_link *link) { @@ -421,7 +604,7 @@ void max_98360a_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(max_98360a_components); link->init = max_98357a_init; } -EXPORT_SYMBOL_NS(max_98360a_dai_link, SND_SOC_INTEL_SOF_MAXIM_COMMON); +EXPORT_SYMBOL_NS(max_98360a_dai_link, "SND_SOC_INTEL_SOF_MAXIM_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Maxim helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_maxim_common.h b/sound/soc/intel/boards/sof_maxim_common.h index fe0212fbad8e..3d34c7dae6f5 100644 --- a/sound/soc/intel/boards/sof_maxim_common.h +++ b/sound/soc/intel/boards/sof_maxim_common.h @@ -11,7 +11,7 @@ #define __SOF_MAXIM_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Maxim MAX98373 @@ -20,13 +20,8 @@ #define MAX_98373_DEV0_NAME "i2c-" MAX_98373_ACPI_HID ":00" #define MAX_98373_DEV1_NAME "i2c-" MAX_98373_ACPI_HID ":01" -extern struct snd_soc_dai_link_component max_98373_components[2]; -extern struct snd_soc_ops max_98373_ops; -extern const struct snd_soc_dapm_route max_98373_dapm_routes[]; - -int max_98373_spk_codec_init(struct snd_soc_pcm_runtime *rtd); +void max_98373_dai_link(struct device *dev, struct snd_soc_dai_link *link); void max_98373_set_codec_conf(struct snd_soc_card *card); -int max_98373_trigger(struct snd_pcm_substream *substream, int cmd); /* * Maxim MAX98390 diff --git a/sound/soc/intel/boards/sof_nau8825.c b/sound/soc/intel/boards/sof_nau8825.c index 719c2fbaf515..72ce32e2cd57 100644 --- a/sound/soc/intel/boards/sof_nau8825.c +++ b/sound/soc/intel/boards/sof_nau8825.c @@ -24,27 +24,8 @@ #include "sof_realtek_common.h" #include "sof_maxim_common.h" #include "sof_nuvoton_common.h" -#include "sof_ssp_common.h" - -#define SOF_NAU8825_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_NAU8825_SSP_CODEC_MASK (GENMASK(2, 0)) -#define SOF_NAU8825_SSP_AMP_SHIFT 4 -#define SOF_NAU8825_SSP_AMP_MASK (GENMASK(6, 4)) -#define SOF_NAU8825_SSP_AMP(quirk) \ - (((quirk) << SOF_NAU8825_SSP_AMP_SHIFT) & SOF_NAU8825_SSP_AMP_MASK) -#define SOF_NAU8825_NUM_HDMIDEV_SHIFT 7 -#define SOF_NAU8825_NUM_HDMIDEV_MASK (GENMASK(9, 7)) -#define SOF_NAU8825_NUM_HDMIDEV(quirk) \ - (((quirk) << SOF_NAU8825_NUM_HDMIDEV_SHIFT) & SOF_NAU8825_NUM_HDMIDEV_MASK) - -/* BT audio offload: reserve 3 bits for future */ -#define SOF_BT_OFFLOAD_SSP_SHIFT 10 -#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(12, 10)) -#define SOF_BT_OFFLOAD_SSP(quirk) \ - (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) -#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(13) - -static unsigned long sof_nau8825_quirk = SOF_NAU8825_SSP_CODEC(0); + +static unsigned long sof_nau8825_quirk = SOF_SSP_PORT_CODEC(0); static struct snd_soc_jack_pin jack_pins[] = { { @@ -134,7 +115,7 @@ static int sof_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops sof_nau8825_ops = { +static const struct snd_soc_ops sof_nau8825_ops = { .hw_params = sof_nau8825_hw_params, }; @@ -159,15 +140,11 @@ static int sof_card_late_probe(struct snd_soc_card *card) static const struct snd_kcontrol_new sof_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), }; static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -236,10 +213,7 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, max_98360a_dai_link(ctx->amp_link); break; case CODEC_MAX98373: - ctx->amp_link->codecs = max_98373_components; - ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); - ctx->amp_link->init = max_98373_spk_codec_init; - ctx->amp_link->ops = &max_98373_ops; + max_98373_dai_link(dev, ctx->amp_link); break; case CODEC_NAU8318: nau8318_set_dai_link(ctx->amp_link); @@ -264,41 +238,19 @@ static int sof_audio_probe(struct platform_device *pdev) struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_nau8825_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); - dev_dbg(&pdev->dev, "sof_nau8825_quirk = %lx\n", sof_nau8825_quirk); - /* default number of DMIC DAI's */ - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_nau8825_quirk & SOF_NAU8825_NUM_HDMIDEV_MASK) >> - SOF_NAU8825_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_nau8825_quirk); + if (!ctx) + return -ENOMEM; if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - /* port number of peripherals attached to ssp interface */ - ctx->ssp_bt = (sof_nau8825_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ctx->ssp_amp = (sof_nau8825_quirk & SOF_NAU8825_SSP_AMP_MASK) >> - SOF_NAU8825_SSP_AMP_SHIFT; - - ctx->ssp_codec = sof_nau8825_quirk & SOF_NAU8825_SSP_CODEC_MASK; - - if (sof_nau8825_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; - /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_nau8825, ctx); if (ret) @@ -312,10 +264,10 @@ static int sof_audio_probe(struct platform_device *pdev) case CODEC_RT1015P: sof_rt1015p_codec_conf(&sof_audio_card_nau8825); break; - case CODEC_NONE: case CODEC_MAX98360A: case CODEC_NAU8318: case CODEC_RT1019P: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -339,34 +291,33 @@ static int sof_audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { - .name = "sof_nau8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), - - }, - { .name = "adl_rt1019p_8825", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(2) | - SOF_NAU8825_NUM_HDMIDEV(4)), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .name = "adl_nau8825_def", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "rpl_nau8825_def", - .driver_data = (kernel_ulong_t)(SOF_NAU8825_SSP_CODEC(0) | - SOF_NAU8825_SSP_AMP(1) | - SOF_NAU8825_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), + }, + { + .name = "mtl_nau8825_def", + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT), }, { } }; @@ -388,8 +339,7 @@ MODULE_AUTHOR("David Lin <ctlin0@nuvoton.com>"); MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_NUVOTON_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_NUVOTON_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.c b/sound/soc/intel/boards/sof_nuvoton_common.c index 549a412f5d53..ed41cb6f7fa5 100644 --- a/sound/soc/intel/boards/sof_nuvoton_common.c +++ b/sound/soc/intel/boards/sof_nuvoton_common.c @@ -67,7 +67,7 @@ void nau8318_set_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(nau8318_components); link->init = nau8318_init; } -EXPORT_SYMBOL_NS(nau8318_set_dai_link, SND_SOC_INTEL_SOF_NUVOTON_COMMON); +EXPORT_SYMBOL_NS(nau8318_set_dai_link, "SND_SOC_INTEL_SOF_NUVOTON_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Nuvoton helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_nuvoton_common.h b/sound/soc/intel/boards/sof_nuvoton_common.h index 53a84f9a67c0..8a0f283260e7 100644 --- a/sound/soc/intel/boards/sof_nuvoton_common.h +++ b/sound/soc/intel/boards/sof_nuvoton_common.h @@ -9,7 +9,7 @@ #define __SOF_NUVOTON_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Nuvoton NAU8318 diff --git a/sound/soc/intel/boards/sof_pcm512x.c b/sound/soc/intel/boards/sof_pcm512x.c index b01cb2329542..2f43710c1bae 100644 --- a/sound/soc/intel/boards/sof_pcm512x.c +++ b/sound/soc/intel/boards/sof_pcm512x.c @@ -246,12 +246,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_pcm512x_codec_init; links[id].ops = &sof_pcm512x_ops; - links[id].dpcm_playback = 1; /* * capture only supported with specific versions of the Hifiberry DAC+ */ - if (sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE) - links[id].dpcm_capture = 1; + if (!(sof_pcm512x_quirk & SOF_PCM512X_ENABLE_SSP_CAPTURE)) + links[id].playback_only = 1; links[id].no_pcm = 1; links[id].cpus = &cpus[id]; links[id].num_cpus = 1; @@ -294,7 +293,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].ignore_suspend = 1; - links[id].dpcm_capture = 1; + links[id].capture_only = 1; links[id].no_pcm = 1; id++; } @@ -341,7 +340,7 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].platforms = platform_component; links[id].num_platforms = ARRAY_SIZE(platform_component); links[id].init = sof_hdmi_init; - links[id].dpcm_playback = 1; + links[id].playback_only = 1; links[id].no_pcm = 1; id++; } @@ -371,8 +370,7 @@ static int sof_audio_probe(struct platform_device *pdev) sof_pcm512x_quirk = SOF_PCM512X_SSP_CODEC(2); } else { dmic_be_num = 2; - if (mach->mach_params.common_hdmi_codec_drv && - (mach->mach_params.codec_mask & IDISP_CODEC_MASK)) + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->idisp_codec = true; /* links are always present in topology */ @@ -430,7 +428,7 @@ static void sof_pcm512x_remove(struct platform_device *pdev) static struct platform_driver sof_audio = { .probe = sof_audio_probe, - .remove_new = sof_pcm512x_remove, + .remove = sof_pcm512x_remove, .driver = { .name = "sof_pcm512x", .pm = &snd_soc_pm_ops, @@ -442,4 +440,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF + PCM512x Machine driver"); MODULE_AUTHOR("Pierre-Louis Bossart"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sof_pcm512x"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); diff --git a/sound/soc/intel/boards/sof_realtek_common.c b/sound/soc/intel/boards/sof_realtek_common.c index 80c8687cd1da..600707d403b9 100644 --- a/sound/soc/intel/boards/sof_realtek_common.c +++ b/sound/soc/intel/boards/sof_realtek_common.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation #include <linux/device.h> #include <linux/kernel.h> @@ -15,10 +15,51 @@ #include "../../codecs/rt1011.h" #include "../../codecs/rt1015.h" #include "../../codecs/rt1308.h" +#include "../common/soc-intel-quirks.h" #include "sof_realtek_common.h" /* - * Current only 2-amp configuration is supported for rt1011 + * Common structures and functions + */ +static const struct snd_kcontrol_new realtek_2spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + +}; + +static const struct snd_soc_dapm_widget realtek_2spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + +static const struct snd_kcontrol_new realtek_4spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("WL Ext Spk"), + SOC_DAPM_PIN_SWITCH("WR Ext Spk"), + SOC_DAPM_PIN_SWITCH("TL Ext Spk"), + SOC_DAPM_PIN_SWITCH("TR Ext Spk"), +}; + +static const struct snd_soc_dapm_widget realtek_4spk_widgets[] = { + SND_SOC_DAPM_SPK("WL Ext Spk", NULL), + SND_SOC_DAPM_SPK("WR Ext Spk", NULL), + SND_SOC_DAPM_SPK("TL Ext Spk", NULL), + SND_SOC_DAPM_SPK("TR Ext Spk", NULL), +}; + +/* helper function to get the number of specific codec */ +static unsigned int get_num_codecs(const char *hid) +{ + struct acpi_device *adev; + unsigned int dev_num = 0; + + for_each_acpi_dev_match(adev, hid, NULL, -1) + dev_num++; + + return dev_num; +} + +/* + * Realtek ALC1011 */ static const struct snd_soc_dapm_route speaker_map_lr[] = { /* speaker */ @@ -26,16 +67,14 @@ static const struct snd_soc_dapm_route speaker_map_lr[] = { { "Right Spk", NULL, "Right SPO" }, }; -/* - * Make sure device's Unique ID follows this configuration: - * - * Two speakers: - * 0: left, 1: right - * Four speakers: - * 0: Woofer left, 1: Woofer right - * 2: Tweeter left, 3: Tweeter right - */ -static struct snd_soc_codec_conf rt1011_codec_confs[] = { +static const struct snd_soc_dapm_route rt1011_4spk_routes[] = { + {"WL Ext Spk", NULL, "WL SPO" }, + {"WR Ext Spk", NULL, "WR SPO" }, + {"TL Ext Spk", NULL, "TL SPO" }, + {"TR Ext Spk", NULL, "TR SPO" }, +}; + +static struct snd_soc_codec_conf rt1011_2spk_codec_confs[] = { { .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), .name_prefix = "Left", @@ -46,6 +85,25 @@ static struct snd_soc_codec_conf rt1011_codec_confs[] = { }, }; +static struct snd_soc_codec_conf rt1011_4spk_codec_confs[] = { + { + .dlc = COMP_CODEC_CONF(RT1011_DEV0_NAME), + .name_prefix = "WL", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV1_NAME), + .name_prefix = "WR", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV2_NAME), + .name_prefix = "TL", + }, + { + .dlc = COMP_CODEC_CONF(RT1011_DEV3_NAME), + .name_prefix = "TR", + }, +}; + static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { { .name = RT1011_DEV0_NAME, @@ -55,6 +113,14 @@ static struct snd_soc_dai_link_component rt1011_dai_link_components[] = { .name = RT1011_DEV1_NAME, .dai_name = RT1011_CODEC_DAI, }, + { + .name = RT1011_DEV2_NAME, + .dai_name = RT1011_CODEC_DAI, + }, + { + .name = RT1011_DEV3_NAME, + .dai_name = RT1011_CODEC_DAI, + }, }; static const struct { @@ -63,6 +129,8 @@ static const struct { } rt1011_tdm_mask[] = { {.tx = 0x4, .rx = 0x1}, {.tx = 0x8, .rx = 0x2}, + {.tx = 0x1, .rx = 0x1}, + {.tx = 0x2, .rx = 0x2}, }; static int rt1011_hw_params(struct snd_pcm_substream *substream, @@ -118,30 +186,127 @@ static const struct snd_soc_ops rt1011_ops = { static int rt1011_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); int ret; - ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, - ARRAY_SIZE(speaker_map_lr)); - if (ret) - dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); + switch (num_codecs) { + case 2: + if (!soc_intel_is_cml()) { + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", + ret); + return ret; + } + + break; + } + + /* + * register speaker widgets "WL Ext Spk" and "WR Ext Spk" to + * keep backward compatible with cml devices + */ + fallthrough; + case 4: + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_4spk_widgets, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_4spk_kcontrols, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 controls, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1011_4spk_routes, + num_codecs); + if (ret) { + dev_err(rtd->dev, "fail to add rt1011 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "rt1011: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + return ret; } -void sof_rt1011_dai_link(struct snd_soc_dai_link *link) +void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link) { + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); + link->codecs = rt1011_dai_link_components; - link->num_codecs = ARRAY_SIZE(rt1011_dai_link_components); + + switch (num_codecs) { + case 2: + case 4: + link->num_codecs = num_codecs; + break; + default: + dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs); + break; + } + link->init = rt1011_init; link->ops = &rt1011_ops; } -EXPORT_SYMBOL_NS(sof_rt1011_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1011_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); -void sof_rt1011_codec_conf(struct snd_soc_card *card) +void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card) { - card->codec_conf = rt1011_codec_confs; - card->num_configs = ARRAY_SIZE(rt1011_codec_confs); + unsigned int num_codecs = get_num_codecs(RT1011_ACPI_HID); + + switch (num_codecs) { + case 2: + if (soc_intel_is_cml()) { + /* + * use name prefix 'WL' and 'WR' for speaker widgets to + * keep backward compatible with cml devices + */ + card->codec_conf = rt1011_4spk_codec_confs; + } else { + card->codec_conf = rt1011_2spk_codec_confs; + } + + card->num_configs = num_codecs; + break; + case 4: + card->codec_conf = rt1011_4spk_codec_confs; + card->num_configs = ARRAY_SIZE(rt1011_4spk_codec_confs); + break; + default: + dev_err(dev, "rt1011: invalid num_codecs %d\n", num_codecs); + break; + } + } -EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * rt1015: i2c mode driver for ALC1015 and ALC1015Q @@ -149,59 +314,21 @@ EXPORT_SYMBOL_NS(sof_rt1011_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); * * For stereo output, there are always two amplifiers on the board. * However, the ACPI implements only one device instance (UID=0) if they - * are sharing the same enable pin. The code will detect the number of - * device instance and use corresponding DAPM structures for - * initialization. + * are sharing the same enable pin. This is the case of rt1015p. */ -static const struct snd_soc_dapm_route rt1015p_1dev_dapm_routes[] = { +static const struct snd_soc_dapm_route rt1015p_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "Speaker" }, { "Right Spk", NULL, "Speaker" }, }; -static const struct snd_soc_dapm_route rt1015p_2dev_dapm_routes[] = { - /* speaker */ - { "Left Spk", NULL, "Left Speaker" }, - { "Right Spk", NULL, "Right Speaker" }, -}; - -static struct snd_soc_codec_conf rt1015p_codec_confs[] = { - { - .dlc = COMP_CODEC_CONF(RT1015P_DEV0_NAME), - .name_prefix = "Left", - }, - { - .dlc = COMP_CODEC_CONF(RT1015P_DEV1_NAME), - .name_prefix = "Right", - }, -}; - static struct snd_soc_dai_link_component rt1015p_dai_link_components[] = { { .name = RT1015P_DEV0_NAME, .dai_name = RT1015P_CODEC_DAI, }, - { - .name = RT1015P_DEV1_NAME, - .dai_name = RT1015P_CODEC_DAI, - }, }; -static int rt1015p_get_num_codecs(void) -{ - static int dev_num; - - if (dev_num) - return dev_num; - - if (!acpi_dev_present("RTL1015", "1", -1)) - dev_num = 1; - else - dev_num = 2; - - return dev_num; -} - static int rt1015p_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -219,12 +346,22 @@ static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; - if (rt1015p_get_num_codecs() == 1) - ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_1dev_dapm_routes, - ARRAY_SIZE(rt1015p_1dev_dapm_routes)); - else - ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_2dev_dapm_routes, - ARRAY_SIZE(rt1015p_2dev_dapm_routes)); + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015p widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015p kcontrols, ret %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&card->dapm, rt1015p_dapm_routes, + ARRAY_SIZE(rt1015p_dapm_routes)); if (ret) dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); return ret; @@ -233,21 +370,16 @@ static int rt1015p_init(struct snd_soc_pcm_runtime *rtd) void sof_rt1015p_dai_link(struct snd_soc_dai_link *link) { link->codecs = rt1015p_dai_link_components; - link->num_codecs = rt1015p_get_num_codecs(); + link->num_codecs = ARRAY_SIZE(rt1015p_dai_link_components); link->init = rt1015p_init; link->ops = &rt1015p_ops; } -EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); void sof_rt1015p_codec_conf(struct snd_soc_card *card) { - if (rt1015p_get_num_codecs() == 1) - return; - - card->codec_conf = rt1015p_codec_confs; - card->num_configs = ARRAY_SIZE(rt1015p_codec_confs); } -EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015p_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * RT1015 audio amplifier @@ -320,7 +452,7 @@ static int rt1015_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rt1015_ops = { +static const struct snd_soc_ops rt1015_ops = { .hw_params = rt1015_hw_params, }; @@ -348,8 +480,42 @@ static struct snd_soc_dai_link_component rt1015_components[] = { static int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) { - return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, - ARRAY_SIZE(speaker_map_lr)); + struct snd_soc_card *card = rtd->card; + unsigned int num_codecs = get_num_codecs(RT1015_ACPI_HID); + int ret; + + switch (num_codecs) { + case 2: + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 kcontrols, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, + ARRAY_SIZE(speaker_map_lr)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1015 routes, ret %d\n", + ret); + return ret; + } + break; + default: + dev_err(rtd->dev, "rt1015: invalid num_codecs %d\n", num_codecs); + return -EINVAL; + } + + return ret; } void sof_rt1015_codec_conf(struct snd_soc_card *card) @@ -357,7 +523,7 @@ void sof_rt1015_codec_conf(struct snd_soc_card *card) card->codec_conf = rt1015_amp_conf; card->num_configs = ARRAY_SIZE(rt1015_amp_conf); } -EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015_codec_conf, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); void sof_rt1015_dai_link(struct snd_soc_dai_link *link) { @@ -366,7 +532,7 @@ void sof_rt1015_dai_link(struct snd_soc_dai_link *link) link->init = speaker_codec_init_lr; link->ops = &rt1015_ops; } -EXPORT_SYMBOL_NS(sof_rt1015_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1015_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * RT1308 audio amplifier @@ -462,7 +628,7 @@ void sof_rt1308_dai_link(struct snd_soc_dai_link *link) link->init = rt1308_init; link->ops = &rt1308_ops; } -EXPORT_SYMBOL_NS(sof_rt1308_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1308_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); /* * 2-amp Configuration for RT1019 @@ -486,6 +652,20 @@ static int rt1019p_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; + ret = snd_soc_dapm_new_controls(&card->dapm, realtek_2spk_widgets, + ARRAY_SIZE(realtek_2spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1019p widgets, ret %d\n", ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, realtek_2spk_kcontrols, + ARRAY_SIZE(realtek_2spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt1019p kcontrols, ret %d\n", ret); + return ret; + } + ret = snd_soc_dapm_add_routes(&card->dapm, rt1019p_dapm_routes, ARRAY_SIZE(rt1019p_dapm_routes)); if (ret) { @@ -501,7 +681,7 @@ void sof_rt1019p_dai_link(struct snd_soc_dai_link *link) link->num_codecs = ARRAY_SIZE(rt1019p_components); link->init = rt1019p_init; } -EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, SND_SOC_INTEL_SOF_REALTEK_COMMON); +EXPORT_SYMBOL_NS(sof_rt1019p_dai_link, "SND_SOC_INTEL_SOF_REALTEK_COMMON"); MODULE_DESCRIPTION("ASoC Intel SOF Realtek helpers"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_realtek_common.h b/sound/soc/intel/boards/sof_realtek_common.h index e3fa2924c1c1..876290555c22 100644 --- a/sound/soc/intel/boards/sof_realtek_common.h +++ b/sound/soc/intel/boards/sof_realtek_common.h @@ -11,7 +11,7 @@ #define __SOF_REALTEK_COMMON_H #include <sound/soc.h> -#include "sof_ssp_common.h" +#include <sound/soc-acpi-intel-ssp-common.h> /* * Realtek ALC1011 @@ -23,15 +23,14 @@ #define RT1011_DEV2_NAME "i2c-" RT1011_ACPI_HID ":02" #define RT1011_DEV3_NAME "i2c-" RT1011_ACPI_HID ":03" -void sof_rt1011_dai_link(struct snd_soc_dai_link *link); -void sof_rt1011_codec_conf(struct snd_soc_card *card); +void sof_rt1011_dai_link(struct device *dev, struct snd_soc_dai_link *link); +void sof_rt1011_codec_conf(struct device *dev, struct snd_soc_card *card); /* * Realtek ALC1015 (AUTO) */ #define RT1015P_CODEC_DAI "HiFi" #define RT1015P_DEV0_NAME RT1015P_ACPI_HID ":00" -#define RT1015P_DEV1_NAME RT1015P_ACPI_HID ":01" void sof_rt1015p_dai_link(struct snd_soc_dai_link *link); void sof_rt1015p_codec_conf(struct snd_soc_card *card); diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 640d17c6cd35..f5925bd0a3fc 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -27,37 +27,13 @@ #include "sof_board_helpers.h" #include "sof_maxim_common.h" #include "sof_realtek_common.h" -#include "sof_ssp_common.h" - -#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) -#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) -#define SOF_RT5682_MCLK_EN BIT(3) -#define SOF_RT5682_SSP_AMP_SHIFT 6 -#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) -#define SOF_RT5682_SSP_AMP(quirk) \ - (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) -#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) -#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10 -#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10)) -#define SOF_RT5682_NUM_HDMIDEV(quirk) \ - ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) - -/* BT audio offload: reserve 3 bits for future */ -#define SOF_BT_OFFLOAD_SSP_SHIFT 19 -#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(21, 19)) -#define SOF_BT_OFFLOAD_SSP(quirk) \ - (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) -#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(22) - -/* HDMI capture*/ -#define SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT 27 -#define SOF_SSP_HDMI_CAPTURE_PRESENT_MASK (GENMASK(30, 27)) -#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ - (((quirk) << SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT) & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) + +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_RT5682_MCLK_EN BIT(0) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0); + SOF_SSP_PORT_CODEC(0); static int sof_rt5682_quirk_cb(const struct dmi_system_id *id) { @@ -72,7 +48,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), }, - .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)), }, { .callback = sof_rt5682_quirk_cb, @@ -80,7 +56,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), }, - .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + .driver_data = (void *)(SOF_SSP_PORT_CODEC(2)), }, { .callback = sof_rt5682_quirk_cb, @@ -89,25 +65,7 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(1)), - }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1)), - }, - { - .callback = sof_rt5682_quirk_cb, - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), - }, - .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0)), + SOF_SSP_PORT_CODEC(1)), }, { .callback = sof_rt5682_quirk_cb, @@ -116,9 +74,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .callback = sof_rt5682_quirk_cb, @@ -128,9 +86,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_OEM_STRING, "AUDIO-ADL_MAX98373_ALC5682I_I2S"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .callback = sof_rt5682_quirk_cb, @@ -139,9 +97,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98390_ALC5682I_I2S"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .callback = sof_rt5682_quirk_cb, @@ -150,9 +108,9 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98360_ALC5682I_I2S_AMP_SSP2"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .callback = sof_rt5682_quirk_cb, @@ -160,11 +118,10 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Rex"), }, .driver_data = (void *)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(2) | - SOF_RT5682_SSP_AMP(0) | - SOF_RT5682_NUM_HDMIDEV(3) | - SOF_BT_OFFLOAD_SSP(1) | - SOF_SSP_BT_OFFLOAD_PRESENT + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(0) | + SOF_SSP_PORT_BT_OFFLOAD(1) | + SOF_BT_OFFLOAD_PRESENT ), }, {} @@ -189,7 +146,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) int extra_jack_data; int ret, mclk_freq; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + if (ctx->rt5682.mclk_en) { mclk_freq = sof_dai_get_mclk(rtd); if (mclk_freq <= 0) { dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_freq); @@ -230,7 +187,7 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) } } - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + if (ctx->rt5682.is_legacy_cpu) { /* * The firmware might enable the clock at * boot (this information may or may not @@ -302,8 +259,8 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); int pll_id, pll_source, pll_in, pll_out, clk_id, ret; - if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + if (ctx->rt5682.mclk_en) { + if (ctx->rt5682.is_legacy_cpu) { ret = clk_prepare_enable(ctx->rt5682.mclk); if (ret < 0) { dev_err(rtd->dev, @@ -351,25 +308,12 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - pll_in = params_rate(params) * 50; - } - - switch (ctx->codec_type) { - case CODEC_RT5650: - pll_id = 0; /* not used in codec driver */ - clk_id = RT5645_SCLK_S_PLL1; - break; - case CODEC_RT5682: - pll_id = RT5682_PLL1; - clk_id = RT5682_SCLK_S_PLL1; - break; - case CODEC_RT5682S: - pll_id = RT5682S_PLL2; - clk_id = RT5682S_SCLK_S_PLL2; - break; - default: - dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type); - return -EINVAL; + /* get the tplg configured bclk. */ + pll_in = sof_dai_get_bclk(rtd); + if (pll_in <= 0) { + dev_err(rtd->dev, "invalid bclk freq %d\n", pll_in); + return -EINVAL; + } } pll_out = params_rate(params) * 512; @@ -392,6 +336,40 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } } else { + switch (ctx->codec_type) { + case CODEC_RT5650: + pll_id = 0; /* not used in codec driver */ + clk_id = RT5645_SCLK_S_PLL1; + break; + case CODEC_RT5682: + pll_id = RT5682_PLL1; + clk_id = RT5682_SCLK_S_PLL1; + break; + case CODEC_RT5682S: + /* check plla_table and pllb_table in rt5682s.c */ + switch (pll_in) { + case 3072000: + case 24576000: + /* + * For MCLK = 24.576MHz and sample rate = 96KHz case, use PLL1 We don't test + * pll_out or params_rate() here since rt5682s PLL2 doesn't support 24.576MHz + * input, so we have no choice but to use PLL1. Besides, we will not use PLL at + * all if pll_in == pll_out. ex, MCLK = 24.576Mhz and sample rate = 48KHz + */ + pll_id = RT5682S_PLL1; + clk_id = RT5682S_SCLK_S_PLL1; + break; + default: + pll_id = RT5682S_PLL2; + clk_id = RT5682S_SCLK_S_PLL2; + break; + } + break; + default: + dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type); + return -EINVAL; + } + /* Configure pll for codec */ ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in, pll_out); @@ -419,7 +397,7 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops sof_rt5682_ops = { +static const struct snd_soc_ops sof_rt5682_ops = { .hw_params = sof_rt5682_hw_params, }; @@ -444,16 +422,11 @@ static int sof_card_late_probe(struct snd_soc_card *card) static const struct snd_kcontrol_new sof_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone Jack"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), - }; static const struct snd_soc_dapm_widget sof_widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), }; static const struct snd_soc_dapm_route sof_map[] = { @@ -465,6 +438,17 @@ static const struct snd_soc_dapm_route sof_map[] = { { "IN1P", NULL, "Headset Mic" }, }; +static const struct snd_kcontrol_new rt5650_spk_kcontrols[] = { + SOC_DAPM_PIN_SWITCH("Left Spk"), + SOC_DAPM_PIN_SWITCH("Right Spk"), + +}; + +static const struct snd_soc_dapm_widget rt5650_spk_widgets[] = { + SND_SOC_DAPM_SPK("Left Spk", NULL), + SND_SOC_DAPM_SPK("Right Spk", NULL), +}; + static const struct snd_soc_dapm_route rt5650_spk_dapm_routes[] = { /* speaker */ { "Left Spk", NULL, "SPOL" }, @@ -476,6 +460,22 @@ static int rt5650_spk_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_card *card = rtd->card; int ret; + ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets, + ARRAY_SIZE(rt5650_spk_widgets)); + if (ret) { + dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n", + ret); + return ret; + } + + ret = snd_soc_add_card_controls(card, rt5650_spk_kcontrols, + ARRAY_SIZE(rt5650_spk_kcontrols)); + if (ret) { + dev_err(rtd->dev, "fail to add rt5650 spk kcontrols, ret %d\n", + ret); + return ret; + } + ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes, ARRAY_SIZE(rt5650_spk_dapm_routes)); if (ret) @@ -591,16 +591,13 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, max_98360a_dai_link(ctx->amp_link); break; case CODEC_MAX98373: - ctx->amp_link->codecs = max_98373_components; - ctx->amp_link->num_codecs = ARRAY_SIZE(max_98373_components); - ctx->amp_link->init = max_98373_spk_codec_init; - ctx->amp_link->ops = &max_98373_ops; + max_98373_dai_link(dev, ctx->amp_link); break; case CODEC_MAX98390: max_98390_dai_link(dev, ctx->amp_link); break; case CODEC_RT1011: - sof_rt1011_dai_link(ctx->amp_link); + sof_rt1011_dai_link(dev, ctx->amp_link); break; case CODEC_RT1015: sof_rt1015_dai_link(ctx->amp_link); @@ -626,90 +623,112 @@ sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, return 0; } +#define GLK_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_AMP, \ + SOF_LINK_CODEC, \ + SOF_LINK_DMIC01, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE, \ + SOF_LINK_NONE) + static int sof_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; struct sof_card_private *ctx; + char *card_name; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data; dmi_check_system(sof_rt5682_quirk_table); - ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); + + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk); + if (!ctx) + return -ENOMEM; if (ctx->codec_type == CODEC_RT5650) { - sof_audio_card_rt5682.name = devm_kstrdup(&pdev->dev, "rt5650", - GFP_KERNEL); + card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; /* create speaker dai link also */ if (ctx->amp_type == CODEC_NONE) ctx->amp_type = CODEC_RT5650; } + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + if (soc_intel_is_byt() || soc_intel_is_cht()) { ctx->rt5682.is_legacy_cpu = true; ctx->dmic_be_num = 0; /* HDMI is not supported by SOF on Baytrail/CherryTrail */ ctx->hdmi_num = 0; - /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_MCLK_EN | - SOF_RT5682_MCLK_BYTCHT_EN | - SOF_RT5682_SSP_CODEC(2); - } else { - ctx->dmic_be_num = 2; - ctx->hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >> - SOF_RT5682_NUM_HDMIDEV_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; - - if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) - ctx->hdmi.idisp_codec = true; - } - - /* need to get main clock from pmc */ - if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { - ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); - if (IS_ERR(ctx->rt5682.mclk)) { - ret = PTR_ERR(ctx->rt5682.mclk); - - dev_err(&pdev->dev, - "Failed to get MCLK from pmc_plt_clk_3: %d\n", - ret); - return ret; + } else if (soc_intel_is_glk()) { + /* dmic16k not support */ + ctx->dmic_be_num = 1; + + /* overwrite the DAI link order for GLK boards */ + ctx->link_order_overwrite = GLK_LINK_ORDER; + + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98357A: + card_name = devm_kstrdup(&pdev->dev, "glkrt5682max", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; + break; + default: + break; } - - ret = clk_prepare_enable(ctx->rt5682.mclk); - if (ret < 0) { - dev_err(&pdev->dev, - "could not configure MCLK state"); - return ret; + } else if (soc_intel_is_cml()) { + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_RT1011: + card_name = devm_kstrdup(&pdev->dev, "cml_rt1011_rt5682", + GFP_KERNEL); + if (!card_name) + return -ENOMEM; + + sof_audio_card_rt5682.name = card_name; + break; + default: + break; } } - dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); - - /* port number/mask of peripherals attached to ssp interface */ - ctx->ssp_mask_hdmi_in = (sof_rt5682_quirk & SOF_SSP_HDMI_CAPTURE_PRESENT_MASK) >> - SOF_NO_OF_HDMI_CAPTURE_SSP_SHIFT; - - ctx->ssp_bt = (sof_rt5682_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; + if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + ctx->rt5682.mclk_en = true; - ctx->ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> - SOF_RT5682_SSP_AMP_SHIFT; + /* need to get main clock from pmc */ + if (ctx->rt5682.is_legacy_cpu) { + ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + if (IS_ERR(ctx->rt5682.mclk)) { + ret = PTR_ERR(ctx->rt5682.mclk); - ctx->ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; + dev_err(&pdev->dev, + "Failed to get MCLK from pmc_plt_clk_3: %d\n", + ret); + return ret; + } - if (sof_rt5682_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) - ctx->bt_offload_present = true; + ret = clk_prepare_enable(ctx->rt5682.mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "could not configure MCLK state"); + return ret; + } + } + } /* update dai_link */ ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); @@ -725,7 +744,7 @@ static int sof_audio_probe(struct platform_device *pdev) max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1011: - sof_rt1011_codec_conf(&sof_audio_card_rt5682); + sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1015: sof_rt1015_codec_conf(&sof_audio_card_rt5682); @@ -733,11 +752,11 @@ static int sof_audio_probe(struct platform_device *pdev) case CODEC_RT1015P: sof_rt1015p_codec_conf(&sof_audio_card_rt5682); break; - case CODEC_NONE: case CODEC_MAX98357A: case CODEC_MAX98360A: case CODEC_RT1019P: case CODEC_RT5650: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -762,100 +781,116 @@ static int sof_audio_probe(struct platform_device *pdev) static const struct platform_device_id board_ids[] = { { .name = "sof_rt5682", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2)), + }, + { + .name = "glk_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(2) | + SOF_SSP_PORT_AMP(1)), + }, + { + .name = "icl_rt5682_def", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(0)), }, { - .name = "cml_rt1015_rt5682", + .name = "cml_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), }, { .name = "jsl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1)), }, { .name = "tgl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "adl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "adl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .name = "adl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(1) | - SOF_RT5682_NUM_HDMIDEV(3) | + SOF_SSP_PORT_CODEC(1) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { .name = "rpl_mx98357_rt5682", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(2) | - SOF_RT5682_NUM_HDMIDEV(4)), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(2) | + SOF_NUM_IDISP_HDMI(4)), }, { .name = "rpl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(4) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "rpl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(1) | - SOF_RT5682_NUM_HDMIDEV(3) | + SOF_SSP_PORT_CODEC(1) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_HDMI_CAPTURE_SSP_MASK(0x5)), + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { - .name = "mtl_mx98357_rt5682", + .name = "mtl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(3) | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { - .name = "mtl_mx98360_rt5682", + .name = "mtl_rt5682_c1_h02", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(0) | - SOF_RT5682_SSP_AMP(1) | - SOF_RT5682_NUM_HDMIDEV(3)), + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), }, { - .name = "mtl_rt5682_def", + .name = "arl_rt5682_c1_h02", + .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | + SOF_SSP_PORT_CODEC(1) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_SSP_MASK_HDMI_CAPTURE(0x5)), + }, + { + .name = "ptl_rt5682_def", .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | - SOF_RT5682_SSP_CODEC(2) | - SOF_RT5682_SSP_AMP(0) | - SOF_RT5682_NUM_HDMIDEV(3) | - SOF_BT_OFFLOAD_SSP(1) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_CODEC(0) | + SOF_SSP_PORT_AMP(1) | + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { } }; @@ -878,7 +913,6 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_AUTHOR("Mac Chiang <mac.chiang@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_MAXIM_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index 08f330ed5c2e..81a914bd7ec2 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -5,37 +5,48 @@ * sof_sdw - ASOC Machine driver for Intel SoundWire platforms */ +#include <linux/acpi.h> +#include <linux/bitmap.h> #include <linux/device.h> #include <linux/dmi.h> #include <linux/module.h> #include <linux/soundwire/sdw.h> #include <linux/soundwire/sdw_type.h> -#include <sound/soc.h> +#include <linux/soundwire/sdw_intel.h> +#include <sound/core.h> #include <sound/soc-acpi.h> #include "sof_sdw_common.h" #include "../../codecs/rt711.h" -unsigned long sof_sdw_quirk = RT711_JD1; +static unsigned long sof_sdw_quirk = RT711_JD1; static int quirk_override = -1; module_param_named(quirk, quirk_override, int, 0444); MODULE_PARM_DESC(quirk, "Board-specific quirk override"); +#define DMIC_DEFAULT_CHANNELS 2 + static void log_quirks(struct device *dev) { - if (SOF_JACK_JDSRC(sof_sdw_quirk)) + if (SOC_SDW_JACK_JDSRC(sof_sdw_quirk)) dev_dbg(dev, "quirk realtek,jack-detect-source %ld\n", - SOF_JACK_JDSRC(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - dev_dbg(dev, "quirk SOF_SDW_FOUR_SPK enabled\n"); + SOC_SDW_JACK_JDSRC(sof_sdw_quirk)); + if (sof_sdw_quirk & SOC_SDW_FOUR_SPK) + dev_err(dev, "quirk SOC_SDW_FOUR_SPK enabled but no longer supported\n"); if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) dev_dbg(dev, "quirk SOF_SDW_TGL_HDMI enabled\n"); - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC) - dev_dbg(dev, "quirk SOF_SDW_PCH_DMIC enabled\n"); + if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) + dev_dbg(dev, "quirk SOC_SDW_PCH_DMIC enabled\n"); if (SOF_SSP_GET_PORT(sof_sdw_quirk)) dev_dbg(dev, "SSP port %ld\n", SOF_SSP_GET_PORT(sof_sdw_quirk)); - if (sof_sdw_quirk & SOF_SDW_NO_AGGREGATION) - dev_dbg(dev, "quirk SOF_SDW_NO_AGGREGATION enabled\n"); + if (sof_sdw_quirk & SOC_SDW_NO_AGGREGATION) + dev_err(dev, "quirk SOC_SDW_NO_AGGREGATION enabled but no longer supported\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_SPKR) + dev_dbg(dev, "quirk SOC_SDW_CODEC_SPKR enabled\n"); + if (sof_sdw_quirk & SOC_SDW_SIDECAR_AMPS) + dev_dbg(dev, "quirk SOC_SDW_SIDECAR_AMPS enabled\n"); + if (sof_sdw_quirk & SOC_SDW_CODEC_MIC) + dev_dbg(dev, "quirk SOC_SDW_CODEC_MIC enabled\n"); } static int sof_sdw_quirk_cb(const struct dmi_system_id *id) @@ -52,7 +63,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "CometLake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, { .callback = sof_sdw_quirk_cb, @@ -77,8 +88,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F"), }, - .driver_data = (void *)(RT711_JD2 | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -86,8 +96,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990"), }, - .driver_data = (void *)(RT711_JD2 | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(RT711_JD2), }, /* IceLake devices */ { @@ -96,7 +105,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), }, - .driver_data = (void *)SOF_SDW_PCH_DMIC, + .driver_data = (void *)SOC_SDW_PCH_DMIC, }, /* TigerLake devices */ { @@ -108,7 +117,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | RT711_JD1 | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | SOF_SSP_PORT(SOF_I2S_SSP2)), }, { @@ -138,8 +147,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -148,8 +156,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -158,8 +165,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Volteer"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -170,8 +176,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Ripto"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK), + SOC_SDW_PCH_DMIC), }, { /* @@ -186,7 +191,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x360 Conv"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -200,7 +205,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "8709"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -211,7 +216,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPBC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -222,7 +227,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPBC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD1), }, { @@ -233,7 +238,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "LAPRC"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, { @@ -244,7 +249,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_BOARD_NAME, "LAPRC710"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | + SOC_SDW_PCH_DMIC | RT711_JD2_100K), }, /* TigerLake-SDCA devices */ @@ -255,8 +260,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A32") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -282,12 +286,20 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { { .callback = sof_sdw_quirk_cb, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), + DMI_MATCH(DMI_PRODUCT_SKU, "0000000000070000"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2_100K), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Brya"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_PCH_DMIC | - SOF_SDW_FOUR_SPK | + SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(2) | SOF_SSP_BT_OFFLOAD_PRESENT), }, @@ -298,8 +310,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF0") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -308,8 +319,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AF3"), }, /* No Jack */ - .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(SOF_SDW_TGL_HDMI), }, { .callback = sof_sdw_quirk_cb, @@ -318,8 +328,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -328,8 +337,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -338,8 +346,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -348,8 +355,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -358,8 +364,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B11") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -368,8 +373,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B12") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -397,8 +401,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B29"), }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -412,6 +415,15 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { { .callback = sof_sdw_quirk_cb, .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B8C"), + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16"), }, @@ -426,8 +438,16 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0BDA") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C0F") + }, + .driver_data = (void *)(SOF_SDW_TGL_HDMI | + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -436,8 +456,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C10"), }, /* No Jack */ - .driver_data = (void *)(SOF_SDW_TGL_HDMI | - SOF_SDW_FOUR_SPK), + .driver_data = (void *)(SOF_SDW_TGL_HDMI), }, { .callback = sof_sdw_quirk_cb, @@ -446,8 +465,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C11") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -456,8 +474,7 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C40") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), }, { .callback = sof_sdw_quirk_cb, @@ -466,8 +483,31 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0C4F") }, .driver_data = (void *)(SOF_SDW_TGL_HDMI | - RT711_JD2 | - SOF_SDW_FOUR_SPK), + RT711_JD2), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF6") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF9") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CFA") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), }, /* MeteorLake devices */ { @@ -491,10 +531,19 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), DMI_MATCH(DMI_PRODUCT_NAME, "Rex"), }, - .driver_data = (void *)(SOF_SDW_PCH_DMIC | + .driver_data = (void *)(SOC_SDW_PCH_DMIC | SOF_BT_OFFLOAD_SSP(1) | SOF_SSP_BT_OFFLOAD_PRESENT), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "OMEN Transcend Gaming Laptop"), + }, + .driver_data = (void *)(RT711_JD2), + }, + /* LunarLake devices */ { .callback = sof_sdw_quirk_cb, @@ -504,1137 +553,572 @@ static const struct dmi_system_id sof_sdw_quirk_table[] = { }, .driver_data = (void *)(RT711_JD2), }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE3") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE4") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDB") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDC") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CDD") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D36") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83JX") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83LC") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83MC") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83NM") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83HM") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | + SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21QB") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21QA") + }, + /* Note this quirk excludes the CODEC mic */ + .driver_data = (void *)(SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21Q6") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "21Q7") + }, + .driver_data = (void *)(SOC_SDW_SIDECAR_AMPS | SOC_SDW_CODEC_MIC), + }, + + /* ArrowLake devices */ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CE8") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF1") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF7") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF0") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF3") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF4") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0CF5") + }, + .driver_data = (void *)(SOC_SDW_CODEC_SPKR), + }, + /* Pantherlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_ptlrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Fatcat"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, + /* Wildcatlake devices*/ + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_FAMILY, "Intel_wclrvp"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC), + }, + { + .callback = sof_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_PRODUCT_NAME, "Ocelot"), + }, + .driver_data = (void *)(SOC_SDW_PCH_DMIC | + SOF_BT_OFFLOAD_SSP(2) | + SOF_SSP_BT_OFFLOAD_PRESENT), + }, {} }; -static struct snd_soc_dai_link_component platform_component[] = { - { - /* name might be overridden during probe */ - .name = "0000:00:1f.3" - } +static const struct snd_pci_quirk sof_sdw_ssid_quirk_table[] = { + SND_PCI_QUIRK(0x1043, 0x1e13, "ASUS Zenbook S14", SOC_SDW_CODEC_MIC), + SND_PCI_QUIRK(0x1043, 0x1f43, "ASUS Zenbook S16", SOC_SDW_CODEC_MIC), + {} }; -/* these wrappers are only needed to avoid typecast compilation errors */ -int sdw_startup(struct snd_pcm_substream *substream) +static void sof_sdw_check_ssid_quirk(const struct snd_soc_acpi_mach *mach) { - return sdw_startup_stream(substream); -} + const struct snd_pci_quirk *quirk_entry; -int sdw_prepare(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; + quirk_entry = snd_pci_quirk_lookup_id(mach->mach_params.subsystem_vendor, + mach->mach_params.subsystem_device, + sof_sdw_ssid_quirk_table); - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); + if (quirk_entry) + sof_sdw_quirk = quirk_entry->value; +} - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } +static const struct snd_soc_ops sdw_ops = { + .startup = asoc_sdw_startup, + .prepare = asoc_sdw_prepare, + .trigger = asoc_sdw_trigger, + .hw_params = asoc_sdw_hw_params, + .hw_free = asoc_sdw_hw_free, + .shutdown = asoc_sdw_shutdown, +}; - return sdw_prepare_stream(sdw_stream); -} +static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; -int sdw_trigger(struct snd_pcm_substream *substream, int cmd) +static int create_sdw_dailink(struct snd_soc_card *card, + struct asoc_sdw_dailink *sof_dai, + struct snd_soc_dai_link **dai_links, + int *be_id, struct snd_soc_codec_conf **codec_conf) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; + struct device *dev = card->dev; + struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + struct asoc_sdw_endpoint *sof_end; + int stream; int ret; - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->name_prefix) { + (*codec_conf)->dlc.name = sof_end->codec_name; + (*codec_conf)->name_prefix = sof_end->name_prefix; + (*codec_conf)++; + } - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); + if (sof_end->include_sidecar) { + ret = sof_end->codec_info->add_sidecar(card, dai_links, codec_conf); + if (ret) + return ret; + } } - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - ret = sdw_enable_stream(sdw_stream); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - ret = sdw_disable_stream(sdw_stream); - break; - default: - ret = -EINVAL; - break; - } + for_each_pcm_streams(stream) { + static const char * const sdw_stream_name[] = { + "SDW%d-Playback", + "SDW%d-Capture", + "SDW%d-Playback-%s", + "SDW%d-Capture-%s", + }; + struct snd_soc_dai_link_ch_map *codec_maps; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + struct snd_soc_dai_link_component *platform; + int num_cpus = hweight32(sof_dai->link_mask[stream]); + int num_codecs = sof_dai->num_devs[stream]; + int playback, capture; + int cur_link = 0; + int i = 0, j = 0; + char *name; - if (ret) - dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret); + if (!sof_dai->num_devs[stream]) + continue; - return ret; -} + sof_end = list_first_entry(&sof_dai->endpoints, + struct asoc_sdw_endpoint, list); -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link_ch_map *ch_maps; - int ch = params_channels(params); - unsigned int ch_mask; - int num_codecs; - int step; - int i; - - if (!rtd->dai_link->ch_maps) - return 0; - - /* Identical data will be sent to all codecs in playback */ - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ch_mask = GENMASK(ch - 1, 0); - step = 0; - } else { - num_codecs = rtd->dai_link->num_codecs; - - if (ch < num_codecs || ch % num_codecs != 0) { - dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n", - ch, num_codecs); + *be_id = sof_end->dai_info->dailink[stream]; + if (*be_id < 0) { + dev_err(dev, "Invalid dailink id %d\n", *be_id); return -EINVAL; } - ch_mask = GENMASK(ch / num_codecs - 1, 0); - step = hweight_long(ch_mask); - - } - - /* - * The captured data will be combined from each cpu DAI if the dai - * link has more than one codec DAIs. Set codec channel mask and - * ASoC will set the corresponding channel numbers for each cpu dai. - */ - for_each_link_ch_maps(rtd->dai_link, i, ch_maps) - ch_maps->ch_mask = ch_mask << (i * step); - - return 0; -} - -int sdw_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct sdw_stream_runtime *sdw_stream; - struct snd_soc_dai *dai; - - /* Find stream from first CPU DAI */ - dai = snd_soc_rtd_to_cpu(rtd, 0); - - sdw_stream = snd_soc_dai_get_stream(dai, substream->stream); - if (IS_ERR(sdw_stream)) { - dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name); - return PTR_ERR(sdw_stream); - } - - return sdw_deprepare_stream(sdw_stream); -} - -void sdw_shutdown(struct snd_pcm_substream *substream) -{ - sdw_shutdown_stream(substream); -} - -static const struct snd_soc_ops sdw_ops = { - .startup = sdw_startup, - .prepare = sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = sdw_hw_free, - .shutdown = sdw_shutdown, -}; - -static struct sof_sdw_codec_info codec_info_list[] = { - { - .part_id = 0x700, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt700-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = rt700_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x711, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x711, - .version_id = 2, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt711-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt711_init, - .exit = sof_sdw_rt711_exit, - .rtd_init = rt711_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x712, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - }, - { - .direction = {true, false}, - .dai_name = "rt712-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .rtd_init = rt712_spk_rtd_init, - }, - }, - .dai_num = 2, - }, - { - .part_id = 0x1712, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt712_sdca_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x713, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt712-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - .rtd_init = rt_sdca_jack_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1713, - .version_id = 3, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt712-sdca-dmic-aif1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt712_sdca_dmic_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1308, - .acpi_id = "10EC1308", - .dais = { - { - .direction = {true, false}, - .dai_name = "rt1308-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - }, - }, - .dai_num = 1, - .ops = &sof_sdw_rt1308_i2s_ops, - }, - { - .part_id = 0x1316, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1316-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x1318, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt1318-aif", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_rt_amp_init, - .exit = sof_sdw_rt_amp_exit, - .rtd_init = rt_amp_spk_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x714, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_sdca_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 3, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_sdca_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x714, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x715, - .version_id = 2, - .ignore_pch_dmic = true, - .dais = { - { - .direction = {false, true}, - .dai_name = "rt715-aif2", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = rt715_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x722, - .version_id = 3, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt722-sdca-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = sof_sdw_rt_sdca_jack_init, - .exit = sof_sdw_rt_sdca_jack_exit, - }, - { - .direction = {true, false}, - .dai_name = "rt722-sdca-aif2", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - /* No feedback capability is provided by rt722-sdca codec driver*/ - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_rt722_spk_init, - }, - { - .direction = {false, true}, - .dai_name = "rt722-sdca-aif3", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .init = sof_sdw_rt722_sdca_dmic_init, - }, - }, - .dai_num = 3, - }, - { - .part_id = 0x8373, - .dais = { - { - .direction = {true, true}, - .dai_name = "max98373-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_maxim_init, - .rtd_init = maxim_spk_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x8363, - .dais = { - { - .direction = {true, false}, - .dai_name = "max98363-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .init = sof_sdw_maxim_init, - .rtd_init = maxim_spk_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x5682, - .dais = { - { - .direction = {true, true}, - .dai_name = "rt5682-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = rt5682_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x3556, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs35l56-sdw1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = sof_sdw_cs_amp_init, - .rtd_init = cs_spk_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x4242, - .dais = { - { - .direction = {true, true}, - .dai_name = "cs42l42-sdw", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .rtd_init = cs42l42_rtd_init, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x4243, - .codec_name = "cs42l43-codec", - .dais = { - { - .direction = {true, false}, - .dai_name = "cs42l43-dp5", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_UNUSED_DAI_ID}, - .rtd_init = cs42l43_hs_rtd_init, - }, - { - .direction = {false, true}, - .dai_name = "cs42l43-dp1", - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .rtd_init = cs42l43_dmic_rtd_init, - }, - { - .direction = {false, true}, - .dai_name = "cs42l43-dp2", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_UNUSED_DAI_ID, SDW_JACK_IN_DAI_ID}, - }, - }, - .dai_num = 3, - }, - { - .part_id = 0xaaaa, /* generic codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = NULL, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0xaa55, /* headset codec mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_JACK, - .dailink = {SDW_JACK_OUT_DAI_ID, SDW_JACK_IN_DAI_ID}, - .init = NULL, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x55aa, /* amplifier mockup */ - .version_id = 0, - .dais = { - { - .direction = {true, true}, - .dai_name = "sdw-mockup-aif1", - .dai_type = SOF_SDW_DAI_TYPE_AMP, - .dailink = {SDW_AMP_OUT_DAI_ID, SDW_AMP_IN_DAI_ID}, - .init = NULL, - }, - }, - .dai_num = 1, - }, - { - .part_id = 0x5555, - .version_id = 0, - .dais = { - { - .dai_name = "sdw-mockup-aif1", - .direction = {false, true}, - .dai_type = SOF_SDW_DAI_TYPE_MIC, - .dailink = {SDW_UNUSED_DAI_ID, SDW_DMIC_DAI_ID}, - .init = NULL, - }, - }, - .dai_num = 1, - }, -}; - -static inline int find_codec_info_part(const u64 adr) -{ - unsigned int part_id, sdw_version; - int i; - - part_id = SDW_PART_ID(adr); - sdw_version = SDW_VERSION(adr); - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - /* - * A codec info is for all sdw version with the part id if - * version_id is not specified in the codec info. - */ - if (part_id == codec_info_list[i].part_id && - (!codec_info_list[i].version_id || - sdw_version == codec_info_list[i].version_id)) - return i; - - return -EINVAL; - -} - -static inline int find_codec_info_acpi(const u8 *acpi_id) -{ - int i; - - if (!acpi_id[0]) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) - if (!memcmp(codec_info_list[i].acpi_id, acpi_id, ACPI_ID_LEN)) - return i; - - return -EINVAL; -} - -/* - * get BE dailink number and CPU DAI number based on sdw link adr. - * Since some sdw slaves may be aggregated, the CPU DAI number - * may be larger than the number of BE dailinks. - */ -static int get_dailink_info(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - int *sdw_be_num, int *codecs_num) -{ - bool group_visited[SDW_MAX_GROUPS]; - bool no_aggregation; - int i; - int j; - - no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - *sdw_be_num = 0; + /* create stream name according to first link id */ + if (ctx->append_dai_type) + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream + 2], + ffs(sof_end->link_mask) - 1, + type_strings[sof_end->dai_info->dai_type]); + else + name = devm_kasprintf(dev, GFP_KERNEL, + sdw_stream_name[stream], + ffs(sof_end->link_mask) - 1); + if (!name) + return -ENOMEM; - if (!adr_link) - return -EINVAL; + cpus = devm_kcalloc(dev, num_cpus, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; - for (i = 0; i < SDW_MAX_GROUPS; i++) - group_visited[i] = false; + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; - for (; adr_link->num_adr; adr_link++) { - const struct snd_soc_acpi_endpoint *endpoint; - struct sof_sdw_codec_info *codec_info; - int codec_index; - int stream; - u64 adr; + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!platform) + return -ENOMEM; - /* make sure the link mask has a single bit set */ - if (!is_power_of_2(adr_link->mask)) - return -EINVAL; + codec_maps = devm_kcalloc(dev, num_codecs, sizeof(*codec_maps), GFP_KERNEL); + if (!codec_maps) + return -ENOMEM; - for (i = 0; i < adr_link->num_adr; i++) { - adr = adr_link->adr_d[i].adr; - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (!sof_end->dai_info->direction[stream]) + continue; - codec_info = &codec_info_list[codec_index]; + if (cur_link != sof_end->link_mask) { + int link_num = ffs(sof_end->link_mask) - 1; + int pin_num = intel_ctx->sdw_pin_index[link_num]++; - *codecs_num += codec_info->dai_num; + cur_link = sof_end->link_mask; - if (!adr_link->adr_d[i].name_prefix) { - dev_err(dev, "codec 0x%llx does not have a name prefix\n", - adr_link->adr_d[i].adr); - return -EINVAL; + cpus[i].dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SDW%d Pin%d", + link_num, pin_num); + if (!cpus[i].dai_name) + return -ENOMEM; + i++; } - endpoint = adr_link->adr_d[i].endpoints; - if (endpoint->aggregated && !endpoint->group_id) { - dev_err(dev, "invalid group id on link %x\n", - adr_link->mask); - return -EINVAL; - } + codec_maps[j].cpu = i - 1; + codec_maps[j].codec = j; - for (j = 0; j < codec_info->dai_num; j++) { - /* count DAI number for playback and capture */ - for_each_pcm_streams(stream) { - if (!codec_info->dais[j].direction[stream]) - continue; - - /* count BE for each non-aggregated slave or group */ - if (!endpoint->aggregated || no_aggregation || - !group_visited[endpoint->group_id]) - (*sdw_be_num)++; - } + codecs[j].name = sof_end->codec_name; + codecs[j].dai_name = sof_end->dai_info->dai_name; + if (sof_end->dai_info->dai_type == SOC_SDW_DAI_TYPE_MIC && + mach_params->dmic_num > 0) { + dev_warn(dev, + "Both SDW DMIC and PCH DMIC are present, if incorrect, please set kernel params snd_sof_intel_hda_generic dmic_num=0 to disable PCH DMIC\n"); } - - if (endpoint->aggregated) - group_visited[endpoint->group_id] = true; + j++; } - } - - return 0; -} - -static void init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - struct snd_soc_dai_link_component *cpus, int cpus_num, - struct snd_soc_dai_link_component *codecs, int codecs_num, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - dev_dbg(dev, "create dai link %s, id %d\n", name, *be_id); - dai_links->id = (*be_id)++; - dai_links->name = name; - dai_links->platforms = platform_component; - dai_links->num_platforms = ARRAY_SIZE(platform_component); - dai_links->no_pcm = 1; - dai_links->cpus = cpus; - dai_links->num_cpus = cpus_num; - dai_links->codecs = codecs; - dai_links->num_codecs = codecs_num; - dai_links->dpcm_playback = playback; - dai_links->dpcm_capture = capture; - dai_links->init = init; - dai_links->ops = ops; -} -static int init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links, - int *be_id, char *name, int playback, int capture, - const char *cpu_dai_name, - const char *codec_name, const char *codec_dai_name, - int (*init)(struct snd_soc_pcm_runtime *rtd), - const struct snd_soc_ops *ops) -{ - struct snd_soc_dai_link_component *dlc; + WARN_ON(i != num_cpus || j != num_codecs); - /* Allocate two DLCs one for the CPU, one for the CODEC */ - dlc = devm_kcalloc(dev, 2, sizeof(*dlc), GFP_KERNEL); - if (!dlc || !name || !cpu_dai_name || !codec_name || !codec_dai_name) - return -ENOMEM; + playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); + capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - dlc[0].dai_name = cpu_dai_name; + asoc_sdw_init_dai_link(dev, *dai_links, be_id, name, playback, capture, + cpus, num_cpus, platform, 1, codecs, num_codecs, + 1, asoc_sdw_rtd_init, &sdw_ops); - dlc[1].name = codec_name; - dlc[1].dai_name = codec_dai_name; + /* + * SoundWire DAILINKs use 'stream' functions and Bank Switch operations + * based on wait_for_completion(), tag them as 'nonatomic'. + */ + (*dai_links)->nonatomic = true; + (*dai_links)->ch_maps = codec_maps; + + list_for_each_entry(sof_end, &sof_dai->endpoints, list) { + if (sof_end->dai_info->init) + sof_end->dai_info->init(card, *dai_links, + sof_end->codec_info, + playback); + } - init_dai_link(dev, dai_links, be_id, name, playback, capture, - &dlc[0], 1, &dlc[1], 1, init, ops); + (*dai_links)++; + } return 0; } -static bool is_unique_device(const struct snd_soc_acpi_link_adr *adr_link, - unsigned int sdw_version, - unsigned int mfg_id, - unsigned int part_id, - unsigned int class_id, - int index_in_link) +static int create_sdw_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_dailink *sof_dais, + struct snd_soc_codec_conf **codec_conf) { - int i; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + int ret, i; - for (i = 0; i < adr_link->num_adr; i++) { - unsigned int sdw1_version, mfg1_id, part1_id, class1_id; - u64 adr; + for (i = 0; i < SDW_INTEL_MAX_LINKS; i++) + intel_ctx->sdw_pin_index[i] = SOC_SDW_INTEL_BIDIR_PDI_BASE; - /* skip itself */ - if (i == index_in_link) - continue; + /* generate DAI links by each sdw link */ + while (sof_dais->initialised) { + int current_be_id = 0; - adr = adr_link->adr_d[i].adr; + ret = create_sdw_dailink(card, sof_dais, dai_links, + ¤t_be_id, codec_conf); + if (ret) + return ret; - sdw1_version = SDW_VERSION(adr); - mfg1_id = SDW_MFG_ID(adr); - part1_id = SDW_PART_ID(adr); - class1_id = SDW_CLASS_ID(adr); + /* Update the be_id to match the highest ID used for SDW link */ + if (*be_id < current_be_id) + *be_id = current_be_id; - if (sdw_version == sdw1_version && - mfg_id == mfg1_id && - part_id == part1_id && - class_id == class1_id) - return false; + sof_dais++; } - return true; -} - -static int fill_sdw_codec_dlc(struct device *dev, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link_component *codec, - int adr_index, int dai_index) -{ - unsigned int sdw_version, unique_id, mfg_id, link_id, part_id, class_id; - u64 adr = adr_link->adr_d[adr_index].adr; - int codec_index; - - codec_index = find_codec_info_part(adr); - if (codec_index < 0) - return codec_index; - - sdw_version = SDW_VERSION(adr); - link_id = SDW_DISCO_LINK_ID(adr); - unique_id = SDW_UNIQUE_ID(adr); - mfg_id = SDW_MFG_ID(adr); - part_id = SDW_PART_ID(adr); - class_id = SDW_CLASS_ID(adr); - - if (codec_info_list[codec_index].codec_name) - codec->name = devm_kstrdup(dev, - codec_info_list[codec_index].codec_name, - GFP_KERNEL); - else if (is_unique_device(adr_link, sdw_version, mfg_id, part_id, - class_id, adr_index)) - codec->name = devm_kasprintf(dev, GFP_KERNEL, - "sdw:0:%01x:%04x:%04x:%02x", link_id, - mfg_id, part_id, class_id); - else - codec->name = devm_kasprintf(dev, GFP_KERNEL, - "sdw:0:%01x:%04x:%04x:%02x:%01x", link_id, - mfg_id, part_id, class_id, unique_id); - - if (!codec->name) - return -ENOMEM; - - codec->dai_name = codec_info_list[codec_index].dais[dai_index].dai_name; - return 0; } -static int set_codec_init_func(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_dai_link *dai_links, - bool playback, int group_id, int adr_index, int dai_index) +static int create_ssp_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_codec_info *ssp_info, + unsigned long ssp_mask) { - int i = adr_index; + struct device *dev = card->dev; + int i, j = 0; + int ret; - do { - /* - * Initialize the codec. If codec is part of an aggregated - * group (group_id>0), initialize all codecs belonging to - * same group. - * The first link should start with adr_link->adr_d[adr_index] - * because that is the device that we want to initialize and - * we should end immediately if it is not aggregated (group_id=0) - */ - for ( ; i < adr_link->num_adr; i++) { - int codec_index; + for_each_set_bit(i, &ssp_mask, BITS_PER_TYPE(ssp_mask)) { + char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); + char *codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", + ssp_info->acpi_id, j++); + if (!name || !cpu_dai_name || !codec_name) + return -ENOMEM; - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; + int playback = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; + int capture = ssp_info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - /* The group_id is > 0 iff the codec is aggregated */ - if (adr_link->adr_d[i].endpoints->group_id != group_id) - continue; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + playback, capture, cpu_dai_name, + "dummy", codec_name, + ssp_info->dais[0].dai_name, 1, NULL, + ssp_info->ops); + if (ret) + return ret; - if (codec_info_list[codec_index].dais[dai_index].init) - codec_info_list[codec_index].dais[dai_index].init(card, - adr_link, - dai_links, - &codec_info_list[codec_index], - playback); - if (!group_id) - return 0; - } + ret = ssp_info->dais[0].init(card, *dai_links, ssp_info, 0); + if (ret < 0) + return ret; - i = 0; - adr_link++; - } while (adr_link->mask); + (*dai_links)++; + } return 0; } -/* - * check endpoint status in slaves and gather link ID for all slaves in - * the same group to generate different CPU DAI. Now only support - * one sdw link with all slaves set with only single group id. - * - * one slave on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> one-codec DAI - * - * two or more slaves on one sdw link with aggregated = 0 - * one sdw BE DAI <---> one-cpu DAI <---> multi-codec DAIs - * - * multiple links with multiple slaves with aggregated = 1 - * one sdw BE DAI <---> 1 .. N CPU DAIs <----> 1 .. N codec DAIs - */ -static int get_slave_info(const struct snd_soc_acpi_link_adr *adr_link, - struct device *dev, int *cpu_dai_id, int *cpu_dai_num, - int *codec_num, unsigned int *group_id, - int adr_index) +static int create_dmic_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) { - bool no_aggregation = sof_sdw_quirk & SOF_SDW_NO_AGGREGATION; - int i; - - if (!adr_link->adr_d[adr_index].endpoints->aggregated || no_aggregation) { - cpu_dai_id[0] = ffs(adr_link->mask) - 1; - *cpu_dai_num = 1; - *codec_num = 1; - *group_id = 0; - return 0; - } - - *codec_num = 0; - *cpu_dai_num = 0; - *group_id = adr_link->adr_d[adr_index].endpoints->group_id; - - /* Count endpoints with the same group_id in the adr_link */ - for (; adr_link && adr_link->num_adr; adr_link++) { - unsigned int link_codecs = 0; + struct device *dev = card->dev; + int ret; - for (i = 0; i < adr_link->num_adr; i++) { - if (adr_link->adr_d[i].endpoints->aggregated && - adr_link->adr_d[i].endpoints->group_id == *group_id) - link_codecs++; - } + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic01", + 0, 1, // DMIC only supports capture + "DMIC01 Pin", "dummy", + "dmic-codec", "dmic-hifi", 1, + asoc_sdw_dmic_init, NULL); + if (ret) + return ret; - if (link_codecs) { - *codec_num += link_codecs; + (*dai_links)++; - if (*cpu_dai_num >= SDW_MAX_CPU_DAIS) { - dev_err(dev, "cpu_dai_id array overflowed\n"); - return -EINVAL; - } + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, "dmic16k", + 0, 1, // DMIC only supports capture + "DMIC16k Pin", "dummy", + "dmic-codec", "dmic-hifi", 1, + /* don't call asoc_sdw_dmic_init() twice */ + NULL, NULL); + if (ret) + return ret; - cpu_dai_id[(*cpu_dai_num)++] = ffs(adr_link->mask) - 1; - } - } + (*dai_links)++; return 0; } -static void set_dailink_map(struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps, - int codec_num, int cpu_num) +static int create_hdmi_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + int hdmi_num) { - int step; - int i; + struct device *dev = card->dev; + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; + int i, ret; - step = codec_num / cpu_num; - for (i = 0; i < codec_num; i++) { - sdw_codec_ch_maps[i].cpu = i / step; - sdw_codec_ch_maps[i].codec = i; - } -} + for (i = 0; i < hdmi_num; i++) { + char *name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); + if (!name || !cpu_dai_name) + return -ENOMEM; -static inline int find_codec_info_dai(const char *dai_name, int *dai_index) -{ - int i, j; + char *codec_name, *codec_dai_name; - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - if (!strcmp(codec_info_list[i].dais[j].dai_name, dai_name)) { - *dai_index = j; - return i; - } + if (intel_ctx->hdmi.idisp_codec) { + codec_name = "ehdaudio0D2"; + codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, + "intel-hdmi-hifi%d", i + 1); + } else { + codec_name = "snd-soc-dummy"; + codec_dai_name = "snd-soc-dummy-dai"; } - } - return -EINVAL; -} - -static int sof_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct sof_sdw_codec_info *codec_info; - struct snd_soc_dai *dai; - int codec_index; - int dai_index; - int ret; - int i; + if (!codec_dai_name) + return -ENOMEM; - for_each_rtd_codec_dais(rtd, i, dai) { - codec_index = find_codec_info_dai(dai->name, &dai_index); - if (codec_index < 0) - return -EINVAL; + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 0, // HDMI only supports playback + cpu_dai_name, "dummy", + codec_name, codec_dai_name, 1, + i == 0 ? sof_sdw_hdmi_init : NULL, NULL); + if (ret) + return ret; - codec_info = &codec_info_list[codec_index]; - /* - * A codec dai can be connected to different dai links for capture and playback, - * but we only need to call the rtd_init function once. - * The rtd_init for each codec dai is independent. So, the order of rtd_init - * doesn't matter. - */ - if (codec_info->dais[dai_index].rtd_init_done) - continue; - if (codec_info->dais[dai_index].rtd_init) { - ret = codec_info->dais[dai_index].rtd_init(rtd); - if (ret) - return ret; - } - codec_info->dais[dai_index].rtd_init_done = true; + (*dai_links)++; } return 0; } -static const char * const type_strings[] = {"SimpleJack", "SmartAmp", "SmartMic"}; - -static int create_sdw_dailink(struct snd_soc_card *card, int *link_index, - struct snd_soc_dai_link *dai_links, int sdw_be_num, - const struct snd_soc_acpi_link_adr *adr_link, - struct snd_soc_codec_conf *codec_conf, - int codec_count, int *be_id, - int *codec_conf_index, - bool *ignore_pch_dmic, - bool append_dai_type, - int adr_index, - int dai_index) +static int create_bt_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); struct device *dev = card->dev; - const struct snd_soc_acpi_link_adr *adr_link_next; - struct snd_soc_dai_link_component *codecs; - struct snd_soc_dai_link_component *cpus; - struct sof_sdw_codec_info *codec_info; - int cpu_dai_id[SDW_MAX_CPU_DAIS]; - int cpu_dai_num; - unsigned int group_id; - int codec_dlc_index = 0; - int codec_index; - int codec_num; - int stream; - int i = 0; - int j, k; + int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> + SOF_BT_OFFLOAD_SSP_SHIFT; + char *name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); + char *cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); + if (!name || !cpu_dai_name) + return -ENOMEM; + int ret; - ret = get_slave_info(adr_link, dev, cpu_dai_id, &cpu_dai_num, &codec_num, - &group_id, adr_index); + ret = asoc_sdw_init_simple_dai_link(dev, *dai_links, be_id, name, + 1, 1, cpu_dai_name, "dummy", + snd_soc_dummy_dlc.name, snd_soc_dummy_dlc.dai_name, + 1, NULL, NULL); if (ret) return ret; - codecs = devm_kcalloc(dev, codec_num, sizeof(*codecs), GFP_KERNEL); - if (!codecs) - return -ENOMEM; - - /* generate codec name on different links in the same group */ - j = adr_index; - for (adr_link_next = adr_link; adr_link_next && adr_link_next->num_adr && - i < cpu_dai_num; adr_link_next++) { - /* skip the link excluded by this processed group */ - if (cpu_dai_id[i] != ffs(adr_link_next->mask) - 1) - continue; - - /* j reset after loop, adr_index only applies to first link */ - for (; j < adr_link_next->num_adr && codec_dlc_index < codec_num; j++) { - const struct snd_soc_acpi_endpoint *endpoints; - - endpoints = adr_link_next->adr_d[j].endpoints; - - if (group_id && (!endpoints->aggregated || - endpoints->group_id != group_id)) - continue; - - /* sanity check */ - if (*codec_conf_index >= codec_count) { - dev_err(dev, "codec_conf array overflowed\n"); - return -EINVAL; - } - - ret = fill_sdw_codec_dlc(dev, adr_link_next, - &codecs[codec_dlc_index], - j, dai_index); - if (ret) - return ret; - - codec_conf[*codec_conf_index].dlc = codecs[codec_dlc_index]; - codec_conf[*codec_conf_index].name_prefix = - adr_link_next->adr_d[j].name_prefix; - - codec_dlc_index++; - (*codec_conf_index)++; - } - j = 0; - - /* check next link to create codec dai in the processed group */ - i++; - } - - /* find codec info to create BE DAI */ - codec_index = find_codec_info_part(adr_link->adr_d[adr_index].adr); - if (codec_index < 0) - return codec_index; - codec_info = &codec_info_list[codec_index]; - - if (codec_info->ignore_pch_dmic) - *ignore_pch_dmic = true; - - for_each_pcm_streams(stream) { - struct snd_soc_dai_link_ch_map *sdw_codec_ch_maps; - char *name, *cpu_name; - int playback, capture; - static const char * const sdw_stream_name[] = { - "SDW%d-Playback", - "SDW%d-Capture", - "SDW%d-Playback-%s", - "SDW%d-Capture-%s", - }; - - if (!codec_info->dais[dai_index].direction[stream]) - continue; - - *be_id = codec_info->dais[dai_index].dailink[stream]; - if (*be_id < 0) { - dev_err(dev, "Invalid dailink id %d\n", *be_id); - return -EINVAL; - } - - sdw_codec_ch_maps = devm_kcalloc(dev, codec_num, - sizeof(*sdw_codec_ch_maps), GFP_KERNEL); - if (!sdw_codec_ch_maps) - return -ENOMEM; - - /* create stream name according to first link id */ - if (append_dai_type) { - name = devm_kasprintf(dev, GFP_KERNEL, - sdw_stream_name[stream + 2], cpu_dai_id[0], - type_strings[codec_info->dais[dai_index].dai_type]); - } else { - name = devm_kasprintf(dev, GFP_KERNEL, - sdw_stream_name[stream], cpu_dai_id[0]); - } - if (!name) - return -ENOMEM; - - cpus = devm_kcalloc(dev, cpu_dai_num, sizeof(*cpus), GFP_KERNEL); - if (!cpus) - return -ENOMEM; - - /* - * generate CPU DAI name base on the sdw link ID and - * PIN ID with offset of 2 according to sdw dai driver. - */ - for (k = 0; k < cpu_dai_num; k++) { - cpu_name = devm_kasprintf(dev, GFP_KERNEL, - "SDW%d Pin%d", cpu_dai_id[k], - ctx->sdw_pin_index[cpu_dai_id[k]]++); - if (!cpu_name) - return -ENOMEM; - - cpus[k].dai_name = cpu_name; - } - - /* - * We create sdw dai links at first stage, so link index should - * not be larger than sdw_be_num - */ - if (*link_index >= sdw_be_num) { - dev_err(dev, "invalid dai link index %d\n", *link_index); - return -EINVAL; - } - - playback = (stream == SNDRV_PCM_STREAM_PLAYBACK); - capture = (stream == SNDRV_PCM_STREAM_CAPTURE); - - init_dai_link(dev, dai_links + *link_index, be_id, name, - playback, capture, cpus, cpu_dai_num, codecs, codec_num, - sof_sdw_rtd_init, &sdw_ops); - - /* - * SoundWire DAILINKs use 'stream' functions and Bank Switch operations - * based on wait_for_completion(), tag them as 'nonatomic'. - */ - dai_links[*link_index].nonatomic = true; - - set_dailink_map(sdw_codec_ch_maps, codec_num, cpu_dai_num); - dai_links[*link_index].ch_maps = sdw_codec_ch_maps; - ret = set_codec_init_func(card, adr_link, dai_links + (*link_index)++, - playback, group_id, adr_index, dai_index); - if (ret < 0) { - dev_err(dev, "failed to init codec %d\n", codec_index); - return ret; - } - } + (*dai_links)++; return 0; } @@ -1644,46 +1128,64 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev); int sdw_be_num = 0, ssp_num = 0, dmic_num = 0, bt_num = 0; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; - const struct snd_soc_acpi_link_adr *adr_link = mach_params->links; - bool aggregation = !(sof_sdw_quirk & SOF_SDW_NO_AGGREGATION); struct snd_soc_codec_conf *codec_conf; - bool append_dai_type = false; - bool ignore_pch_dmic = false; - int codec_conf_num = 0; - int codec_conf_index = 0; - bool group_generated[SDW_MAX_GROUPS] = { }; - int ssp_codec_index, ssp_mask; + struct asoc_sdw_codec_info *ssp_info; + struct asoc_sdw_endpoint *sof_ends; + struct asoc_sdw_dailink *sof_dais; + int num_devs = 0; + int num_ends = 0; struct snd_soc_dai_link *dai_links; - int num_links, link_index = 0; - char *name, *cpu_dai_name; - char *codec_name, *codec_dai_name; - int i, j, be_id = 0; - int codec_index; + int num_links; + int be_id = 0; int hdmi_num; + unsigned long ssp_mask; int ret; - ret = get_dailink_info(dev, adr_link, &sdw_be_num, &codec_conf_num); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends); if (ret < 0) { - dev_err(dev, "failed to get sdw link info %d\n", ret); + dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; } /* + * One per DAI link, worst case is a DAI link for every endpoint, also + * add one additional to act as a terminator such that code can iterate + * until it hits an uninitialised DAI. + */ + sof_dais = kcalloc(num_ends + 1, sizeof(*sof_dais), GFP_KERNEL); + if (!sof_dais) + return -ENOMEM; + + /* One per endpoint, ie. each DAI on each codec/amp */ + sof_ends = kcalloc(num_ends, sizeof(*sof_ends), GFP_KERNEL); + if (!sof_ends) { + ret = -ENOMEM; + goto err_dai; + } + + ret = asoc_sdw_parse_sdw_endpoints(card, sof_dais, sof_ends, &num_devs); + if (ret < 0) + goto err_end; + + sdw_be_num = ret; + + /* * on generic tgl platform, I2S or sdw mode is supported * based on board rework. A ACPI device is registered in * system only when I2S mode is supported, not sdw mode. * Here check ACPI ID to confirm I2S is supported. */ - ssp_codec_index = find_codec_info_acpi(mach->id); - if (ssp_codec_index >= 0) { + ssp_info = asoc_sdw_find_codec_info_acpi(mach->id); + if (ssp_info) { ssp_mask = SOF_SSP_GET_PORT(sof_sdw_quirk); ssp_num = hweight_long(ssp_mask); } if (mach_params->codec_mask & IDISP_CODEC_MASK) - ctx->hdmi.idisp_codec = true; + intel_ctx->hdmi.idisp_codec = true; if (sof_sdw_quirk & SOF_SDW_TGL_HDMI) hdmi_num = SOF_TGL_HDMI_COUNT; @@ -1691,313 +1193,144 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) hdmi_num = SOF_PRE_TGL_HDMI_COUNT; /* enable dmic01 & dmic16k */ - if (sof_sdw_quirk & SOF_SDW_PCH_DMIC || mach_params->dmic_num) + if (ctx->ignore_internal_dmic) { + dev_dbg(dev, "SoundWire DMIC is used, ignoring internal DMIC\n"); + mach_params->dmic_num = 0; + } else if (mach_params->dmic_num) { + dmic_num = 2; + } else if (sof_sdw_quirk & SOC_SDW_PCH_DMIC) { dmic_num = 2; + /* + * mach_params->dmic_num will be used to set the cfg-mics value of + * card->components string. Set it to the default value. + */ + mach_params->dmic_num = DMIC_DEFAULT_CHANNELS; + } if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) bt_num = 1; - dev_dbg(dev, "sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", + dev_dbg(dev, "DAI link numbers: sdw %d, ssp %d, dmic %d, hdmi %d, bt: %d\n", sdw_be_num, ssp_num, dmic_num, - ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); + intel_ctx->hdmi.idisp_codec ? hdmi_num : 0, bt_num); + + codec_conf = devm_kcalloc(dev, num_devs, sizeof(*codec_conf), GFP_KERNEL); + if (!codec_conf) { + ret = -ENOMEM; + goto err_end; + } /* allocate BE dailinks */ num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num; dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); - if (!dai_links) - return -ENOMEM; - - /* allocate codec conf, will be populated when dailinks are created */ - codec_conf = devm_kcalloc(dev, codec_conf_num, sizeof(*codec_conf), - GFP_KERNEL); - if (!codec_conf) - return -ENOMEM; - - /* SDW */ - if (!sdw_be_num) - goto SSP; - - for (i = 0; i < SDW_MAX_LINKS; i++) - ctx->sdw_pin_index[i] = SDW_INTEL_BIDIR_PDI_BASE; - - for (; adr_link->num_adr; adr_link++) { - /* - * If there are two or more different devices on the same sdw link, we have to - * append the codec type to the dai link name to prevent duplicated dai link name. - * The same type devices on the same sdw link will be in the same - * snd_soc_acpi_adr_device array. They won't be described in different adr_links. - */ - for (i = 0; i < adr_link->num_adr; i++) { - /* find codec info to get dai_num */ - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; - if (codec_info_list[codec_index].dai_num > 1) { - append_dai_type = true; - goto out; - } - for (j = 0; j < i; j++) { - if ((SDW_PART_ID(adr_link->adr_d[i].adr) != - SDW_PART_ID(adr_link->adr_d[j].adr)) || - (SDW_MFG_ID(adr_link->adr_d[i].adr) != - SDW_MFG_ID(adr_link->adr_d[j].adr))) { - append_dai_type = true; - goto out; - } - } - } + if (!dai_links) { + ret = -ENOMEM; + goto err_end; } -out: - /* generate DAI links by each sdw link */ - for (adr_link = mach_params->links ; adr_link->num_adr; adr_link++) { - for (i = 0; i < adr_link->num_adr; i++) { - const struct snd_soc_acpi_endpoint *endpoint; - - endpoint = adr_link->adr_d[i].endpoints; - - /* this group has been generated */ - if (endpoint->aggregated && - group_generated[endpoint->group_id]) - continue; - - /* find codec info to get dai_num */ - codec_index = find_codec_info_part(adr_link->adr_d[i].adr); - if (codec_index < 0) - return codec_index; - - for (j = 0; j < codec_info_list[codec_index].dai_num ; j++) { - int current_be_id; - - ret = create_sdw_dailink(card, &link_index, dai_links, - sdw_be_num, adr_link, - codec_conf, codec_conf_num, - ¤t_be_id, &codec_conf_index, - &ignore_pch_dmic, append_dai_type, i, j); - if (ret < 0) { - dev_err(dev, "failed to create dai link %d\n", link_index); - return ret; - } - - /* Update the be_id to match the highest ID used for SDW link */ - if (be_id < current_be_id) - be_id = current_be_id; - } + card->codec_conf = codec_conf; + card->num_configs = num_devs; + card->dai_link = dai_links; + card->num_links = num_links; - if (aggregation && endpoint->aggregated) - group_generated[endpoint->group_id] = true; - } + /* SDW */ + if (sdw_be_num) { + ret = create_sdw_dailinks(card, &dai_links, &be_id, + sof_dais, &codec_conf); + if (ret) + goto err_end; } -SSP: /* SSP */ - if (!ssp_num) - goto DMIC; - - for (i = 0, j = 0; ssp_mask; i++, ssp_mask >>= 1) { - struct sof_sdw_codec_info *info; - int playback, capture; - - if (!(ssp_mask & 0x1)) - continue; - - info = &codec_info_list[ssp_codec_index]; - - name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", i); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", i); - codec_name = devm_kasprintf(dev, GFP_KERNEL, "i2c-%s:0%d", - info->acpi_id, j++); - - playback = info->dais[0].direction[SNDRV_PCM_STREAM_PLAYBACK]; - capture = info->dais[0].direction[SNDRV_PCM_STREAM_CAPTURE]; - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - playback, capture, cpu_dai_name, - codec_name, info->dais[0].dai_name, - NULL, info->ops); + if (ssp_num) { + ret = create_ssp_dailinks(card, &dai_links, &be_id, + ssp_info, ssp_mask); if (ret) - return ret; - - ret = info->dais[0].init(card, NULL, dai_links + link_index, info, 0); - if (ret < 0) - return ret; - - link_index++; + goto err_end; } -DMIC: /* dmic */ - if (dmic_num > 0) { - if (ignore_pch_dmic) { - dev_warn(dev, "Ignoring PCH DMIC\n"); - goto HDMI; - } - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic01", - 0, 1, // DMIC only supports capture - "DMIC01 Pin", "dmic-codec", "dmic-hifi", - sof_sdw_dmic_init, NULL); + if (dmic_num) { + ret = create_dmic_dailinks(card, &dai_links, &be_id); if (ret) - return ret; - - link_index++; - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, "dmic16k", - 0, 1, // DMIC only supports capture - "DMIC16k Pin", "dmic-codec", "dmic-hifi", - /* don't call sof_sdw_dmic_init() twice */ - NULL, NULL); - if (ret) - return ret; - - link_index++; + goto err_end; } -HDMI: /* HDMI */ - for (i = 0; i < hdmi_num; i++) { - name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", i + 1); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", i + 1); - - if (ctx->hdmi.idisp_codec) { - codec_name = "ehdaudio0D2"; - codec_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "intel-hdmi-hifi%d", i + 1); - } else { - codec_name = "snd-soc-dummy"; - codec_dai_name = "snd-soc-dummy-dai"; - } - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - 1, 0, // HDMI only supports playback - cpu_dai_name, codec_name, codec_dai_name, - i == 0 ? sof_sdw_hdmi_init : NULL, NULL); - if (ret) - return ret; - - link_index++; - } + ret = create_hdmi_dailinks(card, &dai_links, &be_id, hdmi_num); + if (ret) + goto err_end; + /* BT */ if (sof_sdw_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_sdw_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", port); - cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", port); - - ret = init_simple_dai_link(dev, dai_links + link_index, &be_id, name, - 1, 1, cpu_dai_name, snd_soc_dummy_dlc.name, - snd_soc_dummy_dlc.dai_name, NULL, NULL); + ret = create_bt_dailinks(card, &dai_links, &be_id); if (ret) - return ret; + goto err_end; } - card->dai_link = dai_links; - card->num_links = num_links; + WARN_ON(codec_conf != card->codec_conf + card->num_configs); + WARN_ON(dai_links != card->dai_link + card->num_links); - card->codec_conf = codec_conf; - card->num_configs = codec_conf_num; +err_end: + kfree(sof_ends); +err_dai: + kfree(sof_dais); - return 0; + return ret; } static int sof_sdw_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; int ret = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - if (codec_info_list[i].codec_card_late_probe) { - ret = codec_info_list[i].codec_card_late_probe(card); - if (ret < 0) - return ret; - } - } + ret = asoc_sdw_card_late_probe(card); + if (ret < 0) + return ret; - if (ctx->hdmi.idisp_codec) + if (intel_ctx->hdmi.idisp_codec) ret = sof_sdw_hdmi_card_late_probe(card); return ret; } -/* SoC card */ -static const char sdw_card_long_name[] = "Intel Soundwire SOF"; - -static struct snd_soc_card card_sof_sdw = { - .name = "soundwire", - .owner = THIS_MODULE, - .late_probe = sof_sdw_card_late_probe, -}; - -/* helper to get the link that the codec DAI is used */ -static struct snd_soc_dai_link *mc_find_codec_dai_used(struct snd_soc_card *card, - const char *dai_name) -{ - struct snd_soc_dai_link *dai_link; - int i; - int j; - - for_each_card_prelinks(card, i, dai_link) { - for (j = 0; j < dai_link->num_codecs; j++) { - /* Check each codec in a link */ - if (!strcmp(dai_link->codecs[j].dai_name, dai_name)) - return dai_link; - } - } - return NULL; -} - -static void mc_dailink_exit_loop(struct snd_soc_card *card) -{ - struct snd_soc_dai_link *dai_link; - int ret; - int i, j; - - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) { - for (j = 0; j < codec_info_list[i].dai_num; j++) { - codec_info_list[i].dais[j].rtd_init_done = false; - /* Check each dai in codec_info_lis to see if it is used in the link */ - if (!codec_info_list[i].dais[j].exit) - continue; - /* - * We don't need to call .exit function if there is no matched - * dai link found. - */ - dai_link = mc_find_codec_dai_used(card, - codec_info_list[i].dais[j].dai_name); - if (dai_link) { - /* Do the .exit function if the codec dai is used in the link */ - ret = codec_info_list[i].dais[j].exit(card, dai_link); - if (ret) - dev_warn(card->dev, - "codec exit failed %d\n", - ret); - break; - } - } - } -} - static int mc_probe(struct platform_device *pdev) { - struct snd_soc_card *card = &card_sof_sdw; struct snd_soc_acpi_mach *mach = dev_get_platdata(&pdev->dev); - struct mc_private *ctx; + struct snd_soc_card *card; + struct asoc_sdw_mc_private *ctx; + struct intel_mc_ctx *intel_ctx; int amp_num = 0, i; int ret; - card->dev = &pdev->dev; + dev_dbg(&pdev->dev, "Entry\n"); - dev_dbg(card->dev, "Entry\n"); + intel_ctx = devm_kzalloc(&pdev->dev, sizeof(*intel_ctx), GFP_KERNEL); + if (!intel_ctx) + return -ENOMEM; - ctx = devm_kzalloc(card->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; + ctx->private = intel_ctx; + ctx->codec_info_list_count = asoc_sdw_get_codec_info_list_count(); + card = &ctx->card; + card->dev = &pdev->dev; + card->name = "soundwire"; + card->owner = THIS_MODULE; + card->late_probe = sof_sdw_card_late_probe; + snd_soc_card_set_drvdata(card, ctx); + if (mach->mach_params.subsystem_id_set) { + snd_soc_card_set_pci_ssid(card, + mach->mach_params.subsystem_vendor, + mach->mach_params.subsystem_device); + sof_sdw_check_ssid_quirk(mach); + } + dmi_check_system(sof_sdw_quirk_table); if (quirk_override != -1) { @@ -2008,16 +1341,11 @@ static int mc_probe(struct platform_device *pdev) log_quirks(card->dev); + ctx->mc_quirk = sof_sdw_quirk; /* reset amp_num to ensure amp_num++ starts from 0 in each probe */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) codec_info_list[i].amp_num = 0; - if (mach->mach_params.subsystem_id_set) { - snd_soc_card_set_pci_ssid(card, - mach->mach_params.subsystem_vendor, - mach->mach_params.subsystem_device); - } - ret = sof_card_dai_links_create(card); if (ret < 0) return ret; @@ -2027,13 +1355,11 @@ static int mc_probe(struct platform_device *pdev) * amp_num will only be increased for active amp * codecs on used platform */ - for (i = 0; i < ARRAY_SIZE(codec_info_list); i++) + for (i = 0; i < ctx->codec_info_list_count; i++) amp_num += codec_info_list[i].amp_num; card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "cfg-spk:%d cfg-amp:%d", - (sof_sdw_quirk & SOF_SDW_FOUR_SPK) - ? 4 : 2, amp_num); + " cfg-amp:%d", amp_num); if (!card->components) return -ENOMEM; @@ -2046,13 +1372,11 @@ static int mc_probe(struct platform_device *pdev) return -ENOMEM; } - card->long_name = sdw_card_long_name; - /* Register the card */ ret = devm_snd_soc_register_card(card->dev, card); if (ret) { dev_err_probe(card->dev, ret, "snd_soc_register_card failed %d\n", ret); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); return ret; } @@ -2065,7 +1389,7 @@ static void mc_remove(struct platform_device *pdev) { struct snd_soc_card *card = platform_get_drvdata(pdev); - mc_dailink_exit_loop(card); + asoc_sdw_mc_dailink_exit_loop(card); } static const struct platform_device_id mc_id_table[] = { @@ -2080,7 +1404,7 @@ static struct platform_driver sof_sdw_driver = { .pm = &snd_soc_pm_ops, }, .probe = mc_probe, - .remove_new = mc_remove, + .remove = mc_remove, .id_table = mc_id_table, }; @@ -2091,5 +1415,5 @@ MODULE_AUTHOR("Bard Liao <yung-chuan.liao@linux.intel.com>"); MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>"); MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON"); +MODULE_IMPORT_NS("SND_SOC_SDW_UTILS"); diff --git a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h b/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h deleted file mode 100644 index 4a3e6fdbd623..000000000000 --- a/sound/soc/intel/boards/sof_sdw_amp_coeff_tables.h +++ /dev/null @@ -1,300 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only - */ - -/* - * sof_sdw_amp_coeff_tables.h - related coefficients for amplifier parameters - */ - -#ifndef SND_SOC_SOF_SDW_AMP_COEFF_H -#define SND_SOC_SOF_SDW_AMP_COEFF_H - -#define RT1308_MAX_BQ_REG 480 -#define RT1316_MAX_BQ_REG 580 - -static const u8 __maybe_unused dell_0a5d_bq_params[] = { - 0xb0, 0xc5, 0x00, /* address: 0xc5b0; data: 0x00 */ - 0xb1, 0xc5, 0x32, - 0xb2, 0xc5, 0x44, - 0xb3, 0xc5, 0x19, - 0xc0, 0xc5, 0x04, - 0xc1, 0xc5, 0x00, - 0xc2, 0xc5, 0x00, - 0xc3, 0xc5, 0x00, - 0xd0, 0xc5, 0x02, - 0xd1, 0xc5, 0x00, - 0xd2, 0xc5, 0x00, - 0xd3, 0xc5, 0x00, - 0xe0, 0xc5, 0x01, - 0xe1, 0xc5, 0xe8, - 0xe2, 0xc5, 0x5f, - 0xe3, 0xc5, 0x8a, - 0xf0, 0xc5, 0x1f, - 0xf1, 0xc5, 0x4e, - 0xf2, 0xc5, 0x90, - 0xf3, 0xc5, 0x11, - 0x50, 0xc6, 0x01, - 0x51, 0xc6, 0xff, - 0x52, 0xc6, 0x45, - 0x53, 0xc6, 0x41, - 0x60, 0xc6, 0x1c, - 0x61, 0xc6, 0x00, - 0x62, 0xc6, 0x00, - 0x63, 0xc6, 0x00, - 0x70, 0xc6, 0x02, - 0x71, 0xc6, 0x00, - 0x72, 0xc6, 0x00, - 0x73, 0xc6, 0x00, - 0x80, 0xc6, 0x03, - 0x81, 0xc6, 0xfe, - 0x82, 0xc6, 0x89, - 0x83, 0xc6, 0xfa, - 0x90, 0xc6, 0x1e, - 0x91, 0xc6, 0x01, - 0x92, 0xc6, 0x74, - 0x93, 0xc6, 0xf6, - 0x00, 0xc6, 0x01, - 0x01, 0xc6, 0xd9, - 0x02, 0xc6, 0xfb, - 0x03, 0xc6, 0xc4, - 0x10, 0xc6, 0x1c, - 0x11, 0xc6, 0x00, - 0x12, 0xc6, 0x00, - 0x13, 0xc6, 0x00, - 0x20, 0xc6, 0x02, - 0x21, 0xc6, 0x00, - 0x22, 0xc6, 0x00, - 0x23, 0xc6, 0x00, - 0x30, 0xc6, 0x03, - 0x31, 0xc6, 0xaf, - 0x32, 0xc6, 0x23, - 0x33, 0xc6, 0xcb, - 0x40, 0xc6, 0x1e, - 0x41, 0xc6, 0x47, - 0x42, 0xc6, 0x34, - 0x43, 0xc6, 0xba, - 0xa0, 0xc6, 0x01, - 0xa1, 0xc6, 0xff, - 0xa2, 0xc6, 0x45, - 0xa3, 0xc6, 0x41, - 0xb0, 0xc6, 0x1c, - 0xb1, 0xc6, 0x00, - 0xb2, 0xc6, 0x00, - 0xb3, 0xc6, 0x00, - 0xc0, 0xc6, 0x02, - 0xc1, 0xc6, 0x00, - 0xc2, 0xc6, 0x00, - 0xc3, 0xc6, 0x00, - 0xd0, 0xc6, 0x03, - 0xd1, 0xc6, 0xfe, - 0xd2, 0xc6, 0x89, - 0xd3, 0xc6, 0xfa, - 0xe0, 0xc6, 0x1e, - 0xe1, 0xc6, 0x01, - 0xe2, 0xc6, 0x74, - 0xe3, 0xc6, 0xf6, - 0x40, 0xc5, 0x0d, - 0x30, 0xc7, 0x15, - 0x31, 0xc7, 0x7c, - 0x32, 0xc7, 0x0f, - 0x33, 0xc7, 0xa0, - 0x40, 0xc7, 0x00, - 0x41, 0xc7, 0x00, - 0x42, 0xc7, 0xf8, - 0x43, 0xc7, 0xf8, - 0x50, 0xc7, 0x00, - 0x51, 0xc7, 0x00, - 0x52, 0xc7, 0x00, - 0x53, 0xc7, 0x01, - 0x90, 0xc7, 0x00, - 0x91, 0xc7, 0x14, - 0x92, 0xc7, 0x00, - 0x93, 0xc7, 0x14, - 0xa0, 0xc7, 0x00, - 0xa1, 0xc7, 0x00, - 0xa2, 0xc7, 0xf8, - 0xa3, 0xc7, 0xf8, - 0xb0, 0xc7, 0x00, - 0xb1, 0xc7, 0x00, - 0xb2, 0xc7, 0x00, - 0xb3, 0xc7, 0x00, - 0x60, 0xc7, 0x03, - 0x61, 0xc7, 0xe8, - 0x62, 0xc7, 0x03, - 0x63, 0xc7, 0xb6, - 0x70, 0xc7, 0x00, - 0x71, 0xc7, 0x00, - 0x72, 0xc7, 0xf8, - 0x73, 0xc7, 0xf8, - 0x80, 0xc7, 0x00, - 0x81, 0xc7, 0x00, - 0x82, 0xc7, 0x00, - 0x83, 0xc7, 0x00, - 0xc0, 0xc7, 0x00, - 0xc1, 0xc7, 0x14, - 0xc2, 0xc7, 0x00, - 0xc3, 0xc7, 0x14, - 0xd0, 0xc7, 0x00, - 0xd1, 0xc7, 0x00, - 0xd2, 0xc7, 0xf8, - 0xd3, 0xc7, 0xf8, - 0xe0, 0xc7, 0x00, - 0xe1, 0xc7, 0x00, - 0xe2, 0xc7, 0x00, - 0xe3, 0xc7, 0x00, - 0x60, 0xc5, 0x02, - 0x61, 0xc5, 0x00, - 0x62, 0xc5, 0x00, - 0x63, 0xc5, 0x00, - 0x70, 0xc5, 0x02, - 0x71, 0xc5, 0x00, - 0x72, 0xc5, 0x00, - 0x73, 0xc5, 0x00, - 0x80, 0xc5, 0x02, - 0x81, 0xc5, 0x00, - 0x82, 0xc5, 0x00, - 0x83, 0xc5, 0x00, - 0x90, 0xc5, 0x02, - 0x91, 0xc5, 0x00, - 0x92, 0xc5, 0x00, - 0x93, 0xc5, 0x00, - 0x50, 0xc5, 0x01, -}; - -static const u8 __maybe_unused dell_0b00_bq_params[] = { - 0x03, 0xc2, 0x00, - 0x04, 0xc2, 0xb2, - 0x05, 0xc2, 0xe0, - 0x06, 0xc2, 0x3a, - 0x07, 0xc2, 0x01, - 0x08, 0xc2, 0x65, - 0x09, 0xc2, 0xc0, - 0x0a, 0xc2, 0x75, - 0x0b, 0xc2, 0x00, - 0x0c, 0xc2, 0xb2, - 0x0d, 0xc2, 0xe0, - 0x0e, 0xc2, 0x3a, - 0x0f, 0xc2, 0xf7, - 0x10, 0xc2, 0x4d, - 0x11, 0xc2, 0x5b, - 0x12, 0xc2, 0xe9, - 0x13, 0xc2, 0x03, - 0x14, 0xc2, 0x7e, - 0x15, 0xc2, 0x25, - 0x16, 0xc2, 0x01, - 0x17, 0xc2, 0x07, - 0x18, 0xc2, 0xfd, - 0x19, 0xc2, 0x15, - 0x1a, 0xc2, 0x04, - 0x1b, 0xc2, 0xf0, - 0x1c, 0xc2, 0x05, - 0x1d, 0xc2, 0xd5, - 0x1e, 0xc2, 0xf7, - 0x1f, 0xc2, 0x07, - 0x20, 0xc2, 0xfd, - 0x21, 0xc2, 0x15, - 0x22, 0xc2, 0x04, - 0x23, 0xc2, 0xf0, - 0x24, 0xc2, 0x05, - 0x25, 0xc2, 0xd8, - 0x26, 0xc2, 0x17, - 0x27, 0xc2, 0x07, - 0x28, 0xc2, 0xfa, - 0x29, 0xc2, 0x2c, - 0x2a, 0xc2, 0x29, - 0x2b, 0xc2, 0x07, - 0x2c, 0xc2, 0x74, - 0x2d, 0xc2, 0xe0, - 0x2e, 0xc2, 0x33, - 0x2f, 0xc2, 0xf1, - 0x30, 0xc2, 0x16, - 0x31, 0xc2, 0x3f, - 0x32, 0xc2, 0x9b, - 0x33, 0xc2, 0x07, - 0x34, 0xc2, 0x74, - 0x35, 0xc2, 0xe0, - 0x36, 0xc2, 0x33, - 0x37, 0xc2, 0xf1, - 0x38, 0xc2, 0x29, - 0x39, 0xc2, 0xb0, - 0x3a, 0xc2, 0x4d, - 0x3b, 0xc2, 0x06, - 0x3c, 0xc2, 0xfd, - 0x3d, 0xc2, 0x31, - 0x3e, 0xc2, 0x18, - 0x3f, 0xc2, 0x07, - 0x40, 0xc2, 0xfd, - 0x41, 0xc2, 0x15, - 0x42, 0xc2, 0x04, - 0x43, 0xc2, 0xf0, - 0x44, 0xc2, 0x05, - 0x45, 0xc2, 0xd5, - 0x46, 0xc2, 0xf7, - 0x47, 0xc2, 0x07, - 0x48, 0xc2, 0xfd, - 0x49, 0xc2, 0x15, - 0x4a, 0xc2, 0x04, - 0x4b, 0xc2, 0xf0, - 0x4c, 0xc2, 0x05, - 0x4d, 0xc2, 0xd8, - 0x4e, 0xc2, 0x17, - 0x4f, 0xc2, 0x07, - 0x50, 0xc2, 0xfa, - 0x51, 0xc2, 0x2c, - 0x52, 0xc2, 0x29, - 0x0b, 0xc0, 0x30, - 0x80, 0xc3, 0x13, - 0x81, 0xc3, 0x88, - 0x82, 0xc3, 0x17, - 0x83, 0xc3, 0x70, - 0x84, 0xc3, 0x00, - 0x85, 0xc3, 0x00, - 0x86, 0xc3, 0xff, - 0x87, 0xc3, 0xee, - 0x88, 0xc3, 0x02, - 0x92, 0xc3, 0x00, - 0x93, 0xc3, 0x14, - 0x94, 0xc3, 0x00, - 0x95, 0xc3, 0x14, - 0x96, 0xc3, 0x00, - 0x97, 0xc3, 0x00, - 0x98, 0xc3, 0x00, - 0x99, 0xc3, 0x00, - 0x9a, 0xc3, 0x01, - 0x89, 0xc3, 0x03, - 0x8a, 0xc3, 0xe8, - 0x8b, 0xc3, 0x03, - 0x8c, 0xc3, 0xb6, - 0x8d, 0xc3, 0x00, - 0x8e, 0xc3, 0x00, - 0x8f, 0xc3, 0xff, - 0x90, 0xc3, 0xee, - 0x91, 0xc3, 0x01, - 0x9b, 0xc3, 0x00, - 0x9c, 0xc3, 0x14, - 0x9d, 0xc3, 0x00, - 0x9e, 0xc3, 0x14, - 0x9f, 0xc3, 0x00, - 0xa0, 0xc3, 0x00, - 0xa1, 0xc3, 0x00, - 0xa2, 0xc3, 0x00, - 0xa3, 0xc3, 0x01, - 0x61, 0xc2, 0x08, - 0x62, 0xc2, 0x00, - 0x63, 0xc2, 0x00, - 0x64, 0xc2, 0x00, - 0x65, 0xc2, 0x08, - 0x66, 0xc2, 0x00, - 0x67, 0xc2, 0x00, - 0x68, 0xc2, 0x00, - 0x69, 0xc2, 0x08, - 0x6a, 0xc2, 0x00, - 0x6b, 0xc2, 0x00, - 0x6c, 0xc2, 0x00, - 0x6d, 0xc2, 0x08, - 0x6e, 0xc2, 0x00, - 0x6f, 0xc2, 0x00, - 0x70, 0xc2, 0x00, - 0x00, 0xc2, 0xc0, -}; - -#endif diff --git a/sound/soc/intel/boards/sof_sdw_common.h b/sound/soc/intel/boards/sof_sdw_common.h index b1d57034361c..3aa1dcec5172 100644 --- a/sound/soc/intel/boards/sof_sdw_common.h +++ b/sound/soc/intel/boards/sof_sdw_common.h @@ -12,20 +12,12 @@ #include <linux/bits.h> #include <linux/types.h> #include <sound/soc.h> +#include <sound/soc_sdw_utils.h> #include "sof_hdmi_common.h" -#define MAX_NO_PROPS 2 #define MAX_HDMI_NUM 4 -#define SDW_UNUSED_DAI_ID -1 -#define SDW_JACK_OUT_DAI_ID 0 -#define SDW_JACK_IN_DAI_ID 1 -#define SDW_AMP_OUT_DAI_ID 2 -#define SDW_AMP_IN_DAI_ID 3 -#define SDW_DMIC_DAI_ID 4 -#define SDW_MAX_CPU_DAIS 16 -#define SDW_INTEL_BIDIR_PDI_BASE 2 - -#define SDW_MAX_LINKS 4 +#define SOC_SDW_MAX_CPU_DAIS 16 +#define SOC_SDW_INTEL_BIDIR_PDI_BASE 2 /* 8 combinations with 4 links + unused group 0 */ #define SDW_MAX_GROUPS 9 @@ -44,13 +36,14 @@ enum { SOF_I2S_SSP5 = BIT(5), }; -#define SOF_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) -#define SOF_SDW_FOUR_SPK BIT(4) +/* Deprecated and no longer supported by the code */ +#define SOC_SDW_FOUR_SPK BIT(4) #define SOF_SDW_TGL_HDMI BIT(5) -#define SOF_SDW_PCH_DMIC BIT(6) +#define SOC_SDW_PCH_DMIC BIT(6) #define SOF_SSP_PORT(x) (((x) & GENMASK(5, 0)) << 7) #define SOF_SSP_GET_PORT(quirk) (((quirk) >> 7) & GENMASK(5, 0)) -#define SOF_SDW_NO_AGGREGATION BIT(14) +/* Deprecated and no longer supported by the code */ +#define SOC_SDW_NO_AGGREGATION BIT(14) /* BT audio offload: reserve 3 bits for future */ #define SOF_BT_OFFLOAD_SSP_SHIFT 15 @@ -59,138 +52,15 @@ enum { (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) #define SOF_SSP_BT_OFFLOAD_PRESENT BIT(18) -#define SOF_SDW_DAI_TYPE_JACK 0 -#define SOF_SDW_DAI_TYPE_AMP 1 -#define SOF_SDW_DAI_TYPE_MIC 2 - -#define SOF_SDW_MAX_DAI_NUM 3 - -struct sof_sdw_codec_info; - -struct sof_sdw_dai_info { - const bool direction[2]; /* playback & capture support */ - const char *dai_name; - const int dai_type; - const int dailink[2]; /* dailink id for each direction */ - int (*init)(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - int (*rtd_init)(struct snd_soc_pcm_runtime *rtd); - bool rtd_init_done; /* Indicate that the rtd_init callback is done */ -}; - -struct sof_sdw_codec_info { - const int part_id; - const int version_id; - const char *codec_name; - int amp_num; - const u8 acpi_id[ACPI_ID_LEN]; - const bool ignore_pch_dmic; - const struct snd_soc_ops *ops; - struct sof_sdw_dai_info dais[SOF_SDW_MAX_DAI_NUM]; - const int dai_num; - - int (*codec_card_late_probe)(struct snd_soc_card *card); -}; - -struct mc_private { - struct snd_soc_jack sdw_headset; +struct intel_mc_ctx { struct sof_hdmi_private hdmi; - struct device *headset_codec_dev; /* only one headset per card */ - struct device *amp_dev1, *amp_dev2; /* To store SDW Pin index for each SoundWire link */ - unsigned int sdw_pin_index[SDW_MAX_LINKS]; + unsigned int sdw_pin_index[SDW_INTEL_MAX_LINKS]; }; -extern unsigned long sof_sdw_quirk; - -int sdw_startup(struct snd_pcm_substream *substream); -int sdw_prepare(struct snd_pcm_substream *substream); -int sdw_trigger(struct snd_pcm_substream *substream, int cmd); -int sdw_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params); -int sdw_hw_free(struct snd_pcm_substream *substream); -void sdw_shutdown(struct snd_pcm_substream *substream); - /* generic HDMI support */ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd); int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card); -/* DMIC support */ -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd); - -/* RT711 support */ -int sof_sdw_rt711_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT711-SDCA support */ -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT1308 I2S support */ -extern struct snd_soc_ops sof_sdw_rt1308_i2s_ops; - -/* generic amp support */ -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); - -/* RT722-SDCA support */ -int sof_sdw_rt722_spk_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); -int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* MAXIM codec support */ -int sof_sdw_maxim_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* CS AMP support */ -int sof_sdw_cs_amp_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback); - -/* dai_link init callbacks */ - -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd); -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd); -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd); - #endif diff --git a/sound/soc/intel/boards/sof_sdw_cs42l42.c b/sound/soc/intel/boards/sof_sdw_cs42l42.c deleted file mode 100644 index 0dc297f7de01..000000000000 --- a/sound/soc/intel/boards/sof_sdw_cs42l42.c +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2023 Intel Corporation - -/* - * sof_sdw_cs42l42 - Helpers to handle CS42L42 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/jack.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget cs42l42_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route cs42l42_map[] = { - /* HP jack connectors - unknown if we have jack detection */ - {"Headphone", NULL, "cs42l42 HP"}, - - /* other jacks */ - {"cs42l42 HS", NULL, "Headset Mic"}, -}; - -static const struct snd_kcontrol_new cs42l42_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin cs42l42_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const char * const jack_codecs[] = { - "cs42l42" -}; - -int cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - struct snd_soc_jack *jack; - int ret; - - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:cs42l42", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, cs42l42_controls, - ARRAY_SIZE(cs42l42_controls)); - if (ret) { - dev_err(card->dev, "cs42l42 control addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, cs42l42_widgets, - ARRAY_SIZE(cs42l42_widgets)); - if (ret) { - dev_err(card->dev, "cs42l42 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, cs42l42_map, - ARRAY_SIZE(cs42l42_map)); - - if (ret) { - dev_err(card->dev, "cs42l42 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - cs42l42_jack_pins, - ARRAY_SIZE(cs42l42_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_cs42l43.c b/sound/soc/intel/boards/sof_sdw_cs42l43.c deleted file mode 100644 index a9b6edac2ecd..000000000000 --- a/sound/soc/intel/boards/sof_sdw_cs42l43.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Based on sof_sdw_rt5682.c -// Copyright (c) 2023 Intel Corporation - -/* - * sof_sdw_cs42l43 - Helpers to handle CS42L43 from generic machine driver - */ -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <sound/jack.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/cs42l43.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget cs42l43_hs_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route cs42l43_hs_map[] = { - { "Headphone", NULL, "cs42l43 AMP3_OUT" }, - { "Headphone", NULL, "cs42l43 AMP4_OUT" }, - { "cs42l43 ADC1_IN1_P", NULL, "Headset Mic" }, - { "cs42l43 ADC1_IN1_N", NULL, "Headset Mic" }, -}; - -static const struct snd_soc_dapm_widget cs42l43_dmic_widgets[] = { - SND_SOC_DAPM_MIC("DMIC", NULL), -}; - -static const struct snd_soc_dapm_route cs42l43_dmic_map[] = { - { "cs42l43 PDM1_DIN", NULL, "DMIC" }, - { "cs42l43 PDM2_DIN", NULL, "DMIC" }, -}; - -static struct snd_soc_jack_pin sof_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -int cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_component *component = snd_soc_rtd_to_codec(rtd, 0)->component; - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_jack *jack = &ctx->sdw_headset; - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s hs:cs42l43", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_hs_widgets, - ARRAY_SIZE(cs42l43_hs_widgets)); - if (ret) { - dev_err(card->dev, "cs42l43 hs widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_hs_map, - ARRAY_SIZE(cs42l43_hs_map)); - if (ret) { - dev_err(card->dev, "cs42l43 hs map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(card, "Jack", - SND_JACK_MECHANICAL | SND_JACK_AVOUT | - SND_JACK_HEADSET | SND_JACK_LINEOUT | - SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, - jack, sof_jack_pins, - ARRAY_SIZE(sof_jack_pins)); - if (ret) { - dev_err(card->dev, "Failed to create jack: %d\n", ret); - return ret; - } - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) { - dev_err(card->dev, "Failed to register jack: %d\n", ret); - return ret; - } - - ret = snd_soc_component_set_sysclk(component, CS42L43_SYSCLK, CS42L43_SYSCLK_SDW, - 0, SND_SOC_CLOCK_IN); - if (ret) - dev_err(card->dev, "Failed to set sysclk: %d\n", ret); - - return ret; -} - -int cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, "%s mic:cs42l43-dmic", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_new_controls(&card->dapm, cs42l43_dmic_widgets, - ARRAY_SIZE(cs42l43_dmic_widgets)); - if (ret) { - dev_err(card->dev, "cs42l43 dmic widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, cs42l43_dmic_map, - ARRAY_SIZE(cs42l43_dmic_map)); - if (ret) - dev_err(card->dev, "cs42l43 dmic map addition failed: %d\n", ret); - - return ret; -} - diff --git a/sound/soc/intel/boards/sof_sdw_cs_amp.c b/sound/soc/intel/boards/sof_sdw_cs_amp.c deleted file mode 100644 index 56cf75bc6cc4..000000000000 --- a/sound/soc/intel/boards/sof_sdw_cs_amp.c +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2023 Intel Corporation - -/* - * sof_sdw_cs_amp - Helpers to handle CS35L56 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dai.h> -#include "sof_sdw_common.h" - -#define CODEC_NAME_SIZE 8 - -static const struct snd_soc_dapm_widget sof_widgets[] = { - SND_SOC_DAPM_SPK("Speakers", NULL), -}; - -int cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - const char *dai_name = rtd->dai_link->codecs->dai_name; - struct snd_soc_card *card = rtd->card; - char codec_name[CODEC_NAME_SIZE]; - char widget_name[16]; - struct snd_soc_dapm_route route = { "Speakers", NULL, widget_name }; - struct snd_soc_dai *codec_dai; - int i, ret; - - snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:%s", - card->components, codec_name); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_dapm_new_controls(&card->dapm, sof_widgets, - ARRAY_SIZE(sof_widgets)); - if (ret) { - dev_err(card->dev, "widgets addition failed: %d\n", ret); - return ret; - } - - for_each_rtd_codec_dais(rtd, i, codec_dai) { - if (!strstr(codec_dai->name, "cs35l56")) - continue; - - snprintf(widget_name, sizeof(widget_name), "%s SPK", - codec_dai->component->name_prefix); - ret = snd_soc_dapm_add_routes(&card->dapm, &route, 1); - if (ret) - return ret; - } - - return 0; -} - -int sof_sdw_cs_amp_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - /* Do init on playback link only. */ - if (!playback) - return 0; - - info->amp_num++; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_dmic.c b/sound/soc/intel/boards/sof_sdw_dmic.c deleted file mode 100644 index 19df0f7a1d85..000000000000 --- a/sound/soc/intel/boards/sof_sdw_dmic.c +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_dmic - Helpers to handle dmic from generic machine driver - */ - -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget dmic_widgets[] = { - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route dmic_map[] = { - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, -}; - -int sof_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, - ARRAY_SIZE(dmic_widgets)); - if (ret) { - dev_err(card->dev, "DMic widget addition failed: %d\n", ret); - /* Don't need to add routes if widget addition failed */ - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, - ARRAY_SIZE(dmic_map)); - - if (ret) - dev_err(card->dev, "DMic map addition failed: %d\n", ret); - - return ret; -} - diff --git a/sound/soc/intel/boards/sof_sdw_hdmi.c b/sound/soc/intel/boards/sof_sdw_hdmi.c index f34fabdf9d93..f92867deb029 100644 --- a/sound/soc/intel/boards/sof_sdw_hdmi.c +++ b/sound/soc/intel/boards/sof_sdw_hdmi.c @@ -5,10 +5,12 @@ * sof_sdw_hdmi - Helpers to handle HDMI from generic machine driver */ +#include <linux/acpi.h> #include <linux/device.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/list.h> +#include <linux/soundwire/sdw_intel.h> #include <sound/soc.h> #include <sound/soc-acpi.h> #include <sound/jack.h> @@ -17,23 +19,25 @@ int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd) { - struct mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - ctx->hdmi.hdmi_comp = dai->component; + intel_ctx->hdmi.hdmi_comp = dai->component; return 0; } int sof_sdw_hdmi_card_late_probe(struct snd_soc_card *card) { - struct mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; - if (!ctx->hdmi.idisp_codec) + if (!intel_ctx->hdmi.idisp_codec) return 0; - if (!ctx->hdmi.hdmi_comp) + if (!intel_ctx->hdmi.hdmi_comp) return -EINVAL; - return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); + return hda_dsp_hdmi_build_controls(card, intel_ctx->hdmi.hdmi_comp); } diff --git a/sound/soc/intel/boards/sof_sdw_maxim.c b/sound/soc/intel/boards/sof_sdw_maxim.c deleted file mode 100644 index 034730432671..000000000000 --- a/sound/soc/intel/boards/sof_sdw_maxim.c +++ /dev/null @@ -1,165 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation -// -// sof_sdw_maxim - Helpers to handle maxim codecs -// codec devices from generic machine driver - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include "sof_sdw_common.h" -#include "sof_maxim_common.h" - -static int maxim_part_id; -#define SOF_SDW_PART_ID_MAX98363 0x8363 -#define SOF_SDW_PART_ID_MAX98373 0x8373 - -static const struct snd_soc_dapm_widget maxim_widgets[] = { - SND_SOC_DAPM_SPK("Left Spk", NULL), - SND_SOC_DAPM_SPK("Right Spk", NULL), -}; - -static const struct snd_kcontrol_new maxim_controls[] = { - SOC_DAPM_PIN_SWITCH("Left Spk"), - SOC_DAPM_PIN_SWITCH("Right Spk"), -}; - -int maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:mx%04x", - card->components, maxim_part_id); - if (!card->components) - return -ENOMEM; - - dev_dbg(card->dev, "soundwire maxim card components assigned : %s\n", - card->components); - - ret = snd_soc_add_card_controls(card, maxim_controls, - ARRAY_SIZE(maxim_controls)); - if (ret) { - dev_err(card->dev, "mx%04x ctrls addition failed: %d\n", maxim_part_id, ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, maxim_widgets, - ARRAY_SIZE(maxim_widgets)); - if (ret) { - dev_err(card->dev, "mx%04x widgets addition failed: %d\n", maxim_part_id, ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, max_98373_dapm_routes, 2); - if (ret) - dev_err(rtd->dev, "failed to add first SPK map: %d\n", ret); - - return ret; -} - -static int mx8373_enable_spk_pin(struct snd_pcm_substream *substream, bool enable) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai; - struct snd_soc_dai *cpu_dai; - int ret; - int j; - - /* set spk pin by playback only */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - return 0; - - cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); - for_each_rtd_codec_dais(rtd, j, codec_dai) { - struct snd_soc_dapm_context *dapm = - snd_soc_component_get_dapm(cpu_dai->component); - char pin_name[16]; - - snprintf(pin_name, ARRAY_SIZE(pin_name), "%s Spk", - codec_dai->component->name_prefix); - - if (enable) - ret = snd_soc_dapm_enable_pin(dapm, pin_name); - else - ret = snd_soc_dapm_disable_pin(dapm, pin_name); - - if (!ret) - snd_soc_dapm_sync(dapm); - } - - return 0; -} - -static int mx8373_sdw_prepare(struct snd_pcm_substream *substream) -{ - int ret; - - /* according to soc_pcm_prepare dai link prepare is called first */ - ret = sdw_prepare(substream); - if (ret < 0) - return ret; - - return mx8373_enable_spk_pin(substream, true); -} - -static int mx8373_sdw_hw_free(struct snd_pcm_substream *substream) -{ - int ret; - - /* according to soc_pcm_hw_free dai link free is called first */ - ret = sdw_hw_free(substream); - if (ret < 0) - return ret; - - return mx8373_enable_spk_pin(substream, false); -} - -static const struct snd_soc_ops max_98373_sdw_ops = { - .startup = sdw_startup, - .prepare = mx8373_sdw_prepare, - .trigger = sdw_trigger, - .hw_params = sdw_hw_params, - .hw_free = mx8373_sdw_hw_free, - .shutdown = sdw_shutdown, -}; - -static int mx8373_sdw_late_probe(struct snd_soc_card *card) -{ - struct snd_soc_dapm_context *dapm = &card->dapm; - - /* Disable Left and Right Spk pin after boot */ - snd_soc_dapm_disable_pin(dapm, "Left Spk"); - snd_soc_dapm_disable_pin(dapm, "Right Spk"); - return snd_soc_dapm_sync(dapm); -} - -int sof_sdw_maxim_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - info->amp_num++; - - maxim_part_id = info->part_id; - switch (maxim_part_id) { - case SOF_SDW_PART_ID_MAX98363: - /* Default ops are set in function init_dai_link. - * called as part of function create_sdw_dailink - */ - break; - case SOF_SDW_PART_ID_MAX98373: - info->codec_card_late_probe = mx8373_sdw_late_probe; - dai_links->ops = &max_98373_sdw_ops; - break; - default: - dev_err(card->dev, "Invalid maxim_part_id %#x\n", maxim_part_id); - return -EINVAL; - } - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt5682.c b/sound/soc/intel/boards/sof_sdw_rt5682.c deleted file mode 100644 index 6b008a5a343b..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt5682.c +++ /dev/null @@ -1,123 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt5682 - Helpers to handle RT5682 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/jack.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt5682_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route rt5682_map[] = { - /*Headphones*/ - { "Headphone", NULL, "rt5682 HPOL" }, - { "Headphone", NULL, "rt5682 HPOR" }, - { "rt5682 IN1P", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new rt5682_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin rt5682_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const char * const jack_codecs[] = { - "rt5682" -}; - -int rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - struct snd_soc_jack *jack; - int ret; - - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt5682", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt5682_controls, - ARRAY_SIZE(rt5682_controls)); - if (ret) { - dev_err(card->dev, "rt5682 control addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt5682_widgets, - ARRAY_SIZE(rt5682_widgets)); - if (ret) { - dev_err(card->dev, "rt5682 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt5682_map, - ARRAY_SIZE(rt5682_map)); - - if (ret) { - dev_err(card->dev, "rt5682 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt5682_jack_pins, - ARRAY_SIZE(rt5682_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_rt700.c b/sound/soc/intel/boards/sof_sdw_rt700.c deleted file mode 100644 index 88e785a54b16..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt700.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt700 - Helpers to handle RT700 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/jack.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt700_widgets[] = { - SND_SOC_DAPM_HP("Headphones", NULL), - SND_SOC_DAPM_MIC("AMIC", NULL), - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route rt700_map[] = { - /* Headphones */ - { "Headphones", NULL, "rt700 HP" }, - { "Speaker", NULL, "rt700 SPK" }, - { "rt700 MIC2", NULL, "AMIC" }, -}; - -static const struct snd_kcontrol_new rt700_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphones"), - SOC_DAPM_PIN_SWITCH("AMIC"), - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static struct snd_soc_jack_pin rt700_jack_pins[] = { - { - .pin = "Headphones", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "AMIC", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const char * const jack_codecs[] = { - "rt700" -}; - -int rt700_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - struct snd_soc_jack *jack; - int ret; - - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt700", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt700_controls, - ARRAY_SIZE(rt700_controls)); - if (ret) { - dev_err(card->dev, "rt700 controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt700_widgets, - ARRAY_SIZE(rt700_widgets)); - if (ret) { - dev_err(card->dev, "rt700 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt700_map, - ARRAY_SIZE(rt700_map)); - - if (ret) { - dev_err(card->dev, "rt700 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt700_jack_pins, - ARRAY_SIZE(rt700_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_rt711.c b/sound/soc/intel/boards/sof_sdw_rt711.c deleted file mode 100644 index cdd1587b246c..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt711.c +++ /dev/null @@ -1,191 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt711 - Helpers to handle RT711 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/jack.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -/* - * Note this MUST be called before snd_soc_register_card(), so that the props - * are in place before the codec component driver's probe function parses them. - */ -static int rt711_add_codec_device_props(struct device *sdw_dev) -{ - struct property_entry props[MAX_NO_PROPS] = {}; - struct fwnode_handle *fwnode; - int ret; - - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) - return 0; - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); - - fwnode = fwnode_create_software_node(props, NULL); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); - - ret = device_add_software_node(sdw_dev, to_software_node(fwnode)); - - fwnode_handle_put(fwnode); - - return ret; -} - -static const struct snd_soc_dapm_widget rt711_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route rt711_map[] = { - /* Headphones */ - { "Headphone", NULL, "rt711 HP" }, - { "rt711 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new rt711_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin rt711_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const char * const jack_codecs[] = { - "rt711" -}; - -int rt711_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - struct snd_soc_jack *jack; - int ret; - - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:rt711", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt711_controls, - ARRAY_SIZE(rt711_controls)); - if (ret) { - dev_err(card->dev, "rt711 controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt711_widgets, - ARRAY_SIZE(rt711_widgets)); - if (ret) { - dev_err(card->dev, "rt711 widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt711_map, - ARRAY_SIZE(rt711_map)); - - if (ret) { - dev_err(card->dev, "rt711 map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt711_jack_pins, - ARRAY_SIZE(rt711_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -int sof_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - - if (!ctx->headset_codec_dev) - return 0; - - device_remove_software_node(ctx->headset_codec_dev); - put_device(ctx->headset_codec_dev); - - return 0; -} - -int sof_sdw_rt711_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct device *sdw_dev; - int ret; - - /* - * headset should be initialized once. - * Do it with dai link for playback. - */ - if (!playback) - return 0; - - sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); - if (!sdw_dev) - return -EPROBE_DEFER; - - ret = rt711_add_codec_device_props(sdw_dev); - if (ret < 0) { - put_device(sdw_dev); - return ret; - } - ctx->headset_codec_dev = sdw_dev; - - return 0; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c b/sound/soc/intel/boards/sof_sdw_rt712_sdca.c deleted file mode 100644 index ebb4b58c198b..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt712_sdca.c +++ /dev/null @@ -1,93 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2023 Intel Corporation - -/* - * sof_sdw_rt712_sdca - Helpers to handle RT712-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt712_spk_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* - * dapm routes for rt712 spk will be registered dynamically according - * to the number of rt712 spk used. The first two entries will be registered - * for one codec case, and the last two entries are also registered - * if two rt712s are used. - */ -static const struct snd_soc_dapm_route rt712_spk_map[] = { - { "Speaker", NULL, "rt712 SPOL" }, - { "Speaker", NULL, "rt712 SPOR" }, -}; - -static const struct snd_kcontrol_new rt712_spk_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -int rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt712", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt712_spk_controls, - ARRAY_SIZE(rt712_spk_controls)); - if (ret) { - dev_err(card->dev, "rt712 spk controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt712_spk_widgets, - ARRAY_SIZE(rt712_spk_widgets)); - if (ret) { - dev_err(card->dev, "rt712 spk widgets addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt712_spk_map, ARRAY_SIZE(rt712_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add SPK map: %d\n", ret); - - return ret; -} - -static const char * const dmics[] = { - "rt712-sdca-dmic" -}; - -int rt712_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - - codec_dai = get_codec_dai_by_name(rtd, dmics, ARRAY_SIZE(dmics)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:%s", - card->components, component->name_prefix); - if (!card->components) - return -ENOMEM; - - return 0; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_sdw_rt715.c b/sound/soc/intel/boards/sof_sdw_rt715.c deleted file mode 100644 index b5a886cd595d..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt715.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt715 - Helpers to handle RT715 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" - -int rt715_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:rt715", - card->components); - if (!card->components) - return -ENOMEM; - - return 0; -} - diff --git a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c b/sound/soc/intel/boards/sof_sdw_rt715_sdca.c deleted file mode 100644 index 4b37a8a6dd2e..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt715_sdca.c +++ /dev/null @@ -1,26 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt715_sdca - Helpers to handle RT715-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include "sof_sdw_common.h" - -int rt715_sdca_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:rt715-sdca", - card->components); - if (!card->components) - return -ENOMEM; - - return 0; -} - diff --git a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c b/sound/soc/intel/boards/sof_sdw_rt722_sdca.c deleted file mode 100644 index fe3a2bff95bc..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt722_sdca.c +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2023 Intel Corporation - -/* - * sof_sdw_rt722_sdca - Helpers to handle RT722-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include "sof_sdw_common.h" - -static const struct snd_soc_dapm_widget rt722_spk_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -static const struct snd_soc_dapm_route rt722_spk_map[] = { - { "Speaker", NULL, "rt722 SPK" }, -}; - -static const struct snd_kcontrol_new rt722_spk_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static int rt722_spk_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - int ret; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:rt722", - card->components); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt722_spk_controls, - ARRAY_SIZE(rt722_spk_controls)); - if (ret) { - dev_err(card->dev, "failed to add rt722 spk controls: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt722_spk_widgets, - ARRAY_SIZE(rt722_spk_widgets)); - if (ret) { - dev_err(card->dev, "failed to add rt722 spk widgets: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_add_routes(&card->dapm, rt722_spk_map, ARRAY_SIZE(rt722_spk_map)); - if (ret) - dev_err(rtd->dev, "failed to add rt722 spk map: %d\n", ret); - - return ret; -} - -int sof_sdw_rt722_spk_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - dai_links->init = rt722_spk_init; - - return 0; -} - -static int rt722_sdca_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct snd_soc_component *component = codec_dai->component; - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s mic:%s", - card->components, component->name_prefix); - if (!card->components) - return -ENOMEM; - - return 0; -} - -int sof_sdw_rt722_sdca_dmic_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - dai_links->init = rt722_sdca_dmic_rtd_init; - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt_amp.c b/sound/soc/intel/boards/sof_sdw_rt_amp.c deleted file mode 100644 index 202edab95000..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt_amp.c +++ /dev/null @@ -1,324 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2022 Intel Corporation - -/* - * sof_sdw_rt_amp - Helpers to handle RT1308/RT1316/RT1318 from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <linux/dmi.h> -#include "sof_sdw_common.h" -#include "sof_sdw_amp_coeff_tables.h" -#include "../../codecs/rt1308.h" - -#define CODEC_NAME_SIZE 7 - -/* choose a larger value to resolve compatibility issues */ -#define RT_AMP_MAX_BQ_REG RT1316_MAX_BQ_REG - -struct rt_amp_platform_data { - const unsigned char *bq_params; - const unsigned int bq_params_cnt; -}; - -static const struct rt_amp_platform_data dell_0a5d_platform_data = { - .bq_params = dell_0a5d_bq_params, - .bq_params_cnt = ARRAY_SIZE(dell_0a5d_bq_params), -}; - -static const struct rt_amp_platform_data dell_0b00_platform_data = { - .bq_params = dell_0b00_bq_params, - .bq_params_cnt = ARRAY_SIZE(dell_0b00_bq_params), -}; - -static const struct dmi_system_id dmi_platform_data[] = { - /* CometLake devices */ - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0990") - }, - .driver_data = (void *)&dell_0a5d_platform_data, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "098F") - }, - .driver_data = (void *)&dell_0a5d_platform_data, - }, - /* TigerLake devices */ - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5D") - }, - .driver_data = (void *)&dell_0a5d_platform_data, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0A5E") - }, - .driver_data = (void *)&dell_0a5d_platform_data, - }, - /* AlderLake devices */ - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B00") - }, - .driver_data = (void *)&dell_0b00_platform_data, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0B01") - }, - .driver_data = (void *)&dell_0b00_platform_data, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFF") - }, - .driver_data = (void *)&dell_0b00_platform_data, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), - DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0AFE") - }, - .driver_data = (void *)&dell_0b00_platform_data, - }, - {}, -}; - -static int rt_amp_add_device_props(struct device *sdw_dev) -{ - struct property_entry props[3] = {}; - struct fwnode_handle *fwnode; - const struct dmi_system_id *dmi_data; - const struct rt_amp_platform_data *pdata; - unsigned char params[RT_AMP_MAX_BQ_REG]; - int ret; - - dmi_data = dmi_first_match(dmi_platform_data); - if (!dmi_data) - return 0; - - pdata = dmi_data->driver_data; - memcpy(¶ms, pdata->bq_params, sizeof(unsigned char) * pdata->bq_params_cnt); - - props[0] = PROPERTY_ENTRY_U8_ARRAY("realtek,bq-params", params); - props[1] = PROPERTY_ENTRY_U32("realtek,bq-params-cnt", pdata->bq_params_cnt); - - fwnode = fwnode_create_software_node(props, NULL); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); - - ret = device_add_software_node(sdw_dev, to_software_node(fwnode)); - - fwnode_handle_put(fwnode); - - return ret; -} - -static const struct snd_kcontrol_new rt_amp_controls[] = { - SOC_DAPM_PIN_SWITCH("Speaker"), -}; - -static const struct snd_soc_dapm_widget rt_amp_widgets[] = { - SND_SOC_DAPM_SPK("Speaker", NULL), -}; - -/* - * dapm routes for rt1308/rt1316/rt1318 will be registered dynamically - * according to the number of rt1308/rt1316/rt1318 used. The first two - * entries will be registered for one codec case, and the last two entries - * are also registered if two 1308s/1316s/1318s are used. - */ -static const struct snd_soc_dapm_route rt1308_map[] = { - { "Speaker", NULL, "rt1308-1 SPOL" }, - { "Speaker", NULL, "rt1308-1 SPOR" }, - { "Speaker", NULL, "rt1308-2 SPOL" }, - { "Speaker", NULL, "rt1308-2 SPOR" }, -}; - -static const struct snd_soc_dapm_route rt1316_map[] = { - { "Speaker", NULL, "rt1316-1 SPOL" }, - { "Speaker", NULL, "rt1316-1 SPOR" }, - { "Speaker", NULL, "rt1316-2 SPOL" }, - { "Speaker", NULL, "rt1316-2 SPOR" }, -}; - -static const struct snd_soc_dapm_route rt1318_map[] = { - { "Speaker", NULL, "rt1318-1 SPOL" }, - { "Speaker", NULL, "rt1318-1 SPOR" }, - { "Speaker", NULL, "rt1318-2 SPOL" }, - { "Speaker", NULL, "rt1318-2 SPOR" }, -}; - -static const struct snd_soc_dapm_route *get_codec_name_and_route(struct snd_soc_pcm_runtime *rtd, - char *codec_name) -{ - const char *dai_name; - - dai_name = rtd->dai_link->codecs->dai_name; - - /* get the codec name */ - snprintf(codec_name, CODEC_NAME_SIZE, "%s", dai_name); - - /* choose the right codec's map */ - if (strcmp(codec_name, "rt1308") == 0) - return rt1308_map; - else if (strcmp(codec_name, "rt1316") == 0) - return rt1316_map; - else - return rt1318_map; -} - -int rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - const struct snd_soc_dapm_route *rt_amp_map; - char codec_name[CODEC_NAME_SIZE]; - struct snd_soc_dai *dai; - int ret; - int i; - - rt_amp_map = get_codec_name_and_route(rtd, codec_name); - - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s spk:%s", - card->components, codec_name); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt_amp_controls, - ARRAY_SIZE(rt_amp_controls)); - if (ret) { - dev_err(card->dev, "%s controls addition failed: %d\n", codec_name, ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt_amp_widgets, - ARRAY_SIZE(rt_amp_widgets)); - if (ret) { - dev_err(card->dev, "%s widgets addition failed: %d\n", codec_name, ret); - return ret; - } - - for_each_rtd_codec_dais(rtd, i, dai) { - if (strstr(dai->component->name_prefix, "-1")) - ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map, 2); - else if (strstr(dai->component->name_prefix, "-2")) - ret = snd_soc_dapm_add_routes(&card->dapm, rt_amp_map + 2, 2); - } - - return ret; -} - -static int rt1308_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_card *card = rtd->card; - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - int clk_id, clk_freq, pll_out; - int err; - - clk_id = RT1308_PLL_S_MCLK; - clk_freq = 38400000; - - pll_out = params_rate(params) * 512; - - /* Set rt1308 pll */ - err = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 PLL: %d\n", err); - return err; - } - - /* Set rt1308 sysclk */ - err = snd_soc_dai_set_sysclk(codec_dai, RT1308_FS_SYS_S_PLL, pll_out, - SND_SOC_CLOCK_IN); - if (err < 0) { - dev_err(card->dev, "Failed to set RT1308 SYSCLK: %d\n", err); - return err; - } - - return 0; -} - -/* machine stream operations */ -struct snd_soc_ops sof_sdw_rt1308_i2s_ops = { - .hw_params = rt1308_i2s_hw_params, -}; - -int sof_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - - if (ctx->amp_dev1) { - device_remove_software_node(ctx->amp_dev1); - put_device(ctx->amp_dev1); - } - - if (ctx->amp_dev2) { - device_remove_software_node(ctx->amp_dev2); - put_device(ctx->amp_dev2); - } - - return 0; -} - -int sof_sdw_rt_amp_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct device *sdw_dev1, *sdw_dev2; - int ret; - - /* Count amp number and do init on playback link only. */ - if (!playback) - return 0; - - info->amp_num++; - - if (info->amp_num == 2) { - sdw_dev1 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); - if (!sdw_dev1) - return -EPROBE_DEFER; - - ret = rt_amp_add_device_props(sdw_dev1); - if (ret < 0) { - put_device(sdw_dev1); - return ret; - } - ctx->amp_dev1 = sdw_dev1; - - sdw_dev2 = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[1].name); - if (!sdw_dev2) - return -EPROBE_DEFER; - - ret = rt_amp_add_device_props(sdw_dev2); - if (ret < 0) { - put_device(sdw_dev2); - return ret; - } - ctx->amp_dev2 = sdw_dev2; - } - - return 0; -} diff --git a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c b/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c deleted file mode 100644 index 5253d8332780..000000000000 --- a/sound/soc/intel/boards/sof_sdw_rt_sdca_jack_common.c +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright (c) 2020 Intel Corporation - -/* - * sof_sdw_rt711_sdca - Helpers to handle RT711-SDCA from generic machine driver - */ - -#include <linux/device.h> -#include <linux/errno.h> -#include <linux/input.h> -#include <linux/soundwire/sdw.h> -#include <linux/soundwire/sdw_type.h> -#include <sound/control.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-dapm.h> -#include <sound/jack.h> -#include "sof_board_helpers.h" -#include "sof_sdw_common.h" - -/* - * Note this MUST be called before snd_soc_register_card(), so that the props - * are in place before the codec component driver's probe function parses them. - */ -static int rt_sdca_jack_add_codec_device_props(struct device *sdw_dev) -{ - struct property_entry props[MAX_NO_PROPS] = {}; - struct fwnode_handle *fwnode; - int ret; - - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) - return 0; - - props[0] = PROPERTY_ENTRY_U32("realtek,jd-src", SOF_JACK_JDSRC(sof_sdw_quirk)); - - fwnode = fwnode_create_software_node(props, NULL); - if (IS_ERR(fwnode)) - return PTR_ERR(fwnode); - - ret = device_add_software_node(sdw_dev, to_software_node(fwnode)); - - fwnode_handle_put(fwnode); - - return ret; -} - -static const struct snd_soc_dapm_widget rt_sdca_jack_widgets[] = { - SND_SOC_DAPM_HP("Headphone", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), -}; - -static const struct snd_soc_dapm_route rt711_sdca_map[] = { - { "Headphone", NULL, "rt711 HP" }, - { "rt711 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_soc_dapm_route rt712_sdca_map[] = { - { "Headphone", NULL, "rt712 HP" }, - { "rt712 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_soc_dapm_route rt713_sdca_map[] = { - { "Headphone", NULL, "rt713 HP" }, - { "rt713 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_soc_dapm_route rt722_sdca_map[] = { - { "Headphone", NULL, "rt722 HP" }, - { "rt722 MIC2", NULL, "Headset Mic" }, -}; - -static const struct snd_kcontrol_new rt_sdca_jack_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), -}; - -static struct snd_soc_jack_pin rt_sdca_jack_pins[] = { - { - .pin = "Headphone", - .mask = SND_JACK_HEADPHONE, - }, - { - .pin = "Headset Mic", - .mask = SND_JACK_MICROPHONE, - }, -}; - -static const char * const jack_codecs[] = { - "rt711", "rt712", "rt713" -}; - -int rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_card *card = rtd->card; - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai; - struct snd_soc_component *component; - struct snd_soc_jack *jack; - int ret; - - codec_dai = get_codec_dai_by_name(rtd, jack_codecs, ARRAY_SIZE(jack_codecs)); - if (!codec_dai) - return -EINVAL; - - component = codec_dai->component; - card->components = devm_kasprintf(card->dev, GFP_KERNEL, - "%s hs:%s-sdca", - card->components, component->name_prefix); - if (!card->components) - return -ENOMEM; - - ret = snd_soc_add_card_controls(card, rt_sdca_jack_controls, - ARRAY_SIZE(rt_sdca_jack_controls)); - if (ret) { - dev_err(card->dev, "rt sdca jack controls addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_dapm_new_controls(&card->dapm, rt_sdca_jack_widgets, - ARRAY_SIZE(rt_sdca_jack_widgets)); - if (ret) { - dev_err(card->dev, "rt sdca jack widgets addition failed: %d\n", ret); - return ret; - } - - if (strstr(component->name_prefix, "rt711")) { - ret = snd_soc_dapm_add_routes(&card->dapm, rt711_sdca_map, - ARRAY_SIZE(rt711_sdca_map)); - } else if (strstr(component->name_prefix, "rt712")) { - ret = snd_soc_dapm_add_routes(&card->dapm, rt712_sdca_map, - ARRAY_SIZE(rt712_sdca_map)); - } else if (strstr(component->name_prefix, "rt713")) { - ret = snd_soc_dapm_add_routes(&card->dapm, rt713_sdca_map, - ARRAY_SIZE(rt713_sdca_map)); - } else if (strstr(component->name_prefix, "rt722")) { - ret = snd_soc_dapm_add_routes(&card->dapm, rt722_sdca_map, - ARRAY_SIZE(rt722_sdca_map)); - } else { - dev_err(card->dev, "%s is not supported\n", component->name_prefix); - return -EINVAL; - } - - if (ret) { - dev_err(card->dev, "rt sdca jack map addition failed: %d\n", ret); - return ret; - } - - ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", - SND_JACK_HEADSET | SND_JACK_BTN_0 | - SND_JACK_BTN_1 | SND_JACK_BTN_2 | - SND_JACK_BTN_3, - &ctx->sdw_headset, - rt_sdca_jack_pins, - ARRAY_SIZE(rt_sdca_jack_pins)); - if (ret) { - dev_err(rtd->card->dev, "Headset Jack creation failed: %d\n", - ret); - return ret; - } - - jack = &ctx->sdw_headset; - - snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); - snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); - snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); - snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); - - ret = snd_soc_component_set_jack(component, jack, NULL); - - if (ret) - dev_err(rtd->card->dev, "Headset Jack call-back failed: %d\n", - ret); - - return ret; -} - -int sof_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - - if (!ctx->headset_codec_dev) - return 0; - - if (!SOF_JACK_JDSRC(sof_sdw_quirk)) - return 0; - - device_remove_software_node(ctx->headset_codec_dev); - put_device(ctx->headset_codec_dev); - ctx->headset_codec_dev = NULL; - - return 0; -} - -int sof_sdw_rt_sdca_jack_init(struct snd_soc_card *card, - const struct snd_soc_acpi_link_adr *link, - struct snd_soc_dai_link *dai_links, - struct sof_sdw_codec_info *info, - bool playback) -{ - struct mc_private *ctx = snd_soc_card_get_drvdata(card); - struct device *sdw_dev; - int ret; - - /* - * Jack detection should be only initialized once for headsets since - * the playback/capture is sharing the same jack - */ - if (ctx->headset_codec_dev) - return 0; - - sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, dai_links->codecs[0].name); - if (!sdw_dev) - return -EPROBE_DEFER; - - ret = rt_sdca_jack_add_codec_device_props(sdw_dev); - if (ret < 0) { - put_device(sdw_dev); - return ret; - } - ctx->headset_codec_dev = sdw_dev; - - return 0; -} -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); diff --git a/sound/soc/intel/boards/sof_ssp_amp.c b/sound/soc/intel/boards/sof_ssp_amp.c index ee2e813bf4c0..48ee5353bdf1 100644 --- a/sound/soc/intel/boards/sof_ssp_amp.c +++ b/sound/soc/intel/boards/sof_ssp_amp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2022 Intel Corporation. All rights reserved. +// Copyright(c) 2022 Intel Corporation /* * sof_ssp_amp.c - ASoc Machine driver for Intel platforms @@ -20,34 +20,12 @@ #include "sof_board_helpers.h" #include "sof_realtek_common.h" #include "sof_cirrus_common.h" -#include "sof_ssp_common.h" - -/* SSP port ID for speaker amplifier */ -#define SOF_AMPLIFIER_SSP(quirk) ((quirk) & GENMASK(3, 0)) -#define SOF_AMPLIFIER_SSP_MASK (GENMASK(3, 0)) - -/* HDMI capture*/ -#define SOF_HDMI_CAPTURE_SSP_MASK_SHIFT 4 -#define SOF_HDMI_CAPTURE_SSP_MASK_MASK (GENMASK(9, 4)) -#define SOF_HDMI_CAPTURE_SSP_MASK(quirk) \ - (((quirk) << SOF_HDMI_CAPTURE_SSP_MASK_SHIFT) & SOF_HDMI_CAPTURE_SSP_MASK_MASK) - -/* HDMI playback */ -#define SOF_HDMI_PLAYBACK_PRESENT BIT(13) -#define SOF_NO_OF_HDMI_PLAYBACK_SHIFT 14 -#define SOF_NO_OF_HDMI_PLAYBACK_MASK (GENMASK(16, 14)) -#define SOF_NO_OF_HDMI_PLAYBACK(quirk) \ - (((quirk) << SOF_NO_OF_HDMI_PLAYBACK_SHIFT) & SOF_NO_OF_HDMI_PLAYBACK_MASK) - -/* BT audio offload */ -#define SOF_SSP_BT_OFFLOAD_PRESENT BIT(17) -#define SOF_BT_OFFLOAD_SSP_SHIFT 18 -#define SOF_BT_OFFLOAD_SSP_MASK (GENMASK(20, 18)) -#define SOF_BT_OFFLOAD_SSP(quirk) \ - (((quirk) << SOF_BT_OFFLOAD_SSP_SHIFT) & SOF_BT_OFFLOAD_SSP_MASK) + +/* Driver-specific board quirks: from bit 0 to 7 */ +#define SOF_HDMI_PLAYBACK_PRESENT BIT(0) /* Default: SSP2 */ -static unsigned long sof_ssp_amp_quirk = SOF_AMPLIFIER_SSP(2); +static unsigned long sof_ssp_amp_quirk = SOF_SSP_PORT_AMP(2); static const struct dmi_system_id chromebook_platforms[] = { { @@ -75,197 +53,107 @@ static struct snd_soc_card sof_ssp_amp_card = { #define HDMI_IN_BE_ID 0 #define SPK_BE_ID 2 #define DMIC01_BE_ID 3 -#define DMIC16K_BE_ID 4 #define INTEL_HDMI_BE_ID 5 - -static struct snd_soc_dai_link * -sof_card_dai_links_create(struct device *dev, enum sof_ssp_codec amp_type, - int ssp_amp, int dmic_be_num, int hdmi_num, - bool idisp_codec) +/* extra BE links to support no-hdmi-in boards */ +#define DMIC16K_BE_ID 4 +#define BT_OFFLOAD_BE_ID 8 + +#define SSP_AMP_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_HDMI_IN, \ + SOF_LINK_AMP, \ + SOF_LINK_DMIC01, \ + SOF_LINK_DMIC16K, \ + SOF_LINK_IDISP_HDMI, \ + SOF_LINK_BT_OFFLOAD, \ + SOF_LINK_NONE) + +#define SSP_AMP_LINK_IDS SOF_LINK_ORDER(HDMI_IN_BE_ID, \ + SPK_BE_ID, \ + DMIC01_BE_ID, \ + DMIC16K_BE_ID, \ + INTEL_HDMI_BE_ID, \ + BT_OFFLOAD_BE_ID, \ + 0) + +static int +sof_card_dai_links_create(struct device *dev, struct snd_soc_card *card, + struct sof_card_private *ctx) { - struct snd_soc_dai_link *links; - int i; - int id = 0; int ret; - bool fixed_be = false; - int be_id; - unsigned long ssp_mask_hdmi_in; - - links = devm_kcalloc(dev, sof_ssp_amp_card.num_links, - sizeof(struct snd_soc_dai_link), GFP_KERNEL); - if (!links) - return NULL; - - /* HDMI-In SSP */ - ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> - SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; - - if (ssp_mask_hdmi_in) { - int port = 0; - - /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ - fixed_be = true; - - be_id = HDMI_IN_BE_ID; - for_each_set_bit(port, &ssp_mask_hdmi_in, 32) { - ret = sof_intel_board_set_hdmi_in_link(dev, &links[id], - be_id, port); - if (ret) - return NULL; - - id++; - be_id++; - } - } - - /* codec SSP */ - if (amp_type != CODEC_NONE) { - be_id = fixed_be ? SPK_BE_ID : id; - ret = sof_intel_board_set_ssp_amp_link(dev, &links[id], be_id, - amp_type, ssp_amp); - if (ret) - return NULL; - - /* codec-specific fields */ - switch (amp_type) { - case CODEC_CS35L41: - cs35l41_set_dai_link(&links[id]); - break; - case CODEC_RT1308: - sof_rt1308_dai_link(&links[id]); - break; - default: - dev_err(dev, "invalid amp type %d\n", amp_type); - return NULL; - } - id++; - } - - /* dmic */ - if (dmic_be_num > 0) { - /* at least we have dmic01 */ - be_id = fixed_be ? DMIC01_BE_ID : id; - ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, - SOF_DMIC_01); - if (ret) - return NULL; - - id++; - } - - if (dmic_be_num > 1) { - /* set up 2 BE links at most */ - be_id = fixed_be ? DMIC16K_BE_ID : id; - ret = sof_intel_board_set_dmic_link(dev, &links[id], be_id, - SOF_DMIC_16K); - if (ret) - return NULL; - - id++; - } + ret = sof_intel_board_set_dai_link(dev, card, ctx); + if (ret) + return ret; - /* HDMI playback */ - for (i = 1; i <= hdmi_num; i++) { - be_id = fixed_be ? (INTEL_HDMI_BE_ID + i - 1) : id; - ret = sof_intel_board_set_intel_hdmi_link(dev, &links[id], be_id, - i, idisp_codec); - if (ret) - return NULL; + if (ctx->amp_type == CODEC_NONE) + return 0; - id++; + if (!ctx->amp_link) { + dev_err(dev, "amp link not available"); + return -EINVAL; } - /* BT audio offload */ - if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - int port = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ret = sof_intel_board_set_bt_link(dev, &links[id], id, port); - if (ret) - return NULL; - - id++; + /* codec-specific fields for speaker amplifier */ + switch (ctx->amp_type) { + case CODEC_CS35L41: + cs35l41_set_dai_link(ctx->amp_link); + break; + case CODEC_RT1308: + sof_rt1308_dai_link(ctx->amp_link); + break; + default: + dev_err(dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; } - return links; + return 0; } static int sof_ssp_amp_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; - struct snd_soc_dai_link *dai_links; struct sof_card_private *ctx; int ret; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - if (pdev->id_entry && pdev->id_entry->driver_data) sof_ssp_amp_quirk = (unsigned long)pdev->id_entry->driver_data; - ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); - - if (dmi_check_system(chromebook_platforms) || mach->mach_params.dmic_num > 0) - ctx->dmic_be_num = 2; - else - ctx->dmic_be_num = 0; - - /* port number/mask of peripherals attached to ssp interface */ - ctx->ssp_mask_hdmi_in = (sof_ssp_amp_quirk & SOF_HDMI_CAPTURE_SSP_MASK_MASK) >> - SOF_HDMI_CAPTURE_SSP_MASK_SHIFT; - - ctx->ssp_bt = (sof_ssp_amp_quirk & SOF_BT_OFFLOAD_SSP_MASK) >> - SOF_BT_OFFLOAD_SSP_SHIFT; - - ctx->ssp_amp = sof_ssp_amp_quirk & SOF_AMPLIFIER_SSP_MASK; - - /* set number of dai links */ - sof_ssp_amp_card.num_links = ctx->dmic_be_num; + dev_dbg(&pdev->dev, "sof_ssp_amp_quirk = %lx\n", sof_ssp_amp_quirk); - if (ctx->amp_type != CODEC_NONE) - sof_ssp_amp_card.num_links++; + /* initialize ctx with board quirk */ + ctx = sof_intel_board_get_ctx(&pdev->dev, sof_ssp_amp_quirk); + if (!ctx) + return -ENOMEM; - if (ctx->ssp_mask_hdmi_in) - sof_ssp_amp_card.num_links += hweight32(ctx->ssp_mask_hdmi_in); + if (!dmi_check_system(chromebook_platforms) && + (mach->mach_params.dmic_num == 0)) + ctx->dmic_be_num = 0; if (sof_ssp_amp_quirk & SOF_HDMI_PLAYBACK_PRESENT) { - ctx->hdmi_num = (sof_ssp_amp_quirk & SOF_NO_OF_HDMI_PLAYBACK_MASK) >> - SOF_NO_OF_HDMI_PLAYBACK_SHIFT; - /* default number of HDMI DAI's */ - if (!ctx->hdmi_num) - ctx->hdmi_num = 3; - if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) ctx->hdmi.idisp_codec = true; - - sof_ssp_amp_card.num_links += ctx->hdmi_num; } else { ctx->hdmi_num = 0; } - if (sof_ssp_amp_quirk & SOF_SSP_BT_OFFLOAD_PRESENT) { - ctx->bt_offload_present = true; - sof_ssp_amp_card.num_links++; - } + ctx->link_order_overwrite = SSP_AMP_LINK_ORDER; - dai_links = sof_card_dai_links_create(&pdev->dev, ctx->amp_type, - ctx->ssp_amp, ctx->dmic_be_num, - ctx->hdmi_num, - ctx->hdmi.idisp_codec); - if (!dai_links) - return -ENOMEM; + if (ctx->ssp_mask_hdmi_in) { + /* the topology supports HDMI-IN uses fixed BE ID for DAI links */ + ctx->link_id_overwrite = SSP_AMP_LINK_IDS; + } - sof_ssp_amp_card.dai_link = dai_links; + /* update dai_link */ + ret = sof_card_dai_links_create(&pdev->dev, &sof_ssp_amp_card, ctx); + if (ret) + return ret; /* update codec_conf */ switch (ctx->amp_type) { case CODEC_CS35L41: cs35l41_set_codec_conf(&sof_ssp_amp_card); break; - case CODEC_NONE: case CODEC_RT1308: + case CODEC_NONE: /* no codec conf required */ break; default: @@ -292,38 +180,41 @@ static const struct platform_device_id board_ids[] = { }, { .name = "tgl_rt1308_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(2) | - SOF_HDMI_CAPTURE_SSP_MASK(0x22)), + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(2) | + SOF_SSP_MASK_HDMI_CAPTURE(0x22)), /* SSP 1 and SSP 5 are used for HDMI IN */ }, { .name = "adl_cs35l41", - .driver_data = (kernel_ulong_t)(SOF_AMPLIFIER_SSP(1) | - SOF_NO_OF_HDMI_PLAYBACK(4) | + .driver_data = (kernel_ulong_t)(SOF_SSP_PORT_AMP(1) | + SOF_NUM_IDISP_HDMI(4) | SOF_HDMI_PLAYBACK_PRESENT | - SOF_BT_OFFLOAD_SSP(2) | - SOF_SSP_BT_OFFLOAD_PRESENT), + SOF_SSP_PORT_BT_OFFLOAD(2) | + SOF_BT_OFFLOAD_PRESENT), }, { .name = "adl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "rpl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | SOF_HDMI_PLAYBACK_PRESENT), }, { .name = "mtl_lt6911_hdmi_ssp", - .driver_data = (kernel_ulong_t)(SOF_HDMI_CAPTURE_SSP_MASK(0x5) | - /* SSP 0 and SSP 2 are used for HDMI IN */ - SOF_NO_OF_HDMI_PLAYBACK(3) | - SOF_HDMI_PLAYBACK_PRESENT), + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), + }, + { + .name = "arl_lt6911_hdmi_ssp", + .driver_data = (kernel_ulong_t)(SOF_SSP_MASK_HDMI_CAPTURE(0x5) | + /* SSP 0 and SSP 2 are used for HDMI IN */ + SOF_HDMI_PLAYBACK_PRESENT), }, { } }; @@ -343,7 +234,6 @@ MODULE_DESCRIPTION("ASoC Intel(R) SOF Amplifier Machine driver"); MODULE_AUTHOR("Balamurugan C <balamurugan.c@intel.com>"); MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL"); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_REALTEK_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_CIRRUS_COMMON); -MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_BOARD_HELPERS"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_REALTEK_COMMON"); +MODULE_IMPORT_NS("SND_SOC_INTEL_SOF_CIRRUS_COMMON"); diff --git a/sound/soc/intel/boards/sof_ssp_common.c b/sound/soc/intel/boards/sof_ssp_common.c deleted file mode 100644 index 96072790e9c0..000000000000 --- a/sound/soc/intel/boards/sof_ssp_common.c +++ /dev/null @@ -1,122 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// -// Copyright(c) 2023 Intel Corporation. All rights reserved. - -#include <linux/device.h> -#include <sound/soc-acpi.h> -#include "sof_ssp_common.h" - -/* - * Codec probe function - */ -#define CODEC_MAP_ENTRY(n, h, t) \ - { \ - .name = n, \ - .acpi_hid = h, \ - .codec_type = t, \ - } - -struct codec_map { - const char *name; - const char *acpi_hid; - enum sof_ssp_codec codec_type; -}; - -static const struct codec_map codecs[] = { - /* Cirrus Logic */ - CODEC_MAP_ENTRY("CS42L42", CS42L42_ACPI_HID, CODEC_CS42L42), - - /* Dialog */ - CODEC_MAP_ENTRY("DA7219", DA7219_ACPI_HID, CODEC_DA7219), - - /* Everest */ - CODEC_MAP_ENTRY("ES8316", ES8316_ACPI_HID, CODEC_ES8316), - CODEC_MAP_ENTRY("ES8326", ES8326_ACPI_HID, CODEC_ES8326), - CODEC_MAP_ENTRY("ES8336", ES8336_ACPI_HID, CODEC_ES8336), - - /* Nuvoton */ - CODEC_MAP_ENTRY("NAU8825", NAU8825_ACPI_HID, CODEC_NAU8825), - - /* Realtek */ - CODEC_MAP_ENTRY("RT5650", RT5650_ACPI_HID, CODEC_RT5650), - CODEC_MAP_ENTRY("RT5682", RT5682_ACPI_HID, CODEC_RT5682), - CODEC_MAP_ENTRY("RT5682S", RT5682S_ACPI_HID, CODEC_RT5682S), -}; - -static const struct codec_map amps[] = { - /* Cirrus Logic */ - CODEC_MAP_ENTRY("CS35L41", CS35L41_ACPI_HID, CODEC_CS35L41), - - /* Maxim */ - CODEC_MAP_ENTRY("MAX98357A", MAX_98357A_ACPI_HID, CODEC_MAX98357A), - CODEC_MAP_ENTRY("MAX98360A", MAX_98360A_ACPI_HID, CODEC_MAX98360A), - CODEC_MAP_ENTRY("MAX98373", MAX_98373_ACPI_HID, CODEC_MAX98373), - CODEC_MAP_ENTRY("MAX98390", MAX_98390_ACPI_HID, CODEC_MAX98390), - - /* Nuvoton */ - CODEC_MAP_ENTRY("NAU8318", NAU8318_ACPI_HID, CODEC_NAU8318), - - /* Realtek */ - CODEC_MAP_ENTRY("RT1011", RT1011_ACPI_HID, CODEC_RT1011), - CODEC_MAP_ENTRY("RT1015", RT1015_ACPI_HID, CODEC_RT1015), - CODEC_MAP_ENTRY("RT1015P", RT1015P_ACPI_HID, CODEC_RT1015P), - CODEC_MAP_ENTRY("RT1019P", RT1019P_ACPI_HID, CODEC_RT1019P), - CODEC_MAP_ENTRY("RT1308", RT1308_ACPI_HID, CODEC_RT1308), -}; - -enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(codecs); i++) { - if (!acpi_dev_present(codecs[i].acpi_hid, NULL, -1)) - continue; - - dev_dbg(dev, "codec %s found\n", codecs[i].name); - return codecs[i].codec_type; - } - - return CODEC_NONE; -} -EXPORT_SYMBOL_NS(sof_ssp_detect_codec_type, SND_SOC_INTEL_SOF_SSP_COMMON); - -enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(amps); i++) { - if (!acpi_dev_present(amps[i].acpi_hid, NULL, -1)) - continue; - - dev_dbg(dev, "amp %s found\n", amps[i].name); - return amps[i].codec_type; - } - - return CODEC_NONE; -} -EXPORT_SYMBOL_NS(sof_ssp_detect_amp_type, SND_SOC_INTEL_SOF_SSP_COMMON); - -const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(codecs); i++) { - if (codecs[i].codec_type != codec_type) - continue; - - return codecs[i].name; - } - for (i = 0; i < ARRAY_SIZE(amps); i++) { - if (amps[i].codec_type != codec_type) - continue; - - return amps[i].name; - } - - return NULL; -} -EXPORT_SYMBOL_NS(sof_ssp_get_codec_name, SND_SOC_INTEL_SOF_SSP_COMMON); - -MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers"); -MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/boards/sof_ssp_common.h b/sound/soc/intel/boards/sof_ssp_common.h deleted file mode 100644 index d24888bc99fd..000000000000 --- a/sound/soc/intel/boards/sof_ssp_common.h +++ /dev/null @@ -1,80 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Copyright(c) 2023 Intel Corporation. - */ - -#ifndef __SOF_SSP_COMMON_H -#define __SOF_SSP_COMMON_H - -/* Cirrus Logic */ -#define CS35L41_ACPI_HID "CSC3541" -#define CS42L42_ACPI_HID "10134242" - -/* Dialog */ -#define DA7219_ACPI_HID "DLGS7219" - -/* Everest */ -#define ES8316_ACPI_HID "ESSX8316" -#define ES8326_ACPI_HID "ESSX8326" -#define ES8336_ACPI_HID "ESSX8336" - -#define MAX_98357A_ACPI_HID "MX98357A" -#define MAX_98360A_ACPI_HID "MX98360A" -#define MAX_98373_ACPI_HID "MX98373" -#define MAX_98390_ACPI_HID "MX98390" - -/* Nuvoton */ -#define NAU8318_ACPI_HID "NVTN2012" -#define NAU8825_ACPI_HID "10508825" - -/* Realtek */ -#define RT1011_ACPI_HID "10EC1011" -#define RT1015_ACPI_HID "10EC1015" -#define RT1015P_ACPI_HID "RTL1015" -#define RT1019P_ACPI_HID "RTL1019" -#define RT1308_ACPI_HID "10EC1308" -#define RT5650_ACPI_HID "10EC5650" -#define RT5682_ACPI_HID "10EC5682" -#define RT5682S_ACPI_HID "RTL5682" - -enum sof_ssp_codec { - CODEC_NONE, - - /* headphone codec */ - CODEC_CS42L42, - CODEC_DA7219, - CODEC_ES8316, - CODEC_ES8326, - CODEC_ES8336, - CODEC_NAU8825, - CODEC_RT5650, - CODEC_RT5682, - CODEC_RT5682S, - - /* speaker amplifier */ - CODEC_CS35L41, - CODEC_MAX98357A, - CODEC_MAX98360A, - CODEC_MAX98373, - CODEC_MAX98390, - CODEC_NAU8318, - CODEC_RT1011, - CODEC_RT1015, - CODEC_RT1015P, - CODEC_RT1019P, - CODEC_RT1308, -}; - -enum sof_ssp_codec sof_ssp_detect_codec_type(struct device *dev); -enum sof_ssp_codec sof_ssp_detect_amp_type(struct device *dev); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SOF_SSP_COMMON) -const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type); -#else -static inline const char *sof_ssp_get_codec_name(enum sof_ssp_codec codec_type) -{ - return NULL; -} -#endif - -#endif /* __SOF_SSP_COMMON_H */ diff --git a/sound/soc/intel/boards/sof_wm8804.c b/sound/soc/intel/boards/sof_wm8804.c index 4cb0d463bf40..51922347409f 100644 --- a/sound/soc/intel/boards/sof_wm8804.c +++ b/sound/soc/intel/boards/sof_wm8804.c @@ -148,7 +148,7 @@ static int sof_wm8804_hw_params(struct snd_pcm_substream *substream, } /* machine stream operations */ -static struct snd_soc_ops sof_wm8804_ops = { +static const struct snd_soc_ops sof_wm8804_ops = { .hw_params = sof_wm8804_hw_params, }; @@ -167,8 +167,6 @@ static struct snd_soc_dai_link dailink[] = { .name = "SSP5-Codec", .id = 0, .no_pcm = 1, - .dpcm_playback = 1, - .dpcm_capture = 1, .ops = &sof_wm8804_ops, SND_SOC_DAILINK_REG(ssp5_pin, ssp5_codec, platform), }, @@ -270,7 +268,11 @@ static int sof_wm8804_probe(struct platform_device *pdev) snprintf(codec_name, sizeof(codec_name), "%s%s", "i2c-", acpi_dev_name(adev)); dailink[dai_index].codecs->name = codec_name; + } else { + dev_err(&pdev->dev, "Error cannot find '%s' dev\n", mach->id); + return -ENOENT; } + acpi_dev_put(adev); snd_soc_card_set_drvdata(card, ctx); @@ -290,7 +292,7 @@ static struct platform_driver sof_wm8804_driver = { .pm = &snd_soc_pm_ops, }, .probe = sof_wm8804_probe, - .remove_new = sof_wm8804_remove, + .remove = sof_wm8804_remove, }; module_platform_driver(sof_wm8804_driver); diff --git a/sound/soc/intel/catpt/Makefile b/sound/soc/intel/catpt/Makefile index c393a45795da..f5f6a7e956ce 100644 --- a/sound/soc/intel/catpt/Makefile +++ b/sound/soc/intel/catpt/Makefile @@ -1,4 +1,4 @@ -snd-soc-catpt-objs := device.o dsp.o loader.o ipc.o messages.o pcm.o sysfs.o +snd-soc-catpt-y := device.o dsp.o loader.o ipc.o messages.o pcm.o sysfs.o # tell define_trace.h where to find the trace header CFLAGS_device.o := -I$(src) diff --git a/sound/soc/intel/catpt/core.h b/sound/soc/intel/catpt/core.h index a64a0a77dcb7..c01d27e9fd88 100644 --- a/sound/soc/intel/catpt/core.h +++ b/sound/soc/intel/catpt/core.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2020 Intel Corporation * * Author: Cezary Rojewski <cezary.rojewski@intel.com> */ diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index cac3dffbd0d9..faa916f40069 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // @@ -28,7 +28,7 @@ #define CREATE_TRACE_POINTS #include "trace.h" -static int __maybe_unused catpt_suspend(struct device *dev) +static int catpt_suspend(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); struct dma_chan *chan; @@ -72,7 +72,7 @@ release_dma_chan: return catpt_dsp_power_down(cdev); } -static int __maybe_unused catpt_resume(struct device *dev) +static int catpt_resume(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); int ret, i; @@ -106,7 +106,7 @@ static int __maybe_unused catpt_resume(struct device *dev) return 0; } -static int __maybe_unused catpt_runtime_suspend(struct device *dev) +static int catpt_runtime_suspend(struct device *dev) { if (!try_module_get(dev->driver->owner)) { dev_info(dev, "module unloading, skipping suspend\n"); @@ -117,14 +117,14 @@ static int __maybe_unused catpt_runtime_suspend(struct device *dev) return catpt_suspend(dev); } -static int __maybe_unused catpt_runtime_resume(struct device *dev) +static int catpt_runtime_resume(struct device *dev) { return catpt_resume(dev); } static const struct dev_pm_ops catpt_dev_pm = { - SET_SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume) - SET_RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume) + RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL) }; /* machine board owned by CATPT is removed with this hook */ @@ -374,11 +374,11 @@ MODULE_DEVICE_TABLE(acpi, catpt_ids); static struct platform_driver catpt_acpi_driver = { .probe = catpt_acpi_probe, - .remove_new = catpt_acpi_remove, + .remove = catpt_acpi_remove, .driver = { .name = "intel_catpt", .acpi_match_table = catpt_ids, - .pm = &catpt_dev_pm, + .pm = pm_ptr(&catpt_dev_pm), .dev_groups = catpt_attr_groups, }, }; diff --git a/sound/soc/intel/catpt/dsp.c b/sound/soc/intel/catpt/dsp.c index 5454c6d9ab5b..008a20a2acbd 100644 --- a/sound/soc/intel/catpt/dsp.c +++ b/sound/soc/intel/catpt/dsp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // @@ -156,7 +156,7 @@ static void catpt_dsp_set_srampge(struct catpt_dev *cdev, struct resource *sram, { unsigned long old; u32 off = sram->start; - u32 b = __ffs(mask); + unsigned long b = __ffs(mask); old = catpt_readl_pci(cdev, VDRTCTL0) & mask; dev_dbg(cdev->dev, "SRAMPGE [0x%08lx] 0x%08lx -> 0x%08lx", diff --git a/sound/soc/intel/catpt/ipc.c b/sound/soc/intel/catpt/ipc.c index 5b718a846fda..d26863249097 100644 --- a/sound/soc/intel/catpt/ipc.c +++ b/sound/soc/intel/catpt/ipc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/intel/catpt/loader.c b/sound/soc/intel/catpt/loader.c index ff7b8f0d34ac..696d84314eeb 100644 --- a/sound/soc/intel/catpt/loader.c +++ b/sound/soc/intel/catpt/loader.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/intel/catpt/messages.c b/sound/soc/intel/catpt/messages.c index a793d114afa4..30eec2de4dc1 100644 --- a/sound/soc/intel/catpt/messages.c +++ b/sound/soc/intel/catpt/messages.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/intel/catpt/messages.h b/sound/soc/intel/catpt/messages.h index c17e948d9f52..a634943eb669 100644 --- a/sound/soc/intel/catpt/messages.h +++ b/sound/soc/intel/catpt/messages.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2020 Intel Corporation * * Author: Cezary Rojewski <cezary.rojewski@intel.com> */ diff --git a/sound/soc/intel/catpt/pcm.c b/sound/soc/intel/catpt/pcm.c index 3daf5eb37f7b..81a2f0339e05 100644 --- a/sound/soc/intel/catpt/pcm.c +++ b/sound/soc/intel/catpt/pcm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/intel/catpt/registers.h b/sound/soc/intel/catpt/registers.h index 47280d82842e..6c1ad28c6d69 100644 --- a/sound/soc/intel/catpt/registers.h +++ b/sound/soc/intel/catpt/registers.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2020 Intel Corporation * * Author: Cezary Rojewski <cezary.rojewski@intel.com> */ diff --git a/sound/soc/intel/catpt/sysfs.c b/sound/soc/intel/catpt/sysfs.c index 9b6d2d93a2e7..936ac9d503ff 100644 --- a/sound/soc/intel/catpt/sysfs.c +++ b/sound/soc/intel/catpt/sysfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only // -// Copyright(c) 2020 Intel Corporation. All rights reserved. +// Copyright(c) 2020 Intel Corporation // // Author: Cezary Rojewski <cezary.rojewski@intel.com> // diff --git a/sound/soc/intel/catpt/trace.h b/sound/soc/intel/catpt/trace.h index bb3d627dbeaf..010f57b6a7a8 100644 --- a/sound/soc/intel/catpt/trace.h +++ b/sound/soc/intel/catpt/trace.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright(c) 2020 Intel Corporation. All rights reserved. + * Copyright(c) 2020 Intel Corporation * * Author: Cezary Rojewski <cezary.rojewski@intel.com> */ diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index f7370e5b4e9e..7822bcae6c69 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,7 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sst-dsp-objs := sst-dsp.o -snd-soc-sst-ipc-objs := sst-ipc.o -snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \ +snd-soc-acpi-intel-match-y := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-match.o \ soc-acpi-intel-hsw-bdw-match.o \ soc-acpi-intel-skl-match.o soc-acpi-intel-kbl-match.o \ soc-acpi-intel-bxt-match.o soc-acpi-intel-glk-match.o \ @@ -12,8 +10,13 @@ snd-soc-acpi-intel-match-objs := soc-acpi-intel-byt-match.o soc-acpi-intel-cht-m soc-acpi-intel-rpl-match.o soc-acpi-intel-mtl-match.o \ soc-acpi-intel-arl-match.o \ soc-acpi-intel-lnl-match.o \ + soc-acpi-intel-ptl-match.o \ soc-acpi-intel-hda-match.o \ - soc-acpi-intel-sdw-mockup-match.o + soc-acpi-intel-sdw-mockup-match.o sof-function-topology-lib.o + +snd-soc-acpi-intel-match-y += soc-acpi-intel-ssp-common.o + +snd-soc-acpi-intel-sdca-quirks-y += soc-acpi-intel-sdca-quirks.o -obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_ACPI_INTEL_MATCH) += snd-soc-acpi-intel-match.o +obj-$(CONFIG_SND_SOC_ACPI_INTEL_SDCA_QUIRKS) += snd-soc-acpi-intel-sdca-quirks.o diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index 0da79a3ba1f0..a68efbe98948 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -7,6 +7,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include <sound/soc-acpi-intel-ssp-common.h> static const struct snd_soc_acpi_codecs essx_83x6 = { .num_codecs = 3, @@ -34,6 +35,86 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { + { + .adr = 0x00023201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00023301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -133,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = { + { + .adr = 0x000232025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + static const struct snd_soc_acpi_adr_device rt1316_1_single_adr[] = { { .adr = 0x000130025D131601ull, @@ -415,6 +505,25 @@ static const struct snd_soc_acpi_adr_device rt5682_0_adr[] = { } }; +static const struct snd_soc_acpi_link_adr adl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r_adr), + .adr_d = cs35l56_2_r_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l_adr), + .adr_d = cs35l56_3_l_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr adl_rvp[] = { { .mask = BIT(0), @@ -447,9 +556,18 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = { {} }; -static const struct snd_soc_acpi_codecs adl_max98373_amp = { - .num_codecs = 1, - .codecs = {"MX98373"} +static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link02[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt1316_0_group2_adr), + .adr_d = rt1316_0_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group2_adr), + .adr_d = rt1316_2_group2_adr, + }, + {} }; static const struct snd_soc_acpi_codecs adl_max98357a_amp = { @@ -457,19 +575,9 @@ static const struct snd_soc_acpi_codecs adl_max98357a_amp = { .codecs = {"MX98357A"} }; -static const struct snd_soc_acpi_codecs adl_max98360a_amp = { - .num_codecs = 1, - .codecs = {"MX98360A"} -}; - static const struct snd_soc_acpi_codecs adl_rt5682_rt5682s_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, -}; - -static const struct snd_soc_acpi_codecs adl_rt1015p_amp = { - .num_codecs = 1, - .codecs = {"RTL1015"} + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs adl_rt1019p_amp = { @@ -477,49 +585,20 @@ static const struct snd_soc_acpi_codecs adl_rt1019p_amp = { .codecs = {"RTL1019"} }; -static const struct snd_soc_acpi_codecs adl_max98390_amp = { - .num_codecs = 1, - .codecs = {"MX98390"} -}; - static const struct snd_soc_acpi_codecs adl_lt6911_hdmi = { .num_codecs = 1, .codecs = {"INTC10B0"} }; -static const struct snd_soc_acpi_codecs adl_nau8318_amp = { - .num_codecs = 1, - .codecs = {"NVTN2012"} -}; - -static struct snd_soc_acpi_codecs adl_rt5650_amp = { - .num_codecs = 1, - .codecs = {"10EC5650"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { { .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98373_amp, - .sof_tplg_filename = "sof-adl-max98373-rt5682.tplg", - }, - { - .comp_ids = &adl_rt5682_rt5682s_hp, .drv_name = "adl_mx98357_rt5682", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &adl_max98357a_amp, .sof_tplg_filename = "sof-adl-max98357a-rt5682.tplg", }, { - .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-max98360a-rt5682.tplg", - }, - { .id = "10508825", .drv_name = "adl_rt1019p_8825", .machine_quirk = snd_soc_acpi_codec_list, @@ -527,53 +606,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_tplg_filename = "sof-adl-rt1019-nau8825.tplg", }, { - .id = "10508825", - .drv_name = "adl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98373_amp, - .sof_tplg_filename = "sof-adl-max98373-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "adl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-max98360a-nau8825.tplg", - }, - { - .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_rt1019p_amp, - .sof_tplg_filename = "sof-adl-rt1019-rt5682.tplg", - }, - { - .id = "10508825", - .drv_name = "adl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_rt1015p_amp, - .sof_tplg_filename = "sof-adl-rt1015-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "adl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_nau8318_amp, - .sof_tplg_filename = "sof-adl-nau8318-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "sof_nau8825", - .sof_tplg_filename = "sof-adl-nau8825.tplg", - }, - { - .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98390_amp, - .sof_tplg_filename = "sof-adl-max98390-rt5682.tplg", - }, - { .comp_ids = &adl_rt5682_rt5682s_hp, .drv_name = "adl_rt5682_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -581,18 +613,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { .sof_tplg_filename = "sof-adl-rt5682-ssp1-hdmi-ssp02.tplg", }, { - .comp_ids = &adl_rt5682_rt5682s_hp, - .drv_name = "adl_rt5682_def", - .sof_tplg_filename = "sof-adl-rt5682.tplg", - }, - { - .id = "10134242", - .drv_name = "adl_mx98360a_cs4242", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-max98360a-cs42l42.tplg", - }, - { .comp_ids = &essx_83x6, .drv_name = "adl_es83x6_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -607,19 +627,43 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + /* place boards for each headphone codec: sof driver will complete the + * tplg name and machine driver will detect the amp type + */ + { + .id = CS42L42_ACPI_HID, + .drv_name = "adl_cs42l42_def", + .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = DA7219_ACPI_HID, + .drv_name = "adl_da7219_def", + .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, { - .id = "10EC5650", + .id = NAU8825_ACPI_HID, + .drv_name = "adl_nau8825_def", + .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = RT5650_ACPI_HID, .drv_name = "adl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_rt5650_amp, - .sof_tplg_filename = "sof-adl-rt5650.tplg", + .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, { - .id = "DLGS7219", - .drv_name = "adl_mx98360_da7219", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &adl_max98360a_amp, - .sof_tplg_filename = "sof-adl-max98360a-da7219.tplg", + .comp_ids = &adl_rt5682_rt5682s_hp, + .drv_name = "adl_rt5682_def", + .sof_tplg_filename = "sof-adl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, /* place amp-only boards in the end of table */ { @@ -639,6 +683,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = adl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-cs42l43-l0-cs35l56-l23.tplg", + }, + { .link_mask = 0xF, /* 4 active links required */ .links = adl_default, .drv_name = "sof_sdw", @@ -722,6 +772,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-adl-sdw-max98373-rt5682.tplg", }, + { + .link_mask = BIT(0) | BIT(2), + .links = adl_sdw_rt1316_link02, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt1316-l02.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-arl-match.c b/sound/soc/intel/common/soc-acpi-intel-arl-match.c index e52797aae6e6..73e581e93755 100644 --- a/sound/soc/intel/common/soc-acpi-intel-arl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-arl-match.c @@ -7,6 +7,8 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include <sound/soc-acpi-intel-ssp-common.h> +#include "sof-function-topology-lib.h" static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, @@ -15,6 +17,200 @@ static const struct snd_soc_acpi_endpoint single_endpoint = { .group_id = 0, }; +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +/* + * RT722 is a multi-function codec, three endpoints are created for + * its headset, amp and dmic functions. + */ +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = { + { + .adr = 0x00023001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = { + { + .adr = 0x00033001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033401FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { + { + .adr = 0x00023201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00023301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r1_adr[] = { + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l3_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_r3_adr[] = { + { + .adr = 0x00023301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_l1_adr[] = { + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -24,6 +220,136 @@ static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025D072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l2[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l2_cs35l56_l3[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr), + .adr_d = cs35l56_3_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_l2[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_lr_adr), + .adr_d = cs35l56_2_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r_adr), + .adr_d = cs35l56_2_r_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l_adr), + .adr_d = cs35l56_3_l_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_2_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r1_adr), + .adr_d = cs35l56_2_r1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l3_adr), + .adr_d = cs35l56_3_l3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_cs42l43_l0_cs35l56_3_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_r3_adr), + .adr_d = cs35l56_2_r3_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_l1_adr), + .adr_d = cs35l56_3_l1_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr arl_rvp[] = { { .mask = BIT(0), @@ -33,7 +359,73 @@ static const struct snd_soc_acpi_link_adr arl_rvp[] = { {} }; +static const struct snd_soc_acpi_link_adr arl_sdca_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_single_adr), + .adr_d = rt1320_2_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_codecs arl_essx_83x6 = { + .num_codecs = 3, + .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, +}; + +static const struct snd_soc_acpi_codecs arl_rt5682_hp = { + .num_codecs = 2, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, +}; + +static const struct snd_soc_acpi_codecs arl_lt6911_hdmi = { + .num_codecs = 1, + .codecs = {"INTC10B0"} +}; + struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[] = { + { + .comp_ids = &arl_essx_83x6, + .drv_name = "arl_es83x6_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &arl_lt6911_hdmi, + .sof_tplg_filename = "sof-arl-es83x6-ssp1-hdmi-ssp02.tplg", + }, + { + .comp_ids = &arl_essx_83x6, + .drv_name = "sof-essx8336", + .sof_tplg_filename = "sof-arl-es8336", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER | + SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | + SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, + }, + { + .comp_ids = &arl_rt5682_hp, + .drv_name = "arl_rt5682_c1_h02", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &arl_lt6911_hdmi, + .sof_tplg_filename = "sof-arl-rt5682-ssp1-hdmi-ssp02.tplg", + }, + /* place amp-only boards in the end of table */ + { + .id = "INTC10B0", + .drv_name = "arl_lt6911_hdmi_ssp", + .sof_tplg_filename = "sof-arl-hdmi-ssp02.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines); @@ -41,11 +433,73 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = { { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_2_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = arl_cs42l43_l0_cs35l56_3_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(2), + .links = arl_cs42l43_l0_cs35l56_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0), + .links = arl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(2), + .links = arl_cs42l43_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(2) | BIT(3), + .links = arl_cs42l43_l2_cs35l56_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { .link_mask = 0x1, /* link0 required */ .links = arl_rvp, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-arl-rt711.tplg", }, + { + .link_mask = 0x1, /* link0 required */ + .links = arl_sdca_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-rt711-l0.tplg", + }, + { + .link_mask = BIT(0) | BIT(2), + .links = arl_rt722_l0_rt1320_l2, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-arl-rt722-l0_rt1320-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_arl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-cht-match.c b/sound/soc/intel/common/soc-acpi-intel-cht-match.c index 5e2ec60e2954..e4c3492a0c28 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cht-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cht-match.c @@ -84,7 +84,6 @@ static const struct dmi_system_id lenovo_yoga_tab3_x90[] = { /* Lenovo Yoga Tab 3 Pro YT3-X90, codec missing from DSDT */ .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"), DMI_MATCH(DMI_PRODUCT_VERSION, "Blade3-10A-001"), }, }, diff --git a/sound/soc/intel/common/soc-acpi-intel-cml-match.c b/sound/soc/intel/common/soc-acpi-intel-cml-match.c index 5eab17820532..f79d7558174a 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cml-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cml-match.c @@ -42,40 +42,40 @@ static const struct snd_soc_acpi_codecs max98390_spk_codecs = { struct snd_soc_acpi_mach snd_soc_acpi_intel_cml_machines[] = { { .id = "10EC5682", - .drv_name = "cml_rt1011_rt5682", + .drv_name = "cml_rt5682_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rt1011_spk_codecs, .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", }, { .id = "10EC5682", - .drv_name = "cml_rt1015_rt5682", + .drv_name = "cml_rt5682_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rt1015_spk_codecs, .sof_tplg_filename = "sof-cml-rt1011-rt5682.tplg", }, { .id = "10EC5682", - .drv_name = "sof_rt5682", + .drv_name = "cml_rt5682_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &max98357a_spk_codecs, .sof_tplg_filename = "sof-cml-rt5682-max98357a.tplg", }, { .id = "10EC5682", - .drv_name = "sof_rt5682", + .drv_name = "cml_rt5682_def", .sof_tplg_filename = "sof-cml-rt5682.tplg", }, { .id = "DLGS7219", - .drv_name = "cml_da7219_mx98357a", + .drv_name = "cml_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &max98357a_spk_codecs, .sof_tplg_filename = "sof-cml-da7219-max98357a.tplg", }, { .id = "DLGS7219", - .drv_name = "cml_da7219_mx98357a", + .drv_name = "cml_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &max98390_spk_codecs, .sof_tplg_filename = "sof-cml-da7219-max98390.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c index 3df89e4511da..8bbb1052faf2 100644 --- a/sound/soc/intel/common/soc-acpi-intel-cnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-cnl-match.c @@ -8,7 +8,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" #include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs essx_83x6 = { @@ -16,16 +15,11 @@ static const struct snd_soc_acpi_codecs essx_83x6 = { .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; -static struct skl_machine_pdata cnl_pdata = { - .use_tplg_pcm = true, -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_machines[] = { { .id = "INT34C2", .drv_name = "cnl_rt274", .fw_filename = "intel/dsp_fw_cnl.bin", - .pdata = &cnl_pdata, .sof_tplg_filename = "sof-cnl-rt274.tplg", }, { diff --git a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c index 84639c41a268..78255d56b08c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ehl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ehl-match.c @@ -8,7 +8,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" struct snd_soc_acpi_mach snd_soc_acpi_intel_ehl_machines[] = { { diff --git a/sound/soc/intel/common/soc-acpi-intel-glk-match.c b/sound/soc/intel/common/soc-acpi-intel-glk-match.c index 8911c90bbaf6..c82c8c93d200 100644 --- a/sound/soc/intel/common/soc-acpi-intel-glk-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-glk-match.c @@ -33,7 +33,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { }, { .id = "DLGS7219", - .drv_name = "glk_da7219_mx98357a", + .drv_name = "glk_da7219_def", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, @@ -41,7 +41,7 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_glk_machines[] = { }, { .comp_ids = &glk_rt5682_rt5682s_hp, - .drv_name = "glk_rt5682_mx98357a", + .drv_name = "glk_rt5682_def", .fw_filename = "intel/dsp_fw_glk.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &glk_codecs, diff --git a/sound/soc/intel/common/soc-acpi-intel-hda-match.c b/sound/soc/intel/common/soc-acpi-intel-hda-match.c index 2017fd0d676f..e93336e27beb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-hda-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-hda-match.c @@ -8,27 +8,13 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" - -static struct skl_machine_pdata hda_pdata = { - .use_tplg_pcm = true, -}; struct snd_soc_acpi_mach snd_soc_acpi_intel_hda_machines[] = { { /* .id is not used in this file */ .drv_name = "skl_hda_dsp_generic", - - /* .fw_filename is dynamically set in skylake driver */ - - .sof_tplg_filename = "sof-hda-generic.tplg", - - /* - * .machine_quirk and .quirk_data are not used here but - * can be used if we need a more complicated machine driver - * combining HDA+other device (e.g. DMIC). - */ - .pdata = &hda_pdata, + .sof_tplg_filename = "sof-hda-generic", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-icl-match.c b/sound/soc/intel/common/soc-acpi-intel-icl-match.c index d0062f2cd256..6ce75fbb842e 100644 --- a/sound/soc/intel/common/soc-acpi-intel-icl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-icl-match.c @@ -8,28 +8,22 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" static const struct snd_soc_acpi_codecs essx_83x6 = { .num_codecs = 3, .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; -static struct skl_machine_pdata icl_pdata = { - .use_tplg_pcm = true, -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_icl_machines[] = { { .id = "INT34C2", .drv_name = "icl_rt274", .fw_filename = "intel/dsp_fw_icl.bin", - .pdata = &icl_pdata, .sof_tplg_filename = "sof-icl-rt274.tplg", }, { .id = "10EC5682", - .drv_name = "sof_rt5682", + .drv_name = "icl_rt5682_def", .sof_tplg_filename = "sof-icl-rt5682.tplg", }, { diff --git a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c index a6ac2525df17..d4b397c53bcc 100644 --- a/sound/soc/intel/common/soc-acpi-intel-jsl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-jsl-match.c @@ -52,14 +52,14 @@ static const struct snd_soc_acpi_codecs rt5682_rt5682s_hp = { struct snd_soc_acpi_mach snd_soc_acpi_intel_jsl_machines[] = { { .id = "DLGS7219", - .drv_name = "jsl_mx98373_da7219", + .drv_name = "jsl_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98373_spk, .sof_tplg_filename = "sof-jsl-da7219.tplg", }, { .id = "DLGS7219", - .drv_name = "jsl_mx98360_da7219", + .drv_name = "jsl_da7219_def", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &mx98360a_spk, .sof_tplg_filename = "sof-jsl-da7219-mx98360a.tplg", diff --git a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c index 4e817f559d38..d4c158d8441b 100644 --- a/sound/soc/intel/common/soc-acpi-intel-kbl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-kbl-match.c @@ -8,9 +8,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" - -static struct skl_machine_pdata skl_dmic_data; static const struct snd_soc_acpi_codecs kbl_codecs = { .num_codecs = 1, @@ -54,7 +51,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98357A", @@ -62,7 +58,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98927", @@ -70,7 +65,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_5663_5514_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98927", @@ -78,7 +72,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_poppy_codecs, - .pdata = &skl_dmic_data, }, { .id = "10EC5663", @@ -91,7 +84,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98357_codecs, - .pdata = &skl_dmic_data, }, { .id = "DLGS7219", @@ -99,7 +91,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98927_codecs, - .pdata = &skl_dmic_data }, { .id = "10EC5660", @@ -117,13 +108,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_kbl_machines[] = { .fw_filename = "intel/dsp_fw_kbl.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &kbl_7219_98373_codecs, - .pdata = &skl_dmic_data }, { .id = "MX98373", .drv_name = "kbl_max98373", .fw_filename = "intel/dsp_fw_kbl.bin", - .pdata = &skl_dmic_data }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 74d6dcd7471f..558dc4c91239 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -2,12 +2,14 @@ /* * soc-acpi-intel-lnl-match.c - tables and support for LNL ACPI enumeration. * - * Copyright (c) 2023, Intel Corporation. All rights reserved. + * Copyright (c) 2023, Intel Corporation * */ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include "sof-function-topology-lib.h" +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[] = { @@ -36,6 +38,48 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_1_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_4_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_5_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_6_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, +}; + static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { { .num = 0, @@ -76,6 +120,206 @@ static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* DMIC Endpoint */ + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_2_l_adr[] = { + { + .adr = 0x00023001FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00023101FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_r_adr[] = { + { + .adr = 0x00033201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP3" + }, + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP4" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = { + { + .adr = 0x00033001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00033101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "AMP2" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = { + { + .adr = 0x00013001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_1_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00013101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + }, + { + .adr = 0x00013201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP3" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_4_endpoint, + .name_prefix = "AMP4" + }, + { + .adr = 0x00033401fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_5_endpoint, + .name_prefix = "AMP5" + }, + { + .adr = 0x00033501fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_6_endpoint, + .name_prefix = "AMP6" + } +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001fa424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints), + .endpoints = cs42l43_amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -103,6 +347,15 @@ static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { + { + .adr = 0x000230025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { { .adr = 0x000030025d072201ull, @@ -130,6 +383,87 @@ static const struct snd_soc_acpi_adr_device rt1316_3_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1318_1_adr[] = { + { + .adr = 0x000133025D131801ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1318-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { + { + .adr = 0x000130025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1318-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_2_group1_adr[] = { + { + .adr = 0x000232025D131801ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1318-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { + { + .adr = 0x000330025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-2" + } +}; + +static const struct snd_soc_acpi_adr_device rt713_0_adr[] = { + { + .adr = 0x000031025D071301ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt713" + } +}; + +static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = { + { + .adr = 0x000230025d071301ull, + .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints), + .endpoints = jack_dmic_endpoints, + .name_prefix = "rt713" + } +}; + +static const struct snd_soc_acpi_adr_device rt714_0_adr[] = { + { + .adr = 0x000030025D071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { { .adr = 0x000130025D071401ull, @@ -139,6 +473,67 @@ static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { } }; +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_lr_adr), + .adr_d = cs35l56_3_lr_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l23[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs35l56_2_l_adr), + .adr_d = cs35l56_2_l_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_r_adr), + .adr_d = cs35l56_3_r_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l2_cs35l56x6_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr), + .adr_d = cs35l56_1_3amp_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr), + .adr_d = cs35l56_3_3amp_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr lnl_rvp[] = { { .mask = BIT(0), @@ -195,6 +590,73 @@ static const struct snd_soc_acpi_link_adr lnl_3_in_1_sdca[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_sdw_rt1318_l12_rt714_l0[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_group1_adr), + .adr_d = rt1318_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1318_2_group1_adr), + .adr_d = rt1318_2_group1_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt714_0_adr), + .adr_d = rt714_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_l0_rt1318_l1[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt713_0_adr), + .adr_d = rt713_0_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_adr), + .adr_d = rt1318_1_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_sdw_rt713_vb_l2_rt1320_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt713_vb_2_adr), + .adr_d = rt713_vb_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1320_3_group2_adr), + .adr_d = rt1320_3_group2_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr lnl_sdw_rt712_vb_l2_rt1320_l1[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr), + .adr_d = rt712_vb_2_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group1_adr), + .adr_d = rt1320_1_group1_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { /* mockup tests need to be first */ @@ -217,12 +679,43 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = BIT(0), + .links = sdw_mockup_multi_func, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", /* Reuse the existing tplg file */ + }, + { .link_mask = GENMASK(3, 0), .links = lnl_3_in_1_sdca, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt711-l0-rt1316-l23-rt714-l1.tplg", }, { + .link_mask = BIT(0) | BIT(2) | BIT(3), + .links = lnl_cs42l43_l0_cs35l56_l23, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg", + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = lnl_cs42l43_l2_cs35l56x6_l13, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg", + }, + { + .link_mask = BIT(0) | BIT(3), + .links = lnl_cs42l43_l0_cs35l56_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l3.tplg", + }, + { + .link_mask = BIT(0), + .links = lnl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { .link_mask = BIT(0), .links = lnl_rvp, .drv_name = "sof_sdw", @@ -239,6 +732,35 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .links = lnl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = GENMASK(2, 0), + .links = lnl_sdw_rt1318_l12_rt714_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt1318-l12-rt714-l0.tplg" + }, + { + .link_mask = BIT(0) | BIT(1), + .links = lnl_sdw_rt713_l0_rt1318_l1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt713-l0-rt1318-l1.tplg" + }, + { + .link_mask = BIT(1) | BIT(2), + .links = lnl_sdw_rt712_vb_l2_rt1320_l1, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-lnl-rt712-l2-rt1320-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = lnl_sdw_rt713_vb_l2_rt1320_l13, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-lnl-rt713-l2-rt1320-l13.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c index e9a5da079089..75dc8935a794 100644 --- a/sound/soc/intel/common/soc-acpi-intel-mtl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-mtl-match.c @@ -6,28 +6,18 @@ * */ +#include <linux/soundwire/sdw_intel.h> +#include <sound/sdca.h> #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include <sound/soc-acpi-intel-ssp-common.h> +#include "sof-function-topology-lib.h" +#include "soc-acpi-intel-sdca-quirks.h" #include "soc-acpi-intel-sdw-mockup-match.h" -static const struct snd_soc_acpi_codecs mtl_max98357a_amp = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - -static const struct snd_soc_acpi_codecs mtl_max98360a_amp = { - .num_codecs = 1, - .codecs = {"MX98360A"} -}; - -static const struct snd_soc_acpi_codecs mtl_rt1019p_amp = { - .num_codecs = 1, - .codecs = {"RTL1019"} -}; - static const struct snd_soc_acpi_codecs mtl_rt5682_rt5682s_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs mtl_essx_83x6 = { @@ -40,34 +30,8 @@ static const struct snd_soc_acpi_codecs mtl_lt6911_hdmi = { .codecs = {"INTC10B0"} }; -static const struct snd_soc_acpi_codecs mtl_rt5650_amp = { - .num_codecs = 1, - .codecs = {"10EC5650"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_mx98357_rt5682", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_max98357a_amp, - .sof_tplg_filename = "sof-mtl-max98357a-rt5682.tplg", - }, - { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_mx98360_rt5682", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_max98360a_amp, - .sof_tplg_filename = "sof-mtl-max98360a-rt5682.tplg", - }, - { - .comp_ids = &mtl_rt5682_rt5682s_hp, - .drv_name = "mtl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_rt1019p_amp, - .sof_tplg_filename = "sof-mtl-rt1019-rt5682.tplg", - }, - { .comp_ids = &mtl_essx_83x6, .drv_name = "mtl_es83x6_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, @@ -83,11 +47,49 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, { - .id = "10EC5650", - .drv_name = "mtl_rt5682_def", + .comp_ids = &mtl_rt5682_rt5682s_hp, + .drv_name = "mtl_rt5682_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &mtl_rt5650_amp, - .sof_tplg_filename = "sof-mtl-rt5650.tplg", + .quirk_data = &mtl_lt6911_hdmi, + .sof_tplg_filename = "sof-mtl-rt5682-ssp1-hdmi-ssp02.tplg", + }, + /* place boards for each headphone codec: sof driver will complete the + * tplg name and machine driver will detect the amp type + */ + { + .id = CS42L42_ACPI_HID, + .drv_name = "mtl_cs42l42_def", + .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = DA7219_ACPI_HID, + .drv_name = "mtl_da7219_def", + .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = NAU8825_ACPI_HID, + .drv_name = "mtl_nau8825_def", + .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = RT5650_ACPI_HID, + .drv_name = "mtl_rt5682_def", + .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .comp_ids = &mtl_rt5682_rt5682s_hp, + .drv_name = "mtl_rt5682_def", + .sof_tplg_filename = "sof-mtl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, }, /* place amp-only boards in the end of table */ { @@ -135,6 +137,27 @@ static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint rt712_vb_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + /* * RT722 is a multi-function codec, three endpoints are created for * its headset, amp and dmic functions. @@ -192,6 +215,15 @@ static const struct snd_soc_acpi_adr_device rt712_0_single_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_0_single_adr[] = { + { + .adr = 0x000030025D071201ull, + .num_endpoints = ARRAY_SIZE(rt712_vb_endpoints), + .endpoints = rt712_vb_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt1712_3_single_adr[] = { { .adr = 0x000330025D171201ull, @@ -288,6 +320,24 @@ static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_3_single_adr[] = { + { + .adr = 0x000330025D131601ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1316-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1318_1_single_adr[] = { + { + .adr = 0x000130025D131801ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1318-1" + } +}; + static const struct snd_soc_acpi_adr_device rt1318_1_group1_adr[] = { { .adr = 0x000130025D131801ull, @@ -324,7 +374,7 @@ static const struct snd_soc_acpi_adr_device rt714_1_adr[] = { } }; -static const struct snd_soc_acpi_link_adr mtl_712_only[] = { +static const struct snd_soc_acpi_link_adr mtl_712_l0_1712_l3[] = { { .mask = BIT(0), .num_adr = ARRAY_SIZE(rt712_0_single_adr), @@ -338,27 +388,245 @@ static const struct snd_soc_acpi_link_adr mtl_712_only[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_712_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt712_0_single_adr), + .adr_d = rt712_0_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_712_vb_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt712_vb_0_single_adr), + .adr_d = rt712_vb_0_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { { .adr = 0x00003001FA424301ull, - .num_endpoints = 1, - .endpoints = &single_endpoint, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, .name_prefix = "cs42l43" } }; +/* CS42L43 - speaker DAI aggregated with 4 amps */ +static const struct snd_soc_acpi_endpoint cs42l43_4amp_spkagg_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 1, + .group_position = 4, + .group_id = 1, + }, +}; + +/* CS42L43 on link3 aggregated with 4 amps */ +static const struct snd_soc_acpi_adr_device cs42l43_l3_4amp_spkagg_adr[] = { + { + .adr = 0x00033001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_4amp_spkagg_endpoints), + .endpoints = cs42l43_4amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_endpoint cs35l56_l_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_r_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 1, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_2_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 2, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_3_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 3, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_4_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 4, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_5_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 5, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_6_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 6, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_7_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 7, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 7, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_0_adr[] = { + { + .adr = 0x00003301FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00003201FA355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + } +}; + static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { { .adr = 0x00013701FA355601ull, .num_endpoints = 1, .endpoints = &spk_r_endpoint, - .name_prefix = "AMP8" + .name_prefix = "AMP3" }, { .adr = 0x00013601FA355601ull, .num_endpoints = 1, .endpoints = &spk_3_endpoint, - .name_prefix = "AMP7" + .name_prefix = "AMP4" } }; @@ -377,17 +645,71 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs35l56_0_fb_adr[] = { + { + .adr = 0x00003301FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, + { + .adr = 0x00003201FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints), + .endpoints = cs35l56_2_fb_endpoints, + .name_prefix = "AMP2" + }, + { + .adr = 0x00003101FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints), + .endpoints = cs35l56_4_fb_endpoints, + .name_prefix = "AMP3" + }, + { + .adr = 0x00003001FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_6_fb_endpoints), + .endpoints = cs35l56_6_fb_endpoints, + .name_prefix = "AMP4" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_1_fb_adr[] = { + { + .adr = 0x00013701FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP8" + }, + { + .adr = 0x00013601FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP7" + }, + { + .adr = 0x00013501FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP6" + }, + { + .adr = 0x00013401FA355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_7_fb_endpoints), + .endpoints = cs35l56_7_fb_endpoints, + .name_prefix = "AMP5" + }, +}; + static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { { .adr = 0x00023201FA355601ull, - .num_endpoints = 1, - .endpoints = &spk_r_endpoint, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, .name_prefix = "AMP3" }, { .adr = 0x00023301FA355601ull, - .num_endpoints = 1, - .endpoints = &spk_3_endpoint, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, .name_prefix = "AMP4" } @@ -396,18 +718,36 @@ static const struct snd_soc_acpi_adr_device cs35l56_2_r_adr[] = { static const struct snd_soc_acpi_adr_device cs35l56_3_l_adr[] = { { .adr = 0x00033001fa355601ull, - .num_endpoints = 1, - .endpoints = &spk_l_endpoint, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, .name_prefix = "AMP1" }, { .adr = 0x00033101fa355601ull, - .num_endpoints = 1, - .endpoints = &spk_2_endpoint, + .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints), + .endpoints = cs35l56_2_fb_endpoints, .name_prefix = "AMP2" } }; +static const struct snd_soc_acpi_adr_device cs35l63_1_fb_adr[] = { + { + .adr = 0x00013001FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l63_3_fb_adr[] = { + { + .adr = 0x00033101FA356301ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP2" + }, +}; + static const struct snd_soc_acpi_link_adr rt5682_link2_max98373_link0[] = { /* Expected order: jack -> amp */ { @@ -508,6 +848,49 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12_rt1713_l3[] = {} }; +static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l1_rt1713_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt713_0_single_adr), + .adr_d = rt713_0_single_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_single_adr), + .adr_d = rt1318_1_single_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1713_3_single_adr), + .adr_d = rt1713_3_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1318_l12_rt1713_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt713_0_single_adr), + .adr_d = rt713_0_single_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1318_1_group1_adr), + .adr_d = rt1318_1_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1318_2_group1_adr), + .adr_d = rt1318_2_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1713_3_single_adr), + .adr_d = rt1713_3_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = { { .mask = BIT(0), @@ -527,6 +910,20 @@ static const struct snd_soc_acpi_link_adr mtl_rt713_l0_rt1316_l12[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_rt711_l0_rt1316_l3[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1316_3_single_adr), + .adr_d = rt1316_3_single_adr, + }, + {} +}; + static const struct snd_soc_acpi_adr_device mx8363_2_adr[] = { { .adr = 0x000230019F836300ull, @@ -566,6 +963,15 @@ static const struct snd_soc_acpi_link_adr cs42l42_link0_max98363_link2[] = { {} }; +static const struct snd_soc_acpi_link_adr mtl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr mtl_cs42l43_cs35l56[] = { { .mask = BIT(0), @@ -605,6 +1011,54 @@ static const struct snd_soc_acpi_link_adr cs42l43_link0_cs35l56_link2_link3[] = {} }; +static const struct snd_soc_acpi_link_adr cs42l43_link3_cs35l56_x4_link0_link1_spkagg[] = { + /* Expected order: jack -> amp */ + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs42l43_l3_4amp_spkagg_adr), + .adr_d = cs42l43_l3_4amp_spkagg_adr, + }, + { + .mask = BIT(1), + .num_adr = 2, + .adr_d = cs35l56_1_adr, + }, + { + .mask = BIT(0), + .num_adr = 2, + .adr_d = cs35l56_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_cs35l56_x8_link0_link1_fb[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_fb_adr), + .adr_d = cs35l56_1_fb_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs35l56_0_fb_adr), + .adr_d = cs35l56_0_fb_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr mtl_cs35l63_x2_link1_link3_fb[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l63_3_fb_adr), + .adr_d = cs35l63_3_fb_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l63_1_fb_adr), + .adr_d = cs35l63_1_fb_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { /* mockup tests need to be first */ @@ -633,6 +1087,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-rt713-l0-rt1316-l12-rt1713-l3.tplg", }, { + .link_mask = GENMASK(3, 0), + .links = mtl_rt713_l0_rt1318_l12_rt1713_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l12-rt1713-l3.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = mtl_rt713_l0_rt1318_l1_rt1713_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt713-l0-rt1318-l1-rt1713-l3.tplg", + }, + { .link_mask = GENMASK(2, 0), .links = mtl_rt713_l0_rt1316_l12, .drv_name = "sof_sdw", @@ -640,11 +1106,26 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { }, { .link_mask = BIT(3) | BIT(0), - .links = mtl_712_only, + .links = mtl_712_l0_1712_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt712-l0-rt1712-l3.tplg", }, { + .link_mask = BIT(0), + .links = mtl_712_vb_l0, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-mtl-rt712-vb-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0), + .links = mtl_712_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt712-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { .link_mask = GENMASK(2, 0), .links = mtl_sdw_rt1318_l12_rt714_l0, .drv_name = "sof_sdw", @@ -655,12 +1136,41 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .links = cs42l43_link0_cs35l56_link2_link3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l23.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = cs42l43_link3_cs35l56_x4_link0_link1_spkagg, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs42l43-l3-cs35l56-l01-spkagg.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = GENMASK(2, 0), .links = mtl_cs42l43_cs35l56, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-cs42l43-l0-cs35l56-l12.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0) | BIT(1), + .links = mtl_cs35l56_x8_link0_link1_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0), + .links = mtl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs42l43-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(3), + .links = mtl_cs35l63_x2_link1_link3_fb, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-cs35l56-l01-fb8.tplg", }, { .link_mask = GENMASK(3, 0), @@ -669,10 +1179,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l23-rt714-l1.tplg", }, { + .link_mask = 0x9, /* 2 active links required */ + .links = mtl_rt711_l0_rt1316_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-mtl-rt711-l0-rt1316-l3.tplg", + }, + { .link_mask = BIT(0), .links = mtl_rt722_only, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-mtl-rt722-l0.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, }, { .link_mask = BIT(0), @@ -695,3 +1212,5 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[] = { {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_mtl_sdw_machines); + +MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c new file mode 100644 index 000000000000..eae75f3f0fa4 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -0,0 +1,683 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-ptl-match.c - tables and support for PTL ACPI enumeration. + * + * Copyright (c) 2024, Intel Corporation. + * + * Order of entries in snd_soc_acpi_intel_ptl_sdw_machines[] matters. + * Check subset of link mask when matching the machine driver, rule is + * superset match should be ordered before subset matches. + */ + +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-match.h> +#include "sof-function-topology-lib.h" +#include "soc-acpi-intel-sdca-quirks.h" +#include "soc-acpi-intel-sdw-mockup-match.h" +#include <sound/soc-acpi-intel-ssp-common.h> + +static const struct snd_soc_acpi_codecs ptl_rt5682_rt5682s_hp = { + .num_codecs = 2, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, +}; + +struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[] = { + { + .comp_ids = &ptl_rt5682_rt5682s_hp, + .drv_name = "ptl_rt5682_def", + .sof_tplg_filename = "sof-ptl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_machines); + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, +}; + +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_1_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_4_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_5_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_6_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, +}; + +/* + * Multi-function codecs with three endpoints created for + * headset, amp and dmic functions. + */ +static const struct snd_soc_acpi_endpoint rt_mf_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* DMIC Endpoint */ + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001fa424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints), + .endpoints = cs42l43_amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = { + { + .adr = 0x00013001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_1_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00013101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + }, + { + .adr = 0x00013201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP3" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_4_endpoint, + .name_prefix = "AMP4" + }, + { + .adr = 0x00033401fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_5_endpoint, + .name_prefix = "AMP5" + }, + { + .adr = 0x00033501fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_6_endpoint, + .name_prefix = "AMP6" + } +}; + +static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = { + { + .adr = 0x00033001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + } +}; + +static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { + { + .adr = 0x000230025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, + .name_prefix = "rt712" + } +}; + +static const struct snd_soc_acpi_adr_device rt712_vb_3_group1_adr[] = { + { + .adr = 0x000330025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, + .name_prefix = "rt712" + } +}; + +static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = { + { + .adr = 0x000230025d071301ull, + .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints), + .endpoints = jack_dmic_endpoints, + .name_prefix = "rt713" + } +}; + +static const struct snd_soc_acpi_adr_device rt713_vb_3_adr[] = { + { + .adr = 0x000330025D071301ull, + .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints), + .endpoints = jack_dmic_endpoints, + .name_prefix = "rt713" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_3_group1_adr[] = { + { + .adr = 0x000330025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { + { + .adr = 0x000330025d072101ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt721" + } +}; + +static const struct snd_soc_acpi_link_adr ptl_rt721_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt721_3_single_adr), + .adr_d = rt721_3_single_adr, + }, + {}, +}; + +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_1_single_adr[] = { + { + .adr = 0x000130025d072201ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt722_3_single_adr[] = { + { + .adr = 0x000330025d072201ull, + .num_endpoints = ARRAY_SIZE(rt_mf_endpoints), + .endpoints = rt_mf_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_1_group1_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_2_group1_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { + { + .adr = 0x000330025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-2" + } +}; + +static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr), + .adr_d = cs35l56_1_3amp_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr), + .adr_d = cs35l56_3_3amp_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_cs42l43_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs42l43_3_adr), + .adr_d = cs42l43_3_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_rt722_l1[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt722_1_single_adr), + .adr_d = rt722_1_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_rt722_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt722_3_single_adr), + .adr_d = rt722_3_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_rvp[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_sdca_0_adr), + .adr_d = rt711_sdca_0_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l2_rt1320_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt713_vb_2_adr), + .adr_d = rt713_vb_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1320_3_group2_adr), + .adr_d = rt1320_3_group2_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l3_rt1320_l12[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt713_vb_3_adr), + .adr_d = rt713_vb_3_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group2_adr), + .adr_d = rt1320_2_group2_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt712_vb_2_group1_adr), + .adr_d = rt712_vb_2_group1_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group1_adr), + .adr_d = rt1320_1_group1_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l2[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr), + .adr_d = rt712_vb_3_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group1_adr), + .adr_d = rt1320_2_group1_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr), + .adr_d = rt712_vb_3_group1_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt1320_3_group1_adr), + .adr_d = rt1320_3_group1_adr, + }, + {} +}; + +/* this table is used when there is no I2S codec present */ +struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { +/* Order Priority: mockup > most links > most bit link-mask > alphabetical */ + { + .link_mask = GENMASK(3, 0), + .links = sdw_mockup_headset_2amps_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt711-rt1308-rt715.tplg", + }, + { + .link_mask = BIT(0) | BIT(1) | BIT(3), + .links = sdw_mockup_headset_1amp_mic, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt711-rt1308-mono-rt715.tplg", + }, + { + .link_mask = GENMASK(2, 0), + .links = sdw_mockup_mic_headset_1amp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.tplg", + }, + { + .link_mask = BIT(0), + .links = sdw_mockup_multi_func, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", /* Reuse the existing tplg file */ + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_sdw_rt713_vb_l2_rt1320_l13, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_sdw_rt713_vb_l3_rt1320_l12, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l12.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_cs42l43_l2_cs35l56x6_l13, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-cs42l43-l2-cs35l56x6-l13.tplg", + }, + { + .link_mask = BIT(1) | BIT(2), + .links = ptl_sdw_rt712_vb_l2_rt1320_l1, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(2) | BIT(3), + .links = ptl_sdw_rt712_vb_l3_rt1320_l2, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l2.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(0), + .links = ptl_rvp, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt711.tplg", + }, + { + .link_mask = BIT(0), + .links = ptl_rt722_only, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(1), + .links = ptl_rt722_l1, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(3), + .links = ptl_cs42l43_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-cs42l43-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(3), + .links = ptl_sdw_rt712_vb_l3_rt1320_l3, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l3.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(3), + .links = ptl_rt721_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt721.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + { + .link_mask = BIT(3), + .links = ptl_rt722_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", + .get_function_tplg_files = sof_sdw_get_tplg_files, + }, + {}, +}; +EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c index 00a21af210fa..b83ac2e6337c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-rpl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-rpl-match.c @@ -7,6 +7,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include <sound/soc-acpi-intel-ssp-common.h> static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, @@ -29,6 +30,42 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { + { + .adr = 0x00003001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_0_adr[] = { { .adr = 0x000020025D071100ull, @@ -155,6 +192,15 @@ static const struct snd_soc_acpi_adr_device rt714_3_adr[] = { } }; +static const struct snd_soc_acpi_link_adr rpl_cs42l43_l0[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs42l43_0_adr), + .adr_d = cs42l43_0_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr rpl_sdca_3_in_1[] = { { .mask = BIT(0), @@ -347,7 +393,7 @@ static const struct snd_soc_acpi_link_adr rplp_crb[] = { static const struct snd_soc_acpi_codecs rpl_rt5682_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs rpl_essx_83x6 = { @@ -360,31 +406,11 @@ static const struct snd_soc_acpi_codecs rpl_max98357a_amp = { .codecs = {"MX98357A"} }; -static const struct snd_soc_acpi_codecs rpl_max98360a_amp = { - .num_codecs = 1, - .codecs = {"MX98360A"}, -}; - -static const struct snd_soc_acpi_codecs rpl_max98373_amp = { - .num_codecs = 1, - .codecs = {"MX98373"} -}; - static const struct snd_soc_acpi_codecs rpl_lt6911_hdmi = { .num_codecs = 1, .codecs = {"INTC10B0"} }; -static const struct snd_soc_acpi_codecs rpl_nau8318_amp = { - .num_codecs = 1, - .codecs = {"NVTN2012"} -}; - -static const struct snd_soc_acpi_codecs rpl_rt1019p_amp = { - .num_codecs = 1, - .codecs = {"RTL1019"} -}; - struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { { .comp_ids = &rpl_rt5682_hp, @@ -395,41 +421,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { }, { .comp_ids = &rpl_rt5682_hp, - .drv_name = "rpl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98360a_amp, - .sof_tplg_filename = "sof-rpl-max98360a-rt5682.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98373_amp, - .sof_tplg_filename = "sof-rpl-max98373-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_max98360a_amp, - .sof_tplg_filename = "sof-rpl-max98360a-nau8825.tplg", - }, - { - .id = "10508825", - .drv_name = "rpl_nau8825_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_nau8318_amp, - .sof_tplg_filename = "sof-rpl-nau8318-nau8825.tplg", - }, - { - .comp_ids = &rpl_rt5682_hp, - .drv_name = "rpl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &rpl_rt1019p_amp, - .sof_tplg_filename = "sof-rpl-rt1019-rt5682.tplg", - }, - { - .comp_ids = &rpl_rt5682_hp, .drv_name = "rpl_rt5682_c1_h02", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &rpl_lt6911_hdmi, @@ -450,6 +441,45 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + /* place boards for each headphone codec: sof driver will complete the + * tplg name and machine driver will detect the amp type + */ + { + .id = CS42L42_ACPI_HID, + .drv_name = "rpl_cs42l42_def", + .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = DA7219_ACPI_HID, + .drv_name = "rpl_da7219_def", + .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = NAU8825_ACPI_HID, + .drv_name = "rpl_nau8825_def", + .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .id = RT5650_ACPI_HID, + .drv_name = "rpl_rt5682_def", + .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + { + .comp_ids = &rpl_rt5682_hp, + .drv_name = "rpl_rt5682_def", + .sof_tplg_filename = "sof-rpl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + /* place amp-only boards in the end of table */ { .id = "INTC10B0", .drv_name = "rpl_lt6911_hdmi_ssp", @@ -462,6 +492,12 @@ EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_rpl_machines); /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[] = { { + .link_mask = BIT(0), + .links = rpl_cs42l43_l0, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-rpl-cs42l43-l0.tplg", + }, + { .link_mask = 0xF, /* 4 active links required */ .links = rpl_sdca_3_in_1, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c new file mode 100644 index 000000000000..3eaa058f8460 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * soc-acpi-intel-sdca-quirks.c - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#include <linux/soundwire/sdw_intel.h> +#include <sound/sdca.h> +#include <sound/soc-acpi.h> +#include "soc-acpi-intel-sdca-quirks.h" + +/* + * Pretend machine quirk. The argument type is not the traditional + * 'struct snd_soc_acpi_mach' pointer but instead the sdw_intel_ctx + * which contains the peripheral information required for the + * SoundWire/SDCA filter on the SMART_MIC setup and interface + * revision. When the return value is false, the entry in the + * 'snd_soc_acpi_mach' table needs to be skipped. + */ +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg) +{ + struct sdw_intel_ctx *ctx = arg; + int i; + + if (!ctx) + return false; + + for (i = 0; i < ctx->peripherals->num_peripherals; i++) { + if (sdca_device_quirk_match(ctx->peripherals->array[i], + SDCA_QUIRKS_RT712_VB)) + return true; + } + + return false; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_sdca_is_device_rt712_vb, "SND_SOC_ACPI_INTEL_SDCA_QUIRKS"); + +MODULE_DESCRIPTION("ASoC ACPI Intel SDCA quirks"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("SND_SOC_SDCA"); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h new file mode 100644 index 000000000000..bead5ec6243f --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-sdca-quirks.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-sdca-quirks.h - tables and support for SDCA quirks + * + * Copyright (c) 2024, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_SDCA_QUIRKS +#define _SND_SOC_ACPI_INTEL_SDCA_QUIRKS + +bool snd_soc_acpi_intel_sdca_is_device_rt712_vb(void *arg); + +#endif diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c index a3d33997736a..d122ce69fa4f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c @@ -31,6 +31,30 @@ static const struct snd_soc_acpi_endpoint sdw_mockup_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_adr_device sdw_mockup_headset_0_adr[] = { { .adr = 0x0000000105AA5500ull, @@ -103,6 +127,15 @@ static const struct snd_soc_acpi_adr_device sdw_mockup_amp_2_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device sdw_mockup_multi_function_adr[] = { + { + .adr = 0x0000000105AAAA01ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, + .name_prefix = "sdw_mockup_mmulti-function" + } +}; + const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[] = { { .mask = BIT(0), @@ -164,3 +197,12 @@ const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[] = { }, {} }; + +const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(sdw_mockup_multi_function_adr), + .adr_d = sdw_mockup_multi_function_adr, + }, + {} +}; diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h index c99eecd19e03..f7ed5beaca96 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h @@ -13,5 +13,6 @@ extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[]; extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_2amps_mic[]; extern const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[]; +extern const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[]; #endif diff --git a/sound/soc/intel/common/soc-acpi-intel-skl-match.c b/sound/soc/intel/common/soc-acpi-intel-skl-match.c index 75302e956742..ee6463202918 100644 --- a/sound/soc/intel/common/soc-acpi-intel-skl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-skl-match.c @@ -8,9 +8,6 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> -#include "../skylake/skl.h" - -static struct skl_machine_pdata skl_dmic_data; static const struct snd_soc_acpi_codecs skl_codecs = { .num_codecs = 1, @@ -29,7 +26,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = { .fw_filename = "intel/dsp_fw_release.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &skl_codecs, - .pdata = &skl_dmic_data, }, { .id = "MX98357A", @@ -37,7 +33,6 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_skl_machines[] = { .fw_filename = "intel/dsp_fw_release.bin", .machine_quirk = snd_soc_acpi_codec_list, .quirk_data = &skl_codecs, - .pdata = &skl_dmic_data, }, {}, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-ssp-common.c b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c new file mode 100644 index 000000000000..f56f4bfa5187 --- /dev/null +++ b/sound/soc/intel/common/soc-acpi-intel-ssp-common.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2023 Intel Corporation + +#include <linux/device.h> +#include <sound/soc-acpi.h> +#include <sound/soc-acpi-intel-ssp-common.h> + +/* + * Codec probe function + */ +#define CODEC_MAP_ENTRY(n, s, h, t) \ + { \ + .name = n, \ + .tplg_suffix = s, \ + .acpi_hid = h, \ + .codec_type = t, \ + } + +struct codec_map { + const char *name; + const char *tplg_suffix; + const char *acpi_hid; + enum snd_soc_acpi_intel_codec codec_type; +}; + +static const struct codec_map codecs[] = { + /* Cirrus Logic */ + CODEC_MAP_ENTRY("CS42L42", "cs42l42", CS42L42_ACPI_HID, CODEC_CS42L42), + + /* Dialog */ + CODEC_MAP_ENTRY("DA7219", "da7219", DA7219_ACPI_HID, CODEC_DA7219), + + /* Everest */ + CODEC_MAP_ENTRY("ES8316", "es8336", ES8316_ACPI_HID, CODEC_ES8316), + CODEC_MAP_ENTRY("ES8326", "es8336", ES8326_ACPI_HID, CODEC_ES8326), + CODEC_MAP_ENTRY("ES8336", "es8336", ES8336_ACPI_HID, CODEC_ES8336), + + /* Nuvoton */ + CODEC_MAP_ENTRY("NAU8825", "nau8825", NAU8825_ACPI_HID, CODEC_NAU8825), + + /* Realtek */ + CODEC_MAP_ENTRY("RT5650", "rt5650", RT5650_ACPI_HID, CODEC_RT5650), + CODEC_MAP_ENTRY("RT5682", "rt5682", RT5682_ACPI_HID, CODEC_RT5682), + CODEC_MAP_ENTRY("RT5682S", "rt5682", RT5682S_ACPI_HID, CODEC_RT5682S), +}; + +static const struct codec_map amps[] = { + /* Cirrus Logic */ + CODEC_MAP_ENTRY("CS35L41", "cs35l41", CS35L41_ACPI_HID, CODEC_CS35L41), + + /* Maxim */ + CODEC_MAP_ENTRY("MAX98357A", "max98357a", MAX_98357A_ACPI_HID, CODEC_MAX98357A), + CODEC_MAP_ENTRY("MAX98360A", "max98360a", MAX_98360A_ACPI_HID, CODEC_MAX98360A), + CODEC_MAP_ENTRY("MAX98373", "max98373", MAX_98373_ACPI_HID, CODEC_MAX98373), + CODEC_MAP_ENTRY("MAX98390", "max98390", MAX_98390_ACPI_HID, CODEC_MAX98390), + + /* Nuvoton */ + CODEC_MAP_ENTRY("NAU8318", "nau8318", NAU8318_ACPI_HID, CODEC_NAU8318), + + /* Realtek */ + CODEC_MAP_ENTRY("RT1011", "rt1011", RT1011_ACPI_HID, CODEC_RT1011), + CODEC_MAP_ENTRY("RT1015", "rt1015", RT1015_ACPI_HID, CODEC_RT1015), + CODEC_MAP_ENTRY("RT1015P", "rt1015", RT1015P_ACPI_HID, CODEC_RT1015P), + CODEC_MAP_ENTRY("RT1019P", "rt1019", RT1019P_ACPI_HID, CODEC_RT1019P), + CODEC_MAP_ENTRY("RT1308", "rt1308", RT1308_ACPI_HID, CODEC_RT1308), + + /* + * Monolithic components + * + * Only put components that can serve as both the amp and the codec below this line. + * This will ensure that if the part is used just as a codec and there is an amp as well + * then the amp will be selected properly. + */ + CODEC_MAP_ENTRY("RT5650", "rt5650", RT5650_ACPI_HID, CODEC_RT5650), +}; + +enum snd_soc_acpi_intel_codec +snd_soc_acpi_intel_detect_codec_type(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codecs); i++) { + if (!acpi_dev_present(codecs[i].acpi_hid, NULL, -1)) + continue; + + dev_dbg(dev, "codec %s found\n", codecs[i].name); + return codecs[i].codec_type; + } + + return CODEC_NONE; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_codec_type, "SND_SOC_ACPI_INTEL_MATCH"); + +enum snd_soc_acpi_intel_codec +snd_soc_acpi_intel_detect_amp_type(struct device *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(amps); i++) { + if (!acpi_dev_present(amps[i].acpi_hid, NULL, -1)) + continue; + + dev_dbg(dev, "amp %s found\n", amps[i].name); + return amps[i].codec_type; + } + + return CODEC_NONE; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_detect_amp_type, "SND_SOC_ACPI_INTEL_MATCH"); + +const char * +snd_soc_acpi_intel_get_codec_name(enum snd_soc_acpi_intel_codec codec_type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codecs); i++) { + if (codecs[i].codec_type != codec_type) + continue; + + return codecs[i].name; + } + for (i = 0; i < ARRAY_SIZE(amps); i++) { + if (amps[i].codec_type != codec_type) + continue; + + return amps[i].name; + } + + return NULL; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_name, "SND_SOC_ACPI_INTEL_MATCH"); + +const char * +snd_soc_acpi_intel_get_codec_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(codecs); i++) { + if (codecs[i].codec_type != codec_type) + continue; + + return codecs[i].tplg_suffix; + } + + return NULL; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_codec_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH"); + +const char * +snd_soc_acpi_intel_get_amp_tplg_suffix(enum snd_soc_acpi_intel_codec codec_type) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(amps); i++) { + if (amps[i].codec_type != codec_type) + continue; + + return amps[i].tplg_suffix; + } + + return NULL; +} +EXPORT_SYMBOL_NS(snd_soc_acpi_intel_get_amp_tplg_suffix, "SND_SOC_ACPI_INTEL_MATCH"); + +MODULE_DESCRIPTION("ASoC Intel SOF Common Machine Driver Helpers"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c index 0fba0a60d9c7..b77aafb0bfb6 100644 --- a/sound/soc/intel/common/soc-acpi-intel-tgl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-tgl-match.c @@ -8,6 +8,7 @@ #include <sound/soc-acpi.h> #include <sound/soc-acpi-intel-match.h> +#include <sound/soc-acpi-intel-ssp-common.h> #include "soc-acpi-intel-sdw-mockup-match.h" static const struct snd_soc_acpi_codecs essx_83x6 = { @@ -15,11 +16,6 @@ static const struct snd_soc_acpi_codecs essx_83x6 = { .codecs = { "ESSX8316", "ESSX8326", "ESSX8336"}, }; -static const struct snd_soc_acpi_codecs tgl_codecs = { - .num_codecs = 1, - .codecs = {"MX98357A"} -}; - static const struct snd_soc_acpi_endpoint single_endpoint = { .num = 0, .aggregated = 0, @@ -414,11 +410,38 @@ static const struct snd_soc_acpi_link_adr tgl_712_only[] = { {} }; +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = { { .adr = 0x00033001FA424301ull, - .num_endpoints = 1, - .endpoints = &single_endpoint, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, .name_prefix = "cs42l43" } }; @@ -443,13 +466,13 @@ static const struct snd_soc_acpi_adr_device cs35l56_1_adr[] = { .adr = 0x00013701FA355601ull, .num_endpoints = 1, .endpoints = &spk_l_endpoint, - .name_prefix = "AMP8" + .name_prefix = "AMP3" }, { .adr = 0x00013601FA355601ull, .num_endpoints = 1, .endpoints = &spk_2_endpoint, - .name_prefix = "AMP7" + .name_prefix = "AMP4" } }; @@ -472,19 +495,9 @@ static const struct snd_soc_acpi_link_adr tgl_cs42l43_cs35l56[] = { {} }; -static const struct snd_soc_acpi_codecs tgl_max98373_amp = { - .num_codecs = 1, - .codecs = {"MX98373"} -}; - -static const struct snd_soc_acpi_codecs tgl_rt1011_amp = { - .num_codecs = 1, - .codecs = {"10EC1011"} -}; - static const struct snd_soc_acpi_codecs tgl_rt5682_rt5682s_hp = { .num_codecs = 2, - .codecs = {"10EC5682", "RTL5682"}, + .codecs = {RT5682_ACPI_HID, RT5682S_ACPI_HID}, }; static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = { @@ -494,27 +507,6 @@ static const struct snd_soc_acpi_codecs tgl_lt6911_hdmi = { struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_codecs, - .sof_tplg_filename = "sof-tgl-max98357a-rt5682.tplg", - }, - { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_max98373_amp, - .sof_tplg_filename = "sof-tgl-max98373-rt5682.tplg", - }, - { - .comp_ids = &tgl_rt5682_rt5682s_hp, - .drv_name = "tgl_rt5682_def", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &tgl_rt1011_amp, - .sof_tplg_filename = "sof-tgl-rt1011-rt5682.tplg", - }, - { .comp_ids = &essx_83x6, .drv_name = "sof-essx8336", .sof_tplg_filename = "sof-tgl-es8336", /* the tplg suffix is added at run time */ @@ -522,6 +514,17 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { SND_SOC_ACPI_TPLG_INTEL_SSP_MSB | SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER, }, + /* place boards for each headphone codec: sof driver will complete the + * tplg name and machine driver will detect the amp type + */ + { + .comp_ids = &tgl_rt5682_rt5682s_hp, + .drv_name = "tgl_rt5682_def", + .sof_tplg_filename = "sof-tgl", /* the tplg suffix is added at run time */ + .tplg_quirk_mask = SND_SOC_ACPI_TPLG_INTEL_AMP_NAME | + SND_SOC_ACPI_TPLG_INTEL_CODEC_NAME, + }, + /* place amp-only boards in the end of table */ { .id = "10EC1308", .drv_name = "tgl_rt1308_hdmi_ssp", @@ -533,6 +536,194 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_machines[] = { }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_machines); +static const struct snd_soc_acpi_endpoint cs35l56_l_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_r_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 1, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_2_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 2, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_3_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 3, + .group_id = 2, + }, +}; + +static const struct snd_soc_acpi_endpoint cs35l56_4_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 4, + .group_id = 2, + } +}; + +static const struct snd_soc_acpi_endpoint cs35l56_5_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 5, + .group_id = 2, + } +}; + +static const struct snd_soc_acpi_endpoint cs35l56_6_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 6, + .group_id = 2, + } +}; + +static const struct snd_soc_acpi_endpoint cs35l56_7_fb_endpoints[] = { + { /* Speaker Playback Endpoint */ + .num = 0, + .aggregated = 1, + .group_position = 7, + .group_id = 1, + }, + { /* Feedback Capture Endpoint */ + .num = 1, + .aggregated = 1, + .group_position = 7, + .group_id = 2, + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_sdw_eight_1_4_fb_adr[] = { + { + .adr = 0x00003301fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_l_fb_endpoints), + .endpoints = cs35l56_l_fb_endpoints, + .name_prefix = "AMP1" + }, + { + .adr = 0x00003201fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_2_fb_endpoints), + .endpoints = cs35l56_2_fb_endpoints, + .name_prefix = "AMP2" + }, + { + .adr = 0x00003101fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_4_fb_endpoints), + .endpoints = cs35l56_4_fb_endpoints, + .name_prefix = "AMP3" + }, + { + .adr = 0x00003001fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_6_fb_endpoints), + .endpoints = cs35l56_6_fb_endpoints, + .name_prefix = "AMP4" + }, +}; + +static const struct snd_soc_acpi_adr_device cs35l56_sdw_eight_5_8_fb_adr[] = { + { + .adr = 0x00013701fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_r_fb_endpoints), + .endpoints = cs35l56_r_fb_endpoints, + .name_prefix = "AMP8" + }, + { + .adr = 0x00013601fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_3_fb_endpoints), + .endpoints = cs35l56_3_fb_endpoints, + .name_prefix = "AMP7" + }, + { + .adr = 0x00013501fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_5_fb_endpoints), + .endpoints = cs35l56_5_fb_endpoints, + .name_prefix = "AMP6" + }, + { + .adr = 0x00013401fa355601ull, + .num_endpoints = ARRAY_SIZE(cs35l56_7_fb_endpoints), + .endpoints = cs35l56_7_fb_endpoints, + .name_prefix = "AMP5" + }, +}; + +static const struct snd_soc_acpi_link_adr up_extreme_cs35l56_sdw_eight[] = { + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_sdw_eight_5_8_fb_adr), + .adr_d = cs35l56_sdw_eight_5_8_fb_adr, + }, + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(cs35l56_sdw_eight_1_4_fb_adr), + .adr_d = cs35l56_sdw_eight_1_4_fb_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { /* mockup tests need to be first */ @@ -632,6 +823,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_tgl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-tgl-rt711.tplg", }, + { + .link_mask = BIT(0) | BIT(1), + .links = up_extreme_cs35l56_sdw_eight, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-tgl-cs35l56-l01-fb8.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_tgl_sdw_machines); diff --git a/sound/soc/intel/common/soc-intel-quirks.h b/sound/soc/intel/common/soc-intel-quirks.h index de4e550c5b34..42bd51456b94 100644 --- a/sound/soc/intel/common/soc-intel-quirks.h +++ b/sound/soc/intel/common/soc-intel-quirks.h @@ -11,7 +11,7 @@ #include <linux/platform_data/x86/soc.h> -#if IS_ENABLED(CONFIG_X86) +#if IS_REACHABLE(CONFIG_IOSF_MBI) #include <linux/dmi.h> #include <asm/iosf_mbi.h> diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c new file mode 100644 index 000000000000..90fe7aa3df1c --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -0,0 +1,135 @@ +// 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/device.h> +#include <linux/errno.h> +#include <linux/firmware.h> +#include <sound/soc.h> +#include <sound/soc-acpi.h> +#include "sof-function-topology-lib.h" + +enum tplg_device_id { + TPLG_DEVICE_SDCA_JACK, + TPLG_DEVICE_SDCA_AMP, + TPLG_DEVICE_SDCA_MIC, + TPLG_DEVICE_INTEL_PCH_DMIC, + TPLG_DEVICE_HDMI, + TPLG_DEVICE_MAX +}; + +#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \ + BIT(TPLG_DEVICE_SDCA_MIC)) + +#define SOF_INTEL_PLATFORM_NAME_MAX 4 + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files) +{ + struct snd_soc_acpi_mach_params mach_params = mach->mach_params; + struct snd_soc_dai_link *dai_link; + const struct firmware *fw; + char platform[SOF_INTEL_PLATFORM_NAME_MAX]; + unsigned long tplg_mask = 0; + int tplg_num = 0; + int tplg_dev; + int ret; + int i; + + ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform); + if (ret != 1) { + dev_err(card->dev, "Invalid platform name %s of tplg %s\n", + platform, mach->sof_tplg_filename); + return -EINVAL; + } + + for_each_card_prelinks(card, i, dai_link) { + char *tplg_dev_name; + + dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id); + if (strstr(dai_link->name, "SimpleJack")) { + tplg_dev = TPLG_DEVICE_SDCA_JACK; + tplg_dev_name = "sdca-jack"; + } else if (strstr(dai_link->name, "SmartAmp")) { + tplg_dev = TPLG_DEVICE_SDCA_AMP; + tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL, + "sdca-%damp", dai_link->num_cpus); + if (!tplg_dev_name) + return -ENOMEM; + } else if (strstr(dai_link->name, "SmartMic")) { + tplg_dev = TPLG_DEVICE_SDCA_MIC; + tplg_dev_name = "sdca-mic"; + } else if (strstr(dai_link->name, "dmic")) { + switch (mach_params.dmic_num) { + case 2: + tplg_dev_name = "dmic-2ch"; + break; + case 4: + tplg_dev_name = "dmic-4ch"; + break; + default: + dev_warn(card->dev, + "only -2ch and -4ch are supported for dmic\n"); + continue; + } + tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC; + } else if (strstr(dai_link->name, "iDisp")) { + tplg_dev = TPLG_DEVICE_HDMI; + tplg_dev_name = "hdmi-pcm5"; + + } else { + /* The dai link is not supported by separated tplg yet */ + dev_dbg(card->dev, + "dai_link %s is not supported by separated tplg yet\n", + dai_link->name); + return 0; + } + if (tplg_mask & BIT(tplg_dev)) + continue; + + tplg_mask |= BIT(tplg_dev); + + /* + * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg + * where <platform> is only required for the DMIC function as the nhlt blob + * is platform dependent. + */ + switch (tplg_dev) { + case TPLG_DEVICE_INTEL_PCH_DMIC: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-%s-id%d.tplg", + prefix, platform, + tplg_dev_name, dai_link->id); + break; + default: + (*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL, + "%s/sof-%s-id%d.tplg", + prefix, tplg_dev_name, + dai_link->id); + break; + } + if (!(*tplg_files)[tplg_num]) + return -ENOMEM; + tplg_num++; + } + + dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num); + + /* Check presence of sub-topologies */ + for (i = 0; i < tplg_num; i++) { + ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev); + if (!ret) { + release_firmware(fw); + } else { + dev_dbg(card->dev, "Failed to open topology file: %s\n", (*tplg_files)[i]); + return 0; + } + } + + return tplg_num; +} + diff --git a/sound/soc/intel/common/sof-function-topology-lib.h b/sound/soc/intel/common/sof-function-topology-lib.h new file mode 100644 index 000000000000..e7d0c39d0788 --- /dev/null +++ b/sound/soc/intel/common/sof-function-topology-lib.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * soc-acpi-intel-get-tplg.h - get-tplg-files ops + * + * Copyright (c) 2025, Intel Corporation. + * + */ + +#ifndef _SND_SOC_ACPI_INTEL_GET_TPLG_H +#define _SND_SOC_ACPI_INTEL_GET_TPLG_H + +int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach, + const char *prefix, const char ***tplg_files); + +#endif diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h deleted file mode 100644 index de2b44568feb..000000000000 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#ifndef __SOUND_SOC_SST_DSP_PRIV_H -#define __SOUND_SOC_SST_DSP_PRIV_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/firmware.h> - -#include "../skylake/skl-sst-dsp.h" - -/* - * DSP Operations exported by platform Audio DSP driver. - */ -struct sst_ops { - /* Shim IO */ - void (*write)(void __iomem *addr, u32 offset, u32 value); - u32 (*read)(void __iomem *addr, u32 offset); - - /* IRQ handlers */ - irqreturn_t (*irq_handler)(int irq, void *context); - - /* SST init and free */ - int (*init)(struct sst_dsp *sst); - void (*free)(struct sst_dsp *sst); -}; - -/* - * Audio DSP memory offsets and addresses. - */ -struct sst_addr { - u32 sram0_base; - u32 sram1_base; - u32 w0_stat_sz; - u32 w0_up_sz; - void __iomem *lpe; - void __iomem *shim; -}; - -/* - * Audio DSP Mailbox configuration. - */ -struct sst_mailbox { - void __iomem *in_base; - void __iomem *out_base; - size_t in_size; - size_t out_size; -}; - -/* - * Generic SST Shim Interface. - */ -struct sst_dsp { - - /* Shared for all platforms */ - - /* runtime */ - struct sst_dsp_device *sst_dev; - spinlock_t spinlock; /* IPC locking */ - struct mutex mutex; /* DSP FW lock */ - struct device *dev; - void *thread_context; - int irq; - u32 id; - - /* operations */ - struct sst_ops *ops; - - /* debug FS */ - struct dentry *debugfs_root; - - /* base addresses */ - struct sst_addr addr; - - /* mailbox */ - struct sst_mailbox mailbox; - - /* SST FW files loaded and their modules */ - struct list_head module_list; - - /* SKL data */ - - const char *fw_name; - - /* To allocate CL dma buffers */ - struct skl_dsp_loader_ops dsp_ops; - struct skl_dsp_fw_ops fw_ops; - int sst_state; - struct skl_cl_dev cl_dev; - u32 intr_status; - const struct firmware *fw; - struct snd_dma_buffer dmab; -}; - -#endif diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c deleted file mode 100644 index 229d09d61afb..000000000000 --- a/sound/soc/intel/common/sst-dsp.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel Smart Sound Technology (SST) DSP Core Driver - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#include <linux/slab.h> -#include <linux/export.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/io-64-nonatomic-lo-hi.h> -#include <linux/delay.h> - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" - -#define CREATE_TRACE_POINTS -#include <trace/events/intel-sst.h> - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) -{ - writel(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write); - -u32 sst_shim32_read(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read); - -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) -{ - writeq(value, addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_write64); - -u64 sst_shim32_read64(void __iomem *addr, u32 offset) -{ - return readq(addr + offset); -} -EXPORT_SYMBOL_GPL(sst_shim32_read64); - -/* Public API */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst->ops->write(sst->addr.shim, offset, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write); - -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) -{ - unsigned long flags; - u32 val; - - spin_lock_irqsave(&sst->spinlock, flags); - val = sst->ops->read(sst->addr.shim, offset); - spin_unlock_irqrestore(&sst->spinlock, flags); - - return val; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read); - -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) -{ - sst->ops->write(sst->addr.shim, offset, value); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); - -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) -{ - return sst->ops->read(sst->addr.shim, offset); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); - -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - bool change; - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - change = (old != new); - if (change) - sst_dsp_shim_write_unlocked(sst, offset, new); - - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned int old, new; - u32 ret; - - ret = sst_dsp_shim_read_unlocked(sst, offset); - - old = ret; - new = (old & (~mask)) | (value & mask); - - sst_dsp_shim_write_unlocked(sst, offset, new); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); - -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - bool change; - - spin_lock_irqsave(&sst->spinlock, flags); - change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); - return change; -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); - -/* This is for registers bits with attribute RWC */ -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value) -{ - unsigned long flags; - - spin_lock_irqsave(&sst->spinlock, flags); - sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); - spin_unlock_irqrestore(&sst->spinlock, flags); -} -EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); - -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation) -{ - u32 reg; - unsigned long timeout; - int k = 0, s = 500; - - /* - * split the loop into sleeps of varying resolution. more accurately, - * the range of wakeups are: - * Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms. - * Phase 2:( 5ms to 10ms) : min sleep 0.5ms; max sleep 10ms - * (usleep_range (500, 1000) and usleep_range(5000, 10000) are - * both possible in this phase depending on whether k > 10 or not). - * Phase 3: (beyond 10 ms) min sleep 5ms; max sleep 10ms. - */ - - timeout = jiffies + msecs_to_jiffies(time); - while ((((reg = sst_dsp_shim_read_unlocked(ctx, offset)) & mask) != target) - && time_before(jiffies, timeout)) { - k++; - if (k > 10) - s = 5000; - - usleep_range(s, 2*s); - } - - if ((reg & mask) == target) { - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s successful\n", - reg, operation); - - return 0; - } - - dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s timedout\n", - reg, operation); - return -ETIME; -} -EXPORT_SYMBOL_GPL(sst_dsp_register_poll); - -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, - u32 outbox_offset, size_t outbox_size) -{ - sst->mailbox.in_base = sst->addr.lpe + inbox_offset; - sst->mailbox.out_base = sst->addr.lpe + outbox_offset; - sst->mailbox.in_size = inbox_size; - sst->mailbox.out_size = outbox_size; - return 0; -} -EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); - -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_write(bytes); - - memcpy_toio(sst->mailbox.out_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); - -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_outbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.out_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); - -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_write(bytes); - - memcpy_toio(sst->mailbox.in_base, message, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); - -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) -{ - u32 i; - - trace_sst_ipc_inbox_read(bytes); - - memcpy_fromio(message, sst->mailbox.in_base, bytes); - - for (i = 0; i < bytes; i += 4) - trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); -} -EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); - -/* Module information */ -MODULE_AUTHOR("Liam Girdwood"); -MODULE_DESCRIPTION("Intel SST Core"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h deleted file mode 100644 index f111fd3f334b..000000000000 --- a/sound/soc/intel/common/sst-dsp.h +++ /dev/null @@ -1,61 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Smart Sound Technology (SST) Core - * - * Copyright (C) 2013, Intel Corporation. All rights reserved. - */ - -#ifndef __SOUND_SOC_SST_DSP_H -#define __SOUND_SOC_SST_DSP_H - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/interrupt.h> - -struct sst_dsp; - -/* - * SST Device. - * - * This structure is populated by the SST core driver. - */ -struct sst_dsp_device { - /* Mandatory fields */ - struct sst_ops *ops; - irqreturn_t (*thread)(int irq, void *context); - void *thread_context; -}; - -/* SHIM Read / Write */ -void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* SHIM Read / Write Unlocked for callers already holding sst lock */ -void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); -u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); -int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); -void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, - u32 mask, u32 value); - -/* Internal generic low-level SST IO functions - can be overidden */ -void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); -u32 sst_shim32_read(void __iomem *addr, u32 offset); -void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value); -u64 sst_shim32_read64(void __iomem *addr, u32 offset); - -/* Mailbox management */ -int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, - size_t inbox_size, u32 outbox_offset, size_t outbox_size); -void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes); -void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes); -int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, - u32 target, u32 time, char *operation); - -#endif diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c deleted file mode 100644 index 89c10724d2a3..000000000000 --- a/sound/soc/intel/common/sst-ipc.c +++ /dev/null @@ -1,294 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/list.h> -#include <linux/wait.h> -#include <linux/module.h> -#include <linux/spinlock.h> -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/platform_device.h> -#include <sound/asound.h> - -#include "sst-dsp.h" -#include "sst-dsp-priv.h" -#include "sst-ipc.h" - -/* IPC message timeout (msecs) */ -#define IPC_TIMEOUT_MSECS 300 - -#define IPC_EMPTY_LIST_SIZE 8 - -/* locks held by caller */ -static struct ipc_message *msg_get_empty(struct sst_generic_ipc *ipc) -{ - struct ipc_message *msg = NULL; - - if (!list_empty(&ipc->empty_list)) { - msg = list_first_entry(&ipc->empty_list, struct ipc_message, - list); - list_del(&msg->list); - } - - return msg; -} - -static int tx_wait_done(struct sst_generic_ipc *ipc, - struct ipc_message *msg, struct sst_ipc_message *reply) -{ - unsigned long flags; - int ret; - - /* wait for DSP completion (in all cases atm inc pending) */ - ret = wait_event_timeout(msg->waitq, msg->complete, - msecs_to_jiffies(IPC_TIMEOUT_MSECS)); - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - if (ret == 0) { - if (ipc->ops.shim_dbg != NULL) - ipc->ops.shim_dbg(ipc, "message timeout"); - - list_del(&msg->list); - ret = -ETIMEDOUT; - } else { - - /* copy the data returned from DSP */ - if (reply) { - reply->header = msg->rx.header; - if (reply->data) - memcpy(reply->data, msg->rx.data, msg->rx.size); - } - ret = msg->errno; - } - - list_add_tail(&msg->list, &ipc->empty_list); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return ret; -} - -static int ipc_tx_message(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, - struct sst_ipc_message *reply, int wait) -{ - struct ipc_message *msg; - unsigned long flags; - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - - msg = msg_get_empty(ipc); - if (msg == NULL) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return -EBUSY; - } - - msg->tx.header = request.header; - msg->tx.size = request.size; - msg->rx.header = 0; - msg->rx.size = reply ? reply->size : 0; - msg->wait = wait; - msg->errno = 0; - msg->pending = false; - msg->complete = false; - - if ((request.size) && (ipc->ops.tx_data_copy != NULL)) - ipc->ops.tx_data_copy(msg, request.data, request.size); - - list_add_tail(&msg->list, &ipc->tx_list); - schedule_work(&ipc->kwork); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - - if (wait) - return tx_wait_done(ipc, msg, reply); - else - return 0; -} - -static int msg_empty_list_init(struct sst_generic_ipc *ipc) -{ - int i; - - ipc->msg = kcalloc(IPC_EMPTY_LIST_SIZE, sizeof(struct ipc_message), - GFP_KERNEL); - if (ipc->msg == NULL) - return -ENOMEM; - - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - ipc->msg[i].tx.data = kzalloc(ipc->tx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].tx.data == NULL) - goto free_mem; - - ipc->msg[i].rx.data = kzalloc(ipc->rx_data_max_size, GFP_KERNEL); - if (ipc->msg[i].rx.data == NULL) { - kfree(ipc->msg[i].tx.data); - goto free_mem; - } - - init_waitqueue_head(&ipc->msg[i].waitq); - list_add(&ipc->msg[i].list, &ipc->empty_list); - } - - return 0; - -free_mem: - while (i > 0) { - kfree(ipc->msg[i-1].tx.data); - kfree(ipc->msg[i-1].rx.data); - --i; - } - kfree(ipc->msg); - - return -ENOMEM; -} - -static void ipc_tx_msgs(struct work_struct *work) -{ - struct sst_generic_ipc *ipc = - container_of(work, struct sst_generic_ipc, kwork); - struct ipc_message *msg; - - spin_lock_irq(&ipc->dsp->spinlock); - - while (!list_empty(&ipc->tx_list) && !ipc->pending) { - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of processing - * completion irq - */ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - break; - } - - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); - - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); - } - - spin_unlock_irq(&ipc->dsp->spinlock); -} - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - int ret; - - /* - * DSP maybe in lower power active state, so - * check if the DSP supports DSP lp On method - * if so invoke that before sending IPC - */ - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) - return -EIO; - - ret = ipc_tx_message(ipc, request, reply, 1); - - if (ipc->ops.check_dsp_lp_on) - if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) - return -EIO; - - return ret; -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request) -{ - return ipc_tx_message(ipc, request, NULL, 0); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply) -{ - return ipc_tx_message(ipc, request, reply, 1); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header) -{ - struct ipc_message *msg; - u64 mask; - - if (ipc->ops.reply_msg_match != NULL) - header = ipc->ops.reply_msg_match(header, &mask); - else - mask = (u64)-1; - - if (list_empty(&ipc->rx_list)) { - dev_err(ipc->dev, "error: rx list empty but received 0x%llx\n", - header); - return NULL; - } - - list_for_each_entry(msg, &ipc->rx_list, list) { - if ((msg->tx.header & mask) == header) - return msg; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(sst_ipc_reply_find_msg); - -/* locks held by caller */ -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg) -{ - msg->complete = true; - - if (!msg->wait) - list_add_tail(&msg->list, &ipc->empty_list); - else - wake_up(&msg->waitq); -} -EXPORT_SYMBOL_GPL(sst_ipc_tx_msg_reply_complete); - -int sst_ipc_init(struct sst_generic_ipc *ipc) -{ - int ret; - - INIT_LIST_HEAD(&ipc->tx_list); - INIT_LIST_HEAD(&ipc->rx_list); - INIT_LIST_HEAD(&ipc->empty_list); - init_waitqueue_head(&ipc->wait_txq); - - ret = msg_empty_list_init(ipc); - if (ret < 0) - return -ENOMEM; - - INIT_WORK(&ipc->kwork, ipc_tx_msgs); - return 0; -} -EXPORT_SYMBOL_GPL(sst_ipc_init); - -void sst_ipc_fini(struct sst_generic_ipc *ipc) -{ - int i; - - cancel_work_sync(&ipc->kwork); - - if (ipc->msg) { - for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { - kfree(ipc->msg[i].tx.data); - kfree(ipc->msg[i].rx.data); - } - kfree(ipc->msg); - } -} -EXPORT_SYMBOL_GPL(sst_ipc_fini); - -/* Module information */ -MODULE_AUTHOR("Jin Yao"); -MODULE_DESCRIPTION("Intel SST IPC generic"); -MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h deleted file mode 100644 index 77d651e888f9..000000000000 --- a/sound/soc/intel/common/sst-ipc.h +++ /dev/null @@ -1,86 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel SST generic IPC Support - * - * Copyright (C) 2015, Intel Corporation. All rights reserved. - */ - -#ifndef __SST_GENERIC_IPC_H -#define __SST_GENERIC_IPC_H - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/list.h> -#include <linux/workqueue.h> -#include <linux/sched.h> - -struct sst_ipc_message { - u64 header; - void *data; - size_t size; -}; - -struct ipc_message { - struct list_head list; - struct sst_ipc_message tx; - struct sst_ipc_message rx; - - wait_queue_head_t waitq; - bool pending; - bool complete; - bool wait; - int errno; -}; - -struct sst_generic_ipc; -struct sst_dsp; - -struct sst_plat_ipc_ops { - void (*tx_msg)(struct sst_generic_ipc *, struct ipc_message *); - void (*shim_dbg)(struct sst_generic_ipc *, const char *); - void (*tx_data_copy)(struct ipc_message *, char *, size_t); - u64 (*reply_msg_match)(u64 header, u64 *mask); - bool (*is_dsp_busy)(struct sst_dsp *dsp); - int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); -}; - -/* SST generic IPC data */ -struct sst_generic_ipc { - struct device *dev; - struct sst_dsp *dsp; - - /* IPC messaging */ - struct list_head tx_list; - struct list_head rx_list; - struct list_head empty_list; - wait_queue_head_t wait_txq; - struct task_struct *tx_thread; - struct work_struct kwork; - bool pending; - struct ipc_message *msg; - int tx_data_max_size; - int rx_data_max_size; - - struct sst_plat_ipc_ops ops; -}; - -int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, - struct sst_ipc_message request); - -int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, - struct sst_ipc_message request, struct sst_ipc_message *reply); - -struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, - u64 header); - -void sst_ipc_tx_msg_reply_complete(struct sst_generic_ipc *ipc, - struct ipc_message *msg); - -int sst_ipc_init(struct sst_generic_ipc *ipc); -void sst_ipc_fini(struct sst_generic_ipc *ipc); - -#endif diff --git a/sound/soc/intel/keembay/Makefile b/sound/soc/intel/keembay/Makefile index 9084e8c63854..3da9a6f9ba2a 100644 --- a/sound/soc/intel/keembay/Makefile +++ b/sound/soc/intel/keembay/Makefile @@ -1,4 +1,4 @@ -snd-soc-kmb_platform-objs := \ +snd-soc-kmb_platform-y := \ kmb_platform.o obj-$(CONFIG_SND_SOC_INTEL_KEEMBAY) += snd-soc-kmb_platform.o diff --git a/sound/soc/intel/keembay/kmb_platform.c b/sound/soc/intel/keembay/kmb_platform.c index 37ea2e1d2e92..4ed71d11ad77 100644 --- a/sound/soc/intel/keembay/kmb_platform.c +++ b/sound/soc/intel/keembay/kmb_platform.c @@ -814,6 +814,7 @@ static const struct of_device_id kmb_plat_of_match[] = { { .compatible = "intel,keembay-tdm", .data = &intel_kmb_tdm_dai}, {} }; +MODULE_DEVICE_TABLE(of, kmb_plat_of_match); static int kmb_plat_dai_probe(struct platform_device *pdev) { @@ -868,7 +869,7 @@ static int kmb_plat_dai_probe(struct platform_device *pdev) kmb_i2s->fifo_th = (1 << COMP1_FIFO_DEPTH(comp1_reg)) / 2; - kmb_i2s->use_pio = !(of_property_read_bool(np, "dmas")); + kmb_i2s->use_pio = !of_property_present(np, "dmas"); if (kmb_i2s->use_pio) { irq = platform_get_irq_optional(pdev, 0); diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile deleted file mode 100644 index 1c4649bccec5..000000000000 --- a/sound/soc/intel/skylake/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o skl-topology.o \ - skl-sst-ipc.o skl-sst-dsp.o cnl-sst-dsp.o skl-sst-cldma.o \ - skl-sst.o bxt-sst.o cnl-sst.o skl-sst-utils.o - -ifdef CONFIG_DEBUG_FS - snd-soc-skl-objs += skl-debug.o -endif - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_COMMON) += snd-soc-skl.o - -#Skylake Clock device support -snd-soc-skl-ssp-clk-objs := skl-ssp-clk.o - -obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE_SSP_CLK) += snd-soc-skl-ssp-clk.o diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c deleted file mode 100644 index fd4fdcb95224..000000000000 --- a/sound/soc/intel/skylake/bxt-sst.c +++ /dev/null @@ -1,629 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * bxt-sst.c - DSP library functions for BXT platform - * - * Copyright (C) 2015-16 Intel Corp - * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/firmware.h> -#include <linux/device.h> - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -#define BXT_BASEFW_TIMEOUT 3000 -#define BXT_ROM_INIT_TIMEOUT 70 -#define BXT_IPC_PURGE_FW 0x01004000 - -#define BXT_ROM_INIT 0x5 -#define BXT_ADSP_SRAM0_BASE 0x80000 - -/* Firmware status window */ -#define BXT_ADSP_FW_STATUS BXT_ADSP_SRAM0_BASE -#define BXT_ADSP_ERROR_CODE (BXT_ADSP_FW_STATUS + 0x4) - -#define BXT_ADSP_SRAM1_BASE 0xA0000 - -#define BXT_INSTANCE_ID 0 -#define BXT_BASE_FW_MODULE_ID 0 - -#define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 - -/* Delay before scheduling D0i3 entry */ -#define BXT_D0I3_DELAY 5000 - -static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); -} - -static int -bxt_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) -{ - struct snd_dma_buffer dmab; - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - int ret = 0, i, dma_id, stream_tag; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, - BXT_ADSP_FW_BIN_HDR_OFFSET, i); - if (ret < 0) - goto load_library_failed; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, - stripped_fw.size, &dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "Lib prepare DMA err: %x\n", - stream_tag); - ret = stream_tag; - goto load_library_failed; - } - - dma_id = stream_tag - 1; - memcpy(dmab.area, stripped_fw.data, stripped_fw.size); - - ctx->dsp_ops.trigger(ctx->dev, true, stream_tag); - ret = skl_sst_ipc_load_library(&skl->ipc, dma_id, i, true); - if (ret < 0) - dev_err(ctx->dev, "IPC Load Lib for %s fail: %d\n", - linfo[i].name, ret); - - ctx->dsp_ops.trigger(ctx->dev, false, stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &dmab, stream_tag); - } - - return ret; - -load_library_failed: - skl_release_library(linfo, lib_count); - return ret; -} - -/* - * First boot sequence has some extra steps. Core 0 waits for power - * status on core 1, so power up core 1 also momentarily, keep it in - * reset/stall and then turn it off - */ -static int sst_bxt_prepare_fw(struct sst_dsp *ctx, - const void *fwdata, u32 fwsize) -{ - int stream_tag, ret; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", - stream_tag); - return stream_tag; - } - - ctx->dsp_ops.stream_tag = stream_tag; - memcpy(ctx->dmab.area, fwdata, fwsize); - - /* Step 1: Power up core 0 and core1 */ - ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK | - SKL_DSP_CORE_MASK(1)); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0/1 power up failed\n"); - goto base_fw_load_failed; - } - - /* Step 2: Purge FW request */ - sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | - (BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9))); - - /* Step 3: Unset core0 reset state & unstall/run core0 */ - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); - ret = -EIO; - goto base_fw_load_failed; - } - - /* Step 4: Wait for DONE Bit */ - ret = sst_dsp_register_poll(ctx, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, - SKL_ADSP_REG_HIPCIE_DONE, - BXT_INIT_TIMEOUT, "HIPCIE Done"); - if (ret < 0) { - dev_err(ctx->dev, "Timeout for Purge Request%d\n", ret); - goto base_fw_load_failed; - } - - /* Step 5: power down core1 */ - ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - if (ret < 0) { - dev_err(ctx->dev, "dsp core1 power down failed\n"); - goto base_fw_load_failed; - } - - /* Step 6: Enable Interrupt */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - - /* Step 7: Wait for ROM init */ - ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, - SKL_FW_INIT, BXT_ROM_INIT_TIMEOUT, "ROM Load"); - if (ret < 0) { - dev_err(ctx->dev, "Timeout for ROM init, ret:%d\n", ret); - goto base_fw_load_failed; - } - - return ret; - -base_fw_load_failed: - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); - skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - return ret; -} - -static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) -{ - int ret; - - ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); - ret = sst_dsp_register_poll(ctx, BXT_ADSP_FW_STATUS, SKL_FW_STS_MASK, - BXT_ROM_INIT, BXT_BASEFW_TIMEOUT, "Firmware boot"); - - ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); - - return ret; -} - -static int bxt_load_base_firmware(struct sst_dsp *ctx) -{ - struct firmware stripped_fw; - struct skl_dev *skl = ctx->thread_context; - int ret, i; - - if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - return ret; - } - } - - /* prase uuids on first boot */ - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, BXT_ADSP_FW_BIN_HDR_OFFSET, 0); - if (ret < 0) - goto sst_load_base_firmware_failed; - } - - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - skl_dsp_strip_extended_manifest(&stripped_fw); - - - for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { - ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (ret == 0) - break; - } - - if (ret < 0) { - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - - dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); - goto sst_load_base_firmware_failed; - } - - ret = sst_transfer_fw_host_dma(ctx); - if (ret < 0) { - dev_err(ctx->dev, "Transfer firmware failed %d\n", ret); - dev_info(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - } else { - dev_dbg(ctx->dev, "Firmware download successful\n"); - ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - ret = -EIO; - } else { - ret = 0; - skl->fw_loaded = true; - } - } - - return ret; - -sst_load_base_firmware_failed: - release_firmware(ctx->fw); - ctx->fw = NULL; - return ret; -} - -/* - * Decide the D0i3 state that can be targeted based on the usecase - * ref counts and DSP state - * - * Decision Matrix: (X= dont care; state = target state) - * - * DSP state != SKL_DSP_RUNNING ; state = no d0i3 - * - * DSP state == SKL_DSP_RUNNING , the following matrix applies - * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 - * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 - * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 - * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 - */ -static int bxt_d0i3_target_state(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) - return SKL_DSP_D0I3_NONE; - - if (d0i3->non_d0i3) - return SKL_DSP_D0I3_NONE; - else if (d0i3->streaming) - return SKL_DSP_D0I3_STREAMING; - else if (d0i3->non_streaming) - return SKL_DSP_D0I3_NON_STREAMING; - else - return SKL_DSP_D0I3_NONE; -} - -static void bxt_set_dsp_D0i3(struct work_struct *work) -{ - int ret; - struct skl_ipc_d0ix_msg msg; - struct skl_dev *skl = container_of(work, - struct skl_dev, d0i3.work.work); - struct sst_dsp *ctx = skl->dsp; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - int target_state; - - dev_dbg(ctx->dev, "In %s:\n", __func__); - - /* D0i3 entry allowed only if core 0 alone is running */ - if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) { - dev_warn(ctx->dev, - "D0i3 allowed when only core0 running:Exit\n"); - return; - } - - target_state = bxt_d0i3_target_state(ctx); - if (target_state == SKL_DSP_D0I3_NONE) - return; - - msg.instance_id = 0; - msg.module_id = 0; - msg.wake = 1; - msg.streaming = 0; - if (target_state == SKL_DSP_D0I3_STREAMING) - msg.streaming = 1; - - ret = skl_ipc_set_d0ix(&skl->ipc, &msg); - - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); - return; - } - - /* Set Vendor specific register D0I3C.I3 to enable D0i3*/ - if (skl->update_d0i3c) - skl->update_d0i3c(skl->dev, true); - - d0i3->state = target_state; - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; -} - -static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - /* Schedule D0i3 only if the usecase ref counts are appropriate */ - if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { - - dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); - - schedule_delayed_work(&d0i3->work, - msecs_to_jiffies(BXT_D0I3_DELAY)); - } - - return 0; -} - -static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) -{ - int ret; - struct skl_ipc_d0ix_msg msg; - struct skl_dev *skl = ctx->thread_context; - - dev_dbg(ctx->dev, "In %s:\n", __func__); - - /* First Cancel any pending attempt to put DSP to D0i3 */ - cancel_delayed_work_sync(&skl->d0i3.work); - - /* If DSP is currently in D0i3, bring it to D0i0 */ - if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) - return 0; - - dev_dbg(ctx->dev, "Set DSP to D0i0\n"); - - msg.instance_id = 0; - msg.module_id = 0; - msg.streaming = 0; - msg.wake = 0; - - if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) - msg.streaming = 1; - - /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ - if (skl->update_d0i3c) - skl->update_d0i3c(skl->dev, false); - - ret = skl_ipc_set_d0ix(&skl->ipc, &msg); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); - return ret; - } - - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; - skl->d0i3.state = SKL_DSP_D0I3_NONE; - - return 0; -} - -static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret; - struct skl_ipc_dxstate_info dx; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - if (skl->fw_loaded == false) { - skl->boot_complete = false; - ret = bxt_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "reload fw failed: %d\n", ret); - return ret; - } - - if (skl->lib_count > 1) { - ret = bxt_load_library(ctx, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(ctx->dev, "reload libs failed: %d\n", ret); - return ret; - } - } - skl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; - } - - /* If core 0 is being turned on, turn on core 1 as well */ - if (core_id == SKL_DSP_CORE0_ID) - ret = skl_dsp_core_power_up(ctx, core_mask | - SKL_DSP_CORE_MASK(1)); - else - ret = skl_dsp_core_power_up(ctx, core_mask); - - if (ret < 0) - goto err; - - if (core_id == SKL_DSP_CORE0_ID) { - - /* - * Enable interrupt after SPA is set and before - * DSP is unstalled - */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - skl->boot_complete = false; - } - - ret = skl_dsp_start_core(ctx, core_mask); - if (ret < 0) - goto err; - - if (core_id == SKL_DSP_CORE0_ID) { - ret = wait_event_timeout(skl->boot_wait, - skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - - /* If core 1 was turned on for booting core 0, turn it off */ - skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); - if (ret == 0) { - dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__); - dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", - sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), - sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); - dev_err(ctx->dev, "Failed to set core0 to D0 state\n"); - ret = -EIO; - goto err; - } - } - - /* Tell FW if additional core in now On */ - - if (core_id != SKL_DSP_CORE0_ID) { - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, - BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n", - core_id, ret); - goto err; - } - } - - skl->cores.state[core_id] = SKL_DSP_RUNNING; - return 0; -err: - if (core_id == SKL_DSP_CORE0_ID) - core_mask |= SKL_DSP_CORE_MASK(1); - skl_dsp_disable_core(ctx, core_mask); - - return ret; -} - -static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n", - dx.core_mask, dx.dx_mask); - - ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, - BXT_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, - "Failed to set DSP to D3:core id = %d;Continue reset\n", - core_id); - /* - * In case of D3 failure, re-download the firmware, so set - * fw_loaded to false. - */ - skl->fw_loaded = false; - } - - if (core_id == SKL_DSP_CORE0_ID) { - /* disable Interrupt */ - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - ret = skl_dsp_disable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "Failed to disable core %d\n", ret); - return ret; - } - skl->cores.state[core_id] = SKL_DSP_RESET; - return 0; -} - -static const struct skl_dsp_fw_ops bxt_fw_ops = { - .set_state_D0 = bxt_set_dsp_D0, - .set_state_D3 = bxt_set_dsp_D3, - .set_state_D0i3 = bxt_schedule_dsp_D0i3, - .set_state_D0i0 = bxt_set_dsp_D0i0, - .load_fw = bxt_load_base_firmware, - .get_fw_errcode = bxt_get_errorcode, - .load_library = bxt_load_library, -}; - -static struct sst_ops skl_ops = { - .irq_handler = skl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = skl_dsp_free, -}; - -static struct sst_dsp_device skl_dev = { - .thread = skl_dsp_irq_thread_handler, - .ops = &skl_ops, -}; - -int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *skl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - skl = *dsp; - sst = skl->dsp; - sst->fw_ops = bxt_fw_ops; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = BXT_ADSP_SRAM0_BASE; - sst->addr.sram1_base = BXT_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (BXT_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), - SKL_ADSP_W0_UP_SZ, BXT_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - - ret = skl_ipc_init(dev, skl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - /* set the D0i3 check */ - skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; - - skl->boot_complete = false; - init_waitqueue_head(&skl->boot_wait); - INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); - skl->d0i3.state = SKL_DSP_D0I3_NONE; - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); - -int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = sst->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "Load base fw failed: %x\n", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - if (skl->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(dev, "Load Library failed : %x\n", ret); - return ret; - } - } - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(bxt_sst_init_fw); - -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - - skl_release_library(skl->lib_info, skl->lib_count); - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - skl_freeup_uuid_list(skl); - skl_ipc_free(&skl->ipc); - skl->dsp->ops->free(skl->dsp); -} -EXPORT_SYMBOL_GPL(bxt_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Broxton IPC driver"); diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c deleted file mode 100644 index 3ef1b194add1..000000000000 --- a/sound/soc/intel/skylake/cnl-sst-dsp.c +++ /dev/null @@ -1,266 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cnl-sst-dsp.c - CNL SST library generic function - * - * Copyright (C) 2016-17, Intel Corporation. - * Author: Guneshwor Singh <guneshwor.o.singh@intel.com> - * - * Modified from: - * SKL SST library generic function - * Copyright (C) 2014-15, Intel Corporation. - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/device.h> -#include "../common/sst-dsp.h" -#include "../common/sst-ipc.h" -#include "../common/sst-dsp-priv.h" -#include "cnl-sst-dsp.h" - -/* various timeout values */ -#define CNL_DSP_PU_TO 50 -#define CNL_DSP_PD_TO 50 -#define CNL_DSP_RESET_TO 50 - -static int -cnl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, - CNL_ADSP_REG_ADSPCS, CNL_ADSPCS_CRST(core_mask), - CNL_ADSPCS_CRST(core_mask)); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), - CNL_ADSPCS_CRST(core_mask), - CNL_DSP_RESET_TO, - "Set reset"); -} - -static int -cnl_dsp_core_unset_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CRST(core_mask), - 0, - CNL_DSP_RESET_TO, - "Unset reset"); -} - -static bool is_cnl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) -{ - int val; - bool is_enable; - - val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPCS); - - is_enable = (val & CNL_ADSPCS_CPA(core_mask)) && - (val & CNL_ADSPCS_SPA(core_mask)) && - !(val & CNL_ADSPCS_CRST(core_mask)) && - !(val & CNL_ADSPCS_CSTALL(core_mask)); - - dev_dbg(ctx->dev, "DSP core(s) enabled? %d: core_mask %#x\n", - is_enable, core_mask); - - return is_enable; -} - -static int cnl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* stall core */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CSTALL(core_mask), - CNL_ADSPCS_CSTALL(core_mask)); - - /* set reset state */ - return cnl_dsp_core_set_reset_state(ctx, core_mask); -} - -static int cnl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* unset reset state */ - ret = cnl_dsp_core_unset_reset_state(ctx, core_mask); - if (ret < 0) - return ret; - - /* run core */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CSTALL(core_mask), 0); - - if (!is_cnl_dsp_core_enable(ctx, core_mask)) { - cnl_dsp_reset_core(ctx, core_mask); - dev_err(ctx->dev, "DSP core mask %#x enable failed\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -static int cnl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_SPA(core_mask), - CNL_ADSPCS_SPA(core_mask)); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CPA(core_mask), - CNL_ADSPCS_CPA(core_mask), - CNL_DSP_PU_TO, - "Power up"); -} - -static int cnl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_SPA(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - CNL_ADSP_REG_ADSPCS, - CNL_ADSPCS_CPA(core_mask), - 0, - CNL_DSP_PD_TO, - "Power down"); -} - -int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* power up */ - ret = cnl_dsp_core_power_up(ctx, core_mask); - if (ret < 0) { - dev_dbg(ctx->dev, "DSP core mask %#x power up failed", - core_mask); - return ret; - } - - return cnl_dsp_start_core(ctx, core_mask); -} - -int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - ret = cnl_dsp_reset_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "DSP core mask %#x reset failed\n", - core_mask); - return ret; - } - - /* power down core*/ - ret = cnl_dsp_core_power_down(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "DSP core mask %#x power down failed\n", - core_mask); - return ret; - } - - if (is_cnl_dsp_core_enable(ctx, core_mask)) { - dev_err(ctx->dev, "DSP core mask %#x disable failed\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id) -{ - struct sst_dsp *ctx = dev_id; - u32 val; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&ctx->spinlock); - - val = sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS); - ctx->intr_status = val; - - if (val == 0xffffffff) { - spin_unlock(&ctx->spinlock); - return IRQ_NONE; - } - - if (val & CNL_ADSPIS_IPC) { - cnl_ipc_int_disable(ctx); - ret = IRQ_WAKE_THREAD; - } - - spin_unlock(&ctx->spinlock); - - return ret; -} - -void cnl_dsp_free(struct sst_dsp *dsp) -{ - cnl_ipc_int_disable(dsp); - - free_irq(dsp->irq, dsp); - cnl_ipc_op_int_disable(dsp); - cnl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); -} -EXPORT_SYMBOL_GPL(cnl_dsp_free); - -void cnl_ipc_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC, - CNL_ADSPIC_IPC, CNL_ADSPIC_IPC); -} - -void cnl_ipc_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, CNL_ADSP_REG_ADSPIC, - CNL_ADSPIC_IPC, 0); -} - -void cnl_ipc_op_int_enable(struct sst_dsp *ctx) -{ - /* enable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, - CNL_ADSP_REG_HIPCCTL_DONE); - - /* enable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_BUSY, - CNL_ADSP_REG_HIPCCTL_BUSY); -} - -void cnl_ipc_op_int_disable(struct sst_dsp *ctx) -{ - /* disable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, 0); - - /* disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_BUSY, 0); -} - -bool cnl_ipc_int_status(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read_unlocked(ctx, CNL_ADSP_REG_ADSPIS) & - CNL_ADSPIS_IPC; -} - -void cnl_ipc_free(struct sst_generic_ipc *ipc) -{ - cnl_ipc_op_int_disable(ipc->dsp); - sst_ipc_fini(ipc); -} diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h deleted file mode 100644 index d3cf4bd1a070..000000000000 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ /dev/null @@ -1,103 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Cannonlake SST DSP Support - * - * Copyright (C) 2016-17, Intel Corporation. - */ - -#ifndef __CNL_SST_DSP_H__ -#define __CNL_SST_DSP_H__ - -struct sst_dsp; -struct sst_dsp_device; -struct sst_generic_ipc; - -/* Intel HD Audio General DSP Registers */ -#define CNL_ADSP_GEN_BASE 0x0 -#define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04) -#define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08) -#define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c) - -/* Intel HD Audio Inter-Processor Communication Registers */ -#define CNL_ADSP_IPC_BASE 0xc0 -#define CNL_ADSP_REG_HIPCTDR (CNL_ADSP_IPC_BASE + 0x00) -#define CNL_ADSP_REG_HIPCTDA (CNL_ADSP_IPC_BASE + 0x04) -#define CNL_ADSP_REG_HIPCTDD (CNL_ADSP_IPC_BASE + 0x08) -#define CNL_ADSP_REG_HIPCIDR (CNL_ADSP_IPC_BASE + 0x10) -#define CNL_ADSP_REG_HIPCIDA (CNL_ADSP_IPC_BASE + 0x14) -#define CNL_ADSP_REG_HIPCIDD (CNL_ADSP_IPC_BASE + 0x18) -#define CNL_ADSP_REG_HIPCCTL (CNL_ADSP_IPC_BASE + 0x28) - -/* HIPCTDR */ -#define CNL_ADSP_REG_HIPCTDR_BUSY BIT(31) - -/* HIPCTDA */ -#define CNL_ADSP_REG_HIPCTDA_DONE BIT(31) - -/* HIPCIDR */ -#define CNL_ADSP_REG_HIPCIDR_BUSY BIT(31) - -/* HIPCIDA */ -#define CNL_ADSP_REG_HIPCIDA_DONE BIT(31) - -/* CNL HIPCCTL */ -#define CNL_ADSP_REG_HIPCCTL_DONE BIT(1) -#define CNL_ADSP_REG_HIPCCTL_BUSY BIT(0) - -/* CNL HIPCT */ -#define CNL_ADSP_REG_HIPCT_BUSY BIT(31) - -/* Intel HD Audio SRAM Window 1 */ -#define CNL_ADSP_SRAM1_BASE 0xa0000 - -#define CNL_ADSP_MMIO_LEN 0x10000 - -#define CNL_ADSP_W0_STAT_SZ 0x1000 - -#define CNL_ADSP_W0_UP_SZ 0x1000 - -#define CNL_ADSP_W1_SZ 0x1000 - -#define CNL_FW_STS_MASK 0xf - -#define CNL_ADSPIC_IPC 0x1 -#define CNL_ADSPIS_IPC 0x1 - -#define CNL_DSP_CORES 4 -#define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1) - -/* core reset - asserted high */ -#define CNL_ADSPCS_CRST_SHIFT 0 -#define CNL_ADSPCS_CRST(x) (x << CNL_ADSPCS_CRST_SHIFT) - -/* core run/stall - when set to 1 core is stalled */ -#define CNL_ADSPCS_CSTALL_SHIFT 8 -#define CNL_ADSPCS_CSTALL(x) (x << CNL_ADSPCS_CSTALL_SHIFT) - -/* set power active - when set to 1 turn core on */ -#define CNL_ADSPCS_SPA_SHIFT 16 -#define CNL_ADSPCS_SPA(x) (x << CNL_ADSPCS_SPA_SHIFT) - -/* current power active - power status of cores, set by hardware */ -#define CNL_ADSPCS_CPA_SHIFT 24 -#define CNL_ADSPCS_CPA(x) (x << CNL_ADSPCS_CPA_SHIFT) - -int cnl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); -int cnl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); -irqreturn_t cnl_dsp_sst_interrupt(int irq, void *dev_id); -void cnl_dsp_free(struct sst_dsp *dsp); - -void cnl_ipc_int_enable(struct sst_dsp *ctx); -void cnl_ipc_int_disable(struct sst_dsp *ctx); -void cnl_ipc_op_int_enable(struct sst_dsp *ctx); -void cnl_ipc_op_int_disable(struct sst_dsp *ctx); -bool cnl_ipc_int_status(struct sst_dsp *ctx); -void cnl_ipc_free(struct sst_generic_ipc *ipc); - -int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl); -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); - -#endif /*__CNL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c deleted file mode 100644 index 1275c149acc0..000000000000 --- a/sound/soc/intel/skylake/cnl-sst.c +++ /dev/null @@ -1,508 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * cnl-sst.c - DSP library functions for CNL platform - * - * Copyright (C) 2016-17, Intel Corporation. - * - * Author: Guneshwor Singh <guneshwor.o.singh@intel.com> - * - * Modified from: - * HDA DSP library functions for SKL platform - * Copyright (C) 2014-15, Intel Corporation. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/firmware.h> -#include <linux/device.h> - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "../common/sst-ipc.h" -#include "cnl-sst-dsp.h" -#include "skl.h" - -#define CNL_FW_ROM_INIT 0x1 -#define CNL_FW_INIT 0x5 -#define CNL_IPC_PURGE 0x01004000 -#define CNL_INIT_TIMEOUT 300 -#define CNL_BASEFW_TIMEOUT 3000 - -#define CNL_ADSP_SRAM0_BASE 0x80000 - -/* Firmware status window */ -#define CNL_ADSP_FW_STATUS CNL_ADSP_SRAM0_BASE -#define CNL_ADSP_ERROR_CODE (CNL_ADSP_FW_STATUS + 0x4) - -#define CNL_INSTANCE_ID 0 -#define CNL_BASE_FW_MODULE_ID 0 -#define CNL_ADSP_FW_HDR_OFFSET 0x2000 -#define CNL_ROM_CTRL_DMA_ID 0x9 - -static int cnl_prepare_fw(struct sst_dsp *ctx, const void *fwdata, u32 fwsize) -{ - - int ret, stream_tag; - - stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); - if (stream_tag <= 0) { - dev_err(ctx->dev, "dma prepare failed: 0%#x\n", stream_tag); - return stream_tag; - } - - ctx->dsp_ops.stream_tag = stream_tag; - memcpy(ctx->dmab.area, fwdata, fwsize); - - ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 power up failed\n"); - ret = -EIO; - goto base_fw_load_failed; - } - - /* purge FW request */ - sst_dsp_shim_write(ctx, CNL_ADSP_REG_HIPCIDR, - CNL_ADSP_REG_HIPCIDR_BUSY | (CNL_IPC_PURGE | - ((stream_tag - 1) << CNL_ROM_CTRL_DMA_ID))); - - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); - ret = -EIO; - goto base_fw_load_failed; - } - - ret = sst_dsp_register_poll(ctx, CNL_ADSP_REG_HIPCIDA, - CNL_ADSP_REG_HIPCIDA_DONE, - CNL_ADSP_REG_HIPCIDA_DONE, - BXT_INIT_TIMEOUT, "HIPCIDA Done"); - if (ret < 0) { - dev_err(ctx->dev, "timeout for purge request: %d\n", ret); - goto base_fw_load_failed; - } - - /* enable interrupt */ - cnl_ipc_int_enable(ctx); - cnl_ipc_op_int_enable(ctx); - - ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, - CNL_FW_ROM_INIT, CNL_INIT_TIMEOUT, - "rom load"); - if (ret < 0) { - dev_err(ctx->dev, "rom init timeout, ret: %d\n", ret); - goto base_fw_load_failed; - } - - return 0; - -base_fw_load_failed: - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - - return ret; -} - -static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) -{ - int ret; - - ctx->dsp_ops.trigger(ctx->dev, true, ctx->dsp_ops.stream_tag); - ret = sst_dsp_register_poll(ctx, CNL_ADSP_FW_STATUS, CNL_FW_STS_MASK, - CNL_FW_INIT, CNL_BASEFW_TIMEOUT, - "firmware boot"); - - ctx->dsp_ops.trigger(ctx->dev, false, ctx->dsp_ops.stream_tag); - ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, ctx->dsp_ops.stream_tag); - - return ret; -} - -static int cnl_load_base_firmware(struct sst_dsp *ctx) -{ - struct firmware stripped_fw; - struct skl_dev *cnl = ctx->thread_context; - int ret, i; - - if (!ctx->fw) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "request firmware failed: %d\n", ret); - goto cnl_load_base_firmware_failed; - } - } - - /* parse uuids if first boot */ - if (cnl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, - CNL_ADSP_FW_HDR_OFFSET, 0); - if (ret < 0) - goto cnl_load_base_firmware_failed; - } - - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - skl_dsp_strip_extended_manifest(&stripped_fw); - - for (i = 0; i < BXT_FW_ROM_INIT_RETRY; i++) { - ret = cnl_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); - if (!ret) - break; - dev_dbg(ctx->dev, "prepare firmware failed: %d\n", ret); - } - - if (ret < 0) - goto cnl_load_base_firmware_failed; - - ret = sst_transfer_fw_host_dma(ctx); - if (ret < 0) { - dev_err(ctx->dev, "transfer firmware failed: %d\n", ret); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - goto cnl_load_base_firmware_failed; - } - - ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "FW ready timed-out\n"); - cnl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - ret = -EIO; - goto cnl_load_base_firmware_failed; - } - - cnl->fw_loaded = true; - - return 0; - -cnl_load_base_firmware_failed: - dev_err(ctx->dev, "firmware load failed: %d\n", ret); - release_firmware(ctx->fw); - ctx->fw = NULL; - - return ret; -} - -static int cnl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *cnl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_ipc_dxstate_info dx; - int ret; - - if (!cnl->fw_loaded) { - cnl->boot_complete = false; - ret = cnl_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "fw reload failed: %d\n", ret); - return ret; - } - - cnl->cores.state[core_id] = SKL_DSP_RUNNING; - return ret; - } - - ret = cnl_dsp_enable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "enable dsp core %d failed: %d\n", - core_id, ret); - goto err; - } - - if (core_id == SKL_DSP_CORE0_ID) { - /* enable interrupt */ - cnl_ipc_int_enable(ctx); - cnl_ipc_op_int_enable(ctx); - cnl->boot_complete = false; - - ret = wait_event_timeout(cnl->boot_wait, cnl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, - "dsp boot timeout, status=%#x error=%#x\n", - sst_dsp_shim_read(ctx, CNL_ADSP_FW_STATUS), - sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE)); - ret = -ETIMEDOUT; - goto err; - } - } else { - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, - CNL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "set_dx failed, core: %d ret: %d\n", - core_id, ret); - goto err; - } - } - cnl->cores.state[core_id] = SKL_DSP_RUNNING; - - return 0; -err: - cnl_dsp_disable_core(ctx, core_mask); - - return ret; -} - -static int cnl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *cnl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - struct skl_ipc_dxstate_info dx; - int ret; - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - ret = skl_ipc_set_dx(&cnl->ipc, CNL_INSTANCE_ID, - CNL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, - "dsp core %d to d3 failed; continue reset\n", - core_id); - cnl->fw_loaded = false; - } - - /* disable interrupts if core 0 */ - if (core_id == SKL_DSP_CORE0_ID) { - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - - ret = cnl_dsp_disable_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "disable dsp core %d failed: %d\n", - core_id, ret); - return ret; - } - - cnl->cores.state[core_id] = SKL_DSP_RESET; - - return ret; -} - -static unsigned int cnl_get_errno(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, CNL_ADSP_ERROR_CODE); -} - -static const struct skl_dsp_fw_ops cnl_fw_ops = { - .set_state_D0 = cnl_set_dsp_D0, - .set_state_D3 = cnl_set_dsp_D3, - .load_fw = cnl_load_base_firmware, - .get_fw_errcode = cnl_get_errno, -}; - -static struct sst_ops cnl_ops = { - .irq_handler = cnl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = cnl_dsp_free, -}; - -#define CNL_IPC_GLB_NOTIFY_RSP_SHIFT 29 -#define CNL_IPC_GLB_NOTIFY_RSP_MASK 0x1 -#define CNL_IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> CNL_IPC_GLB_NOTIFY_RSP_SHIFT) \ - & CNL_IPC_GLB_NOTIFY_RSP_MASK) - -static irqreturn_t cnl_dsp_irq_thread_handler(int irq, void *context) -{ - struct sst_dsp *dsp = context; - struct skl_dev *cnl = dsp->thread_context; - struct sst_generic_ipc *ipc = &cnl->ipc; - struct skl_ipc_header header = {0}; - u32 hipcida, hipctdr, hipctdd; - int ipc_irq = 0; - - /* here we handle ipc interrupts only */ - if (!(dsp->intr_status & CNL_ADSPIS_IPC)) - return IRQ_NONE; - - hipcida = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDA); - hipctdr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDR); - hipctdd = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCTDD); - - /* reply message from dsp */ - if (hipcida & CNL_ADSP_REG_HIPCIDA_DONE) { - sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, 0); - - /* clear done bit - tell dsp operation is complete */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCIDA, - CNL_ADSP_REG_HIPCIDA_DONE, CNL_ADSP_REG_HIPCIDA_DONE); - - ipc_irq = 1; - - /* unmask done interrupt */ - sst_dsp_shim_update_bits(dsp, CNL_ADSP_REG_HIPCCTL, - CNL_ADSP_REG_HIPCCTL_DONE, CNL_ADSP_REG_HIPCCTL_DONE); - } - - /* new message from dsp */ - if (hipctdr & CNL_ADSP_REG_HIPCTDR_BUSY) { - header.primary = hipctdr; - header.extension = hipctdd; - dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", - header.primary); - dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", - header.extension); - - if (CNL_IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { - /* Handle Immediate reply from DSP Core */ - skl_ipc_process_reply(ipc, header); - } else { - dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); - skl_ipc_process_notification(ipc, header); - } - /* clear busy interrupt */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDR, - CNL_ADSP_REG_HIPCTDR_BUSY, CNL_ADSP_REG_HIPCTDR_BUSY); - - /* set done bit to ack dsp */ - sst_dsp_shim_update_bits_forced(dsp, CNL_ADSP_REG_HIPCTDA, - CNL_ADSP_REG_HIPCTDA_DONE, CNL_ADSP_REG_HIPCTDA_DONE); - ipc_irq = 1; - } - - if (ipc_irq == 0) - return IRQ_NONE; - - cnl_ipc_int_enable(dsp); - - /* continue to send any remaining messages */ - schedule_work(&ipc->kwork); - - return IRQ_HANDLED; -} - -static struct sst_dsp_device cnl_dev = { - .thread = cnl_dsp_irq_thread_handler, - .ops = &cnl_ops, -}; - -static void cnl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) -{ - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - - if (msg->tx.size) - sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDD, - header->extension); - sst_dsp_shim_write_unlocked(ipc->dsp, CNL_ADSP_REG_HIPCIDR, - header->primary | CNL_ADSP_REG_HIPCIDR_BUSY); -} - -static bool cnl_ipc_is_dsp_busy(struct sst_dsp *dsp) -{ - u32 hipcidr; - - hipcidr = sst_dsp_shim_read_unlocked(dsp, CNL_ADSP_REG_HIPCIDR); - - return (hipcidr & CNL_ADSP_REG_HIPCIDR_BUSY); -} - -static int cnl_ipc_init(struct device *dev, struct skl_dev *cnl) -{ - struct sst_generic_ipc *ipc; - int err; - - ipc = &cnl->ipc; - ipc->dsp = cnl->dsp; - ipc->dev = dev; - - ipc->tx_data_max_size = CNL_ADSP_W1_SZ; - ipc->rx_data_max_size = CNL_ADSP_W0_UP_SZ; - - err = sst_ipc_init(ipc); - if (err) - return err; - - /* - * overriding tx_msg and is_dsp_busy since - * ipc registers are different for cnl - */ - ipc->ops.tx_msg = cnl_ipc_tx_msg; - ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; - ipc->ops.is_dsp_busy = cnl_ipc_is_dsp_busy; - - return 0; -} - -int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *cnl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &cnl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - cnl = *dsp; - sst = cnl->dsp; - sst->fw_ops = cnl_fw_ops; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = CNL_ADSP_SRAM0_BASE; - sst->addr.sram1_base = CNL_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = CNL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = CNL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (CNL_ADSP_SRAM0_BASE + CNL_ADSP_W0_STAT_SZ), - CNL_ADSP_W0_UP_SZ, CNL_ADSP_SRAM1_BASE, - CNL_ADSP_W1_SZ); - - ret = cnl_ipc_init(dev, cnl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - cnl->boot_complete = false; - init_waitqueue_head(&cnl->boot_wait); - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); - -int cnl_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = skl->dsp->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "load base fw failed: %d", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(cnl_sst_init_fw); - -void cnl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - - skl_freeup_uuid_list(skl); - cnl_ipc_free(&skl->ipc); - - skl->dsp->ops->free(skl->dsp); -} -EXPORT_SYMBOL_GPL(cnl_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Cannonlake IPC driver"); diff --git a/sound/soc/intel/skylake/skl-debug.c b/sound/soc/intel/skylake/skl-debug.c deleted file mode 100644 index a15aa2ffa681..000000000000 --- a/sound/soc/intel/skylake/skl-debug.c +++ /dev/null @@ -1,248 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-debug.c - Debugfs for skl driver - * - * Copyright (C) 2016-17 Intel Corp - */ - -#include <linux/pci.h> -#include <linux/debugfs.h> -#include <uapi/sound/skl-tplg-interface.h> -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl-topology.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -#define MOD_BUF PAGE_SIZE -#define FW_REG_BUF PAGE_SIZE -#define FW_REG_SIZE 0x60 - -struct skl_debug { - struct skl_dev *skl; - struct device *dev; - - struct dentry *fs; - struct dentry *modules; - u8 fw_read_buff[FW_REG_BUF]; -}; - -static ssize_t skl_print_pins(struct skl_module_pin *m_pin, char *buf, - int max_pin, ssize_t size, bool direction) -{ - int i; - ssize_t ret = 0; - - for (i = 0; i < max_pin; i++) { - ret += scnprintf(buf + size, MOD_BUF - size, - "%s %d\n\tModule %d\n\tInstance %d\n\t" - "In-used %s\n\tType %s\n" - "\tState %d\n\tIndex %d\n", - direction ? "Input Pin:" : "Output Pin:", - i, m_pin[i].id.module_id, - m_pin[i].id.instance_id, - m_pin[i].in_use ? "Used" : "Unused", - m_pin[i].is_dynamic ? "Dynamic" : "Static", - m_pin[i].pin_state, i); - size += ret; - } - return ret; -} - -static ssize_t skl_print_fmt(struct skl_module_fmt *fmt, char *buf, - ssize_t size, bool direction) -{ - return scnprintf(buf + size, MOD_BUF - size, - "%s\n\tCh %d\n\tFreq %d\n\tBit depth %d\n\t" - "Valid bit depth %d\n\tCh config %#x\n\tInterleaving %d\n\t" - "Sample Type %d\n\tCh Map %#x\n", - direction ? "Input Format:" : "Output Format:", - fmt->channels, fmt->s_freq, fmt->bit_depth, - fmt->valid_bit_depth, fmt->ch_cfg, - fmt->interleaving_style, fmt->sample_type, - fmt->ch_map); -} - -static ssize_t module_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct skl_module_cfg *mconfig = file->private_data; - struct skl_module *module = mconfig->module; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - char *buf; - ssize_t ret; - - buf = kzalloc(MOD_BUF, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - ret = scnprintf(buf, MOD_BUF, "Module:\n\tUUID %pUL\n\tModule id %d\n" - "\tInstance id %d\n\tPvt_id %d\n", mconfig->guid, - mconfig->id.module_id, mconfig->id.instance_id, - mconfig->id.pvt_id); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Resources:\n\tCPC %#x\n\tIBS %#x\n\tOBS %#x\t\n", - res->cpc, res->ibs, res->obs); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Module data:\n\tCore %d\n\tIn queue %d\n\t" - "Out queue %d\n\tType %s\n", - mconfig->core_id, mconfig->max_in_queue, - mconfig->max_out_queue, - mconfig->is_loadable ? "loadable" : "inbuilt"); - - ret += skl_print_fmt(mconfig->in_fmt, buf, ret, true); - ret += skl_print_fmt(mconfig->out_fmt, buf, ret, false); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Fixup:\n\tParams %#x\n\tConverter %#x\n", - mconfig->params_fixup, mconfig->converter); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Module Gateway:\n\tType %#x\n\tVbus %#x\n\tHW conn %#x\n\tSlot %#x\n", - mconfig->dev_type, mconfig->vbus_id, - mconfig->hw_conn_type, mconfig->time_slot); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Pipeline:\n\tID %d\n\tPriority %d\n\tConn Type %d\n\t" - "Pages %#x\n", mconfig->pipe->ppl_id, - mconfig->pipe->pipe_priority, mconfig->pipe->conn_type, - mconfig->pipe->memory_pages); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tParams:\n\t\tHost DMA %d\n\t\tLink DMA %d\n", - mconfig->pipe->p_params->host_dma_id, - mconfig->pipe->p_params->link_dma_id); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tPCM params:\n\t\tCh %d\n\t\tFreq %d\n\t\tFormat %d\n", - mconfig->pipe->p_params->ch, - mconfig->pipe->p_params->s_freq, - mconfig->pipe->p_params->s_fmt); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tLink %#x\n\tStream %#x\n", - mconfig->pipe->p_params->linktype, - mconfig->pipe->p_params->stream); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "\tState %d\n\tPassthru %s\n", - mconfig->pipe->state, - mconfig->pipe->passthru ? "true" : "false"); - - ret += skl_print_pins(mconfig->m_in_pin, buf, - mconfig->max_in_queue, ret, true); - ret += skl_print_pins(mconfig->m_out_pin, buf, - mconfig->max_out_queue, ret, false); - - ret += scnprintf(buf + ret, MOD_BUF - ret, - "Other:\n\tDomain %d\n\tHomogeneous Input %s\n\t" - "Homogeneous Output %s\n\tIn Queue Mask %d\n\t" - "Out Queue Mask %d\n\tDMA ID %d\n\tMem Pages %d\n\t" - "Module Type %d\n\tModule State %d\n", - mconfig->domain, - mconfig->homogenous_inputs ? "true" : "false", - mconfig->homogenous_outputs ? "true" : "false", - mconfig->in_queue_mask, mconfig->out_queue_mask, - mconfig->dma_id, mconfig->mem_pages, mconfig->m_state, - mconfig->m_type); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - - kfree(buf); - return ret; -} - -static const struct file_operations mcfg_fops = { - .open = simple_open, - .read = module_read, - .llseek = default_llseek, -}; - - -void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig) -{ - debugfs_create_file(w->name, 0444, d->modules, mconfig, - &mcfg_fops); -} - -static ssize_t fw_softreg_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct skl_debug *d = file->private_data; - struct sst_dsp *sst = d->skl->dsp; - size_t w0_stat_sz = sst->addr.w0_stat_sz; - void __iomem *in_base = sst->mailbox.in_base; - void __iomem *fw_reg_addr; - unsigned int offset; - char *tmp; - ssize_t ret = 0; - - tmp = kzalloc(FW_REG_BUF, GFP_KERNEL); - if (!tmp) - return -ENOMEM; - - fw_reg_addr = in_base - w0_stat_sz; - memset(d->fw_read_buff, 0, FW_REG_BUF); - - if (w0_stat_sz > 0) - __ioread32_copy(d->fw_read_buff, fw_reg_addr, w0_stat_sz >> 2); - - for (offset = 0; offset < FW_REG_SIZE; offset += 16) { - ret += scnprintf(tmp + ret, FW_REG_BUF - ret, "%#.4x: ", offset); - hex_dump_to_buffer(d->fw_read_buff + offset, 16, 16, 4, - tmp + ret, FW_REG_BUF - ret, 0); - ret += strlen(tmp + ret); - - /* print newline for each offset */ - if (FW_REG_BUF - ret > 0) - tmp[ret++] = '\n'; - } - - ret = simple_read_from_buffer(user_buf, count, ppos, tmp, ret); - kfree(tmp); - - return ret; -} - -static const struct file_operations soft_regs_ctrl_fops = { - .open = simple_open, - .read = fw_softreg_read, - .llseek = default_llseek, -}; - -struct skl_debug *skl_debugfs_init(struct skl_dev *skl) -{ - struct skl_debug *d; - - d = devm_kzalloc(&skl->pci->dev, sizeof(*d), GFP_KERNEL); - if (!d) - return NULL; - - /* create the debugfs dir with platform component's debugfs as parent */ - d->fs = debugfs_create_dir("dsp", skl->component->debugfs_root); - - d->skl = skl; - d->dev = &skl->pci->dev; - - /* now create the module dir */ - d->modules = debugfs_create_dir("modules", d->fs); - - debugfs_create_file("fw_soft_regs_rd", 0444, d->fs, d, - &soft_regs_ctrl_fops); - - return d; -} - -void skl_debugfs_exit(struct skl_dev *skl) -{ - struct skl_debug *d = skl->debugfs; - - debugfs_remove_recursive(d->fs); - - d = NULL; -} diff --git a/sound/soc/intel/skylake/skl-i2s.h b/sound/soc/intel/skylake/skl-i2s.h deleted file mode 100644 index dfce91e11be1..000000000000 --- a/sound/soc/intel/skylake/skl-i2s.h +++ /dev/null @@ -1,87 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl-i2s.h - i2s blob mapping - * - * Copyright (C) 2017 Intel Corp - * Author: Subhransu S. Prusty < subhransu.s.prusty@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SOUND_SOC_SKL_I2S_H -#define __SOUND_SOC_SKL_I2S_H - -#define SKL_I2S_MAX_TIME_SLOTS 8 -#define SKL_MCLK_DIV_CLK_SRC_MASK GENMASK(17, 16) - -#define SKL_MNDSS_DIV_CLK_SRC_MASK GENMASK(21, 20) -#define SKL_SHIFT(x) (ffs(x) - 1) -#define SKL_MCLK_DIV_RATIO_MASK GENMASK(11, 0) - -#define is_legacy_blob(x) (x.signature != 0xEE) -#define ext_to_legacy_blob(i2s_config_blob_ext) \ - ((struct skl_i2s_config_blob_legacy *) i2s_config_blob_ext) - -#define get_clk_src(mclk, mask) \ - ((mclk.mdivctrl & mask) >> SKL_SHIFT(mask)) -struct skl_i2s_config { - u32 ssc0; - u32 ssc1; - u32 sscto; - u32 sspsp; - u32 sstsa; - u32 ssrsa; - u32 ssc2; - u32 sspsp2; - u32 ssc3; - u32 ssioc; -} __packed; - -struct skl_i2s_config_mclk { - u32 mdivctrl; - u32 mdivr; -}; - -struct skl_i2s_config_mclk_ext { - u32 mdivctrl; - u32 mdivr_count; - u32 mdivr[]; -} __packed; - -struct skl_i2s_config_blob_signature { - u32 minor_ver : 8; - u32 major_ver : 8; - u32 resvdz : 8; - u32 signature : 8; -} __packed; - -struct skl_i2s_config_blob_header { - struct skl_i2s_config_blob_signature sig; - u32 size; -}; - -/** - * struct skl_i2s_config_blob_legacy - Structure defines I2S Gateway - * configuration legacy blob - * - * @gtw_attr: Gateway attribute for the I2S Gateway - * @tdm_ts_group: TDM slot mapping against channels in the Gateway. - * @i2s_cfg: I2S HW registers - * @mclk: MCLK clock source and divider values - */ -struct skl_i2s_config_blob_legacy { - u32 gtw_attr; - u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; - struct skl_i2s_config i2s_cfg; - struct skl_i2s_config_mclk mclk; -}; - -struct skl_i2s_config_blob_ext { - u32 gtw_attr; - struct skl_i2s_config_blob_header hdr; - u32 tdm_ts_group[SKL_I2S_MAX_TIME_SLOTS]; - struct skl_i2s_config i2s_cfg; - struct skl_i2s_config_mclk_ext mclk; -} __packed; -#endif /* __SOUND_SOC_SKL_I2S_H */ diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c deleted file mode 100644 index fc2eb04da172..000000000000 --- a/sound/soc/intel/skylake/skl-messages.c +++ /dev/null @@ -1,1419 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-message.c - HDA DSP interface for FW registration, Pipe and Module - * configurations - * - * Copyright (C) 2015 Intel Corp - * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/slab.h> -#include <linux/pci.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <uapi/sound/skl-tplg-interface.h> -#include "skl-sst-dsp.h" -#include "cnl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl-topology.h" - -static int skl_alloc_dma_buf(struct device *dev, - struct snd_dma_buffer *dmab, size_t size) -{ - return snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size, dmab); -} - -static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) -{ - snd_dma_free_pages(dmab); - return 0; -} - -#define SKL_ASTATE_PARAM_ID 4 - -void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data) -{ - struct skl_ipc_large_config_msg msg = {0}; - - msg.large_param_id = SKL_ASTATE_PARAM_ID; - msg.param_data_size = (cnt * sizeof(struct skl_astate_param) + - sizeof(cnt)); - - skl_ipc_set_large_config(&skl->ipc, &msg, data); -} - -static int skl_dsp_setup_spib(struct device *dev, unsigned int size, - int stream_tag, int enable) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - - if (!stream) - return -EINVAL; - - /* enable/disable SPIB for this hdac stream */ - snd_hdac_stream_spbcap_enable(bus, enable, stream->index); - - /* set the spib value */ - snd_hdac_stream_set_spib(bus, stream, size); - - return 0; -} - -static int skl_dsp_prepare(struct device *dev, unsigned int format, - unsigned int size, struct snd_dma_buffer *dmab) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_ext_stream *estream; - struct hdac_stream *stream; - struct snd_pcm_substream substream; - int ret; - - if (!bus) - return -ENODEV; - - memset(&substream, 0, sizeof(substream)); - substream.stream = SNDRV_PCM_STREAM_PLAYBACK; - - estream = snd_hdac_ext_stream_assign(bus, &substream, - HDAC_EXT_STREAM_TYPE_HOST); - if (!estream) - return -ENODEV; - - stream = hdac_stream(estream); - - /* assign decouple host dma channel */ - ret = snd_hdac_dsp_prepare(stream, format, size, dmab); - if (ret < 0) - return ret; - - skl_dsp_setup_spib(dev, size, stream->stream_tag, true); - - return stream->stream_tag; -} - -static int skl_dsp_trigger(struct device *dev, bool start, int stream_tag) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream; - - if (!bus) - return -ENODEV; - - stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - if (!stream) - return -EINVAL; - - snd_hdac_dsp_trigger(stream, start); - - return 0; -} - -static int skl_dsp_cleanup(struct device *dev, - struct snd_dma_buffer *dmab, int stream_tag) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct hdac_stream *stream; - struct hdac_ext_stream *estream; - - if (!bus) - return -ENODEV; - - stream = snd_hdac_get_stream(bus, - SNDRV_PCM_STREAM_PLAYBACK, stream_tag); - if (!stream) - return -EINVAL; - - estream = stream_to_hdac_ext_stream(stream); - skl_dsp_setup_spib(dev, 0, stream_tag, false); - snd_hdac_ext_stream_release(estream, HDAC_EXT_STREAM_TYPE_HOST); - - snd_hdac_dsp_cleanup(stream, dmab); - - return 0; -} - -static struct skl_dsp_loader_ops skl_get_loader_ops(void) -{ - struct skl_dsp_loader_ops loader_ops; - - memset(&loader_ops, 0, sizeof(struct skl_dsp_loader_ops)); - - loader_ops.alloc_dma_buf = skl_alloc_dma_buf; - loader_ops.free_dma_buf = skl_free_dma_buf; - - return loader_ops; -}; - -static struct skl_dsp_loader_ops bxt_get_loader_ops(void) -{ - struct skl_dsp_loader_ops loader_ops; - - memset(&loader_ops, 0, sizeof(loader_ops)); - - loader_ops.alloc_dma_buf = skl_alloc_dma_buf; - loader_ops.free_dma_buf = skl_free_dma_buf; - loader_ops.prepare = skl_dsp_prepare; - loader_ops.trigger = skl_dsp_trigger; - loader_ops.cleanup = skl_dsp_cleanup; - - return loader_ops; -}; - -static const struct skl_dsp_ops dsp_ops[] = { - { - .id = PCI_DEVICE_ID_INTEL_HDA_SKL_LP, - .num_cores = 2, - .loader_ops = skl_get_loader_ops, - .init = skl_sst_dsp_init, - .init_fw = skl_sst_init_fw, - .cleanup = skl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_KBL_LP, - .num_cores = 2, - .loader_ops = skl_get_loader_ops, - .init = skl_sst_dsp_init, - .init_fw = skl_sst_init_fw, - .cleanup = skl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_APL, - .num_cores = 2, - .loader_ops = bxt_get_loader_ops, - .init = bxt_sst_dsp_init, - .init_fw = bxt_sst_init_fw, - .cleanup = bxt_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_GML, - .num_cores = 2, - .loader_ops = bxt_get_loader_ops, - .init = bxt_sst_dsp_init, - .init_fw = bxt_sst_init_fw, - .cleanup = bxt_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CNL_LP, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CNL_H, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CML_LP, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, - { - .id = PCI_DEVICE_ID_INTEL_HDA_CML_H, - .num_cores = 4, - .loader_ops = bxt_get_loader_ops, - .init = cnl_sst_dsp_init, - .init_fw = cnl_sst_init_fw, - .cleanup = cnl_sst_dsp_cleanup - }, -}; - -const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dsp_ops); i++) { - if (dsp_ops[i].id == pci_id) - return &dsp_ops[i]; - } - - return NULL; -} - -int skl_init_dsp(struct skl_dev *skl) -{ - void __iomem *mmio_base; - struct hdac_bus *bus = skl_to_bus(skl); - struct skl_dsp_loader_ops loader_ops; - int irq = bus->irq; - const struct skl_dsp_ops *ops; - struct skl_dsp_cores *cores; - int ret; - - /* enable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_enable(bus, true); - snd_hdac_ext_bus_ppcap_int_enable(bus, true); - - /* read the BAR of the ADSP MMIO */ - mmio_base = pci_ioremap_bar(skl->pci, 4); - if (mmio_base == NULL) { - dev_err(bus->dev, "ioremap error\n"); - return -ENXIO; - } - - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) { - ret = -EIO; - goto unmap_mmio; - } - - loader_ops = ops->loader_ops(); - ret = ops->init(bus->dev, mmio_base, irq, - skl->fw_name, loader_ops, - &skl); - - if (ret < 0) - goto unmap_mmio; - - skl->dsp_ops = ops; - cores = &skl->cores; - cores->count = ops->num_cores; - - cores->state = kcalloc(cores->count, sizeof(*cores->state), GFP_KERNEL); - if (!cores->state) { - ret = -ENOMEM; - goto unmap_mmio; - } - - cores->usage_count = kcalloc(cores->count, sizeof(*cores->usage_count), - GFP_KERNEL); - if (!cores->usage_count) { - ret = -ENOMEM; - goto free_core_state; - } - - dev_dbg(bus->dev, "dsp registration status=%d\n", ret); - - return 0; - -free_core_state: - kfree(cores->state); - -unmap_mmio: - iounmap(mmio_base); - - return ret; -} - -int skl_free_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - - /* disable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_int_enable(bus, false); - - skl->dsp_ops->cleanup(bus->dev, skl); - - kfree(skl->cores.state); - kfree(skl->cores.usage_count); - - if (skl->dsp->addr.lpe) - iounmap(skl->dsp->addr.lpe); - - return 0; -} - -/* - * In the case of "suspend_active" i.e, the Audio IP being active - * during system suspend, immediately excecute any pending D0i3 work - * before suspending. This is needed for the IP to work in low power - * mode during system suspend. In the case of normal suspend, cancel - * any pending D0i3 work. - */ -int skl_suspend_late_dsp(struct skl_dev *skl) -{ - struct delayed_work *dwork; - - if (!skl) - return 0; - - dwork = &skl->d0i3.work; - - if (dwork->work.func) { - if (skl->supend_active) - flush_delayed_work(dwork); - else - cancel_delayed_work_sync(dwork); - } - - return 0; -} - -int skl_suspend_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - int ret; - - /* if ppcap is not supported return 0 */ - if (!bus->ppcap) - return 0; - - ret = skl_dsp_sleep(skl->dsp); - if (ret < 0) - return ret; - - /* disable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_int_enable(bus, false); - snd_hdac_ext_bus_ppcap_enable(bus, false); - - return 0; -} - -int skl_resume_dsp(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - int ret; - - /* if ppcap is not supported return 0 */ - if (!bus->ppcap) - return 0; - - /* enable ppcap interrupt */ - snd_hdac_ext_bus_ppcap_enable(bus, true); - snd_hdac_ext_bus_ppcap_int_enable(bus, true); - - /* check if DSP 1st boot is done */ - if (skl->is_first_boot) - return 0; - - /* - * Disable dynamic clock and power gating during firmware - * and library download - */ - skl->enable_miscbdcge(skl->dev, false); - skl->clock_power_gating(skl->dev, false); - - ret = skl_dsp_wake(skl->dsp); - skl->enable_miscbdcge(skl->dev, true); - skl->clock_power_gating(skl->dev, true); - if (ret < 0) - return ret; - - if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl, skl->cfg.astate_cfg->count, - skl->cfg.astate_cfg); - } - return ret; -} - -enum skl_bitdepth skl_get_bit_depth(int params) -{ - switch (params) { - case 8: - return SKL_DEPTH_8BIT; - - case 16: - return SKL_DEPTH_16BIT; - - case 24: - return SKL_DEPTH_24BIT; - - case 32: - return SKL_DEPTH_32BIT; - - default: - return SKL_DEPTH_INVALID; - - } -} - -/* - * Each module in DSP expects a base module configuration, which consists of - * PCM format information, which we calculate in driver and resource values - * which are read from widget information passed through topology binary - * This is send when we create a module with INIT_INSTANCE IPC msg - */ -static void skl_set_base_module_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_cfg *base_cfg) -{ - struct skl_module *module = mconfig->module; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *format = &fmt->inputs[0].fmt; - - base_cfg->audio_fmt.number_of_channels = format->channels; - - base_cfg->audio_fmt.s_freq = format->s_freq; - base_cfg->audio_fmt.bit_depth = format->bit_depth; - base_cfg->audio_fmt.valid_bit_depth = format->valid_bit_depth; - base_cfg->audio_fmt.ch_cfg = format->ch_cfg; - base_cfg->audio_fmt.sample_type = format->sample_type; - - dev_dbg(skl->dev, "bit_depth=%x valid_bd=%x ch_config=%x\n", - format->bit_depth, format->valid_bit_depth, - format->ch_cfg); - - base_cfg->audio_fmt.channel_map = format->ch_map; - - base_cfg->audio_fmt.interleaving = format->interleaving_style; - - base_cfg->cpc = res->cpc; - base_cfg->ibs = res->ibs; - base_cfg->obs = res->obs; - base_cfg->is_pages = res->is_pages; -} - -static void fill_pin_params(struct skl_audio_data_format *pin_fmt, - struct skl_module_fmt *format) -{ - pin_fmt->number_of_channels = format->channels; - pin_fmt->s_freq = format->s_freq; - pin_fmt->bit_depth = format->bit_depth; - pin_fmt->valid_bit_depth = format->valid_bit_depth; - pin_fmt->ch_cfg = format->ch_cfg; - pin_fmt->sample_type = format->sample_type; - pin_fmt->channel_map = format->ch_map; - pin_fmt->interleaving = format->interleaving_style; -} - -/* - * Any module configuration begins with a base module configuration but - * can be followed by a generic extension containing audio format for all - * module's pins that are in use. - */ -static void skl_set_base_ext_module_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_cfg_ext *base_cfg_ext) -{ - struct skl_module *module = mconfig->module; - struct skl_module_pin_resources *pin_res; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_res *res = &module->resources[mconfig->res_idx]; - struct skl_module_fmt *format; - struct skl_pin_format *pin_fmt; - char *params; - int i; - - base_cfg_ext->nr_input_pins = res->nr_input_pins; - base_cfg_ext->nr_output_pins = res->nr_output_pins; - base_cfg_ext->priv_param_length = - mconfig->formats_config[SKL_PARAM_INIT].caps_size; - - for (i = 0; i < res->nr_input_pins; i++) { - pin_res = &res->input[i]; - pin_fmt = &base_cfg_ext->pins_fmt[i]; - - pin_fmt->pin_idx = pin_res->pin_index; - pin_fmt->buf_size = pin_res->buf_size; - - format = &fmt->inputs[pin_res->pin_index].fmt; - fill_pin_params(&pin_fmt->audio_fmt, format); - } - - for (i = 0; i < res->nr_output_pins; i++) { - pin_res = &res->output[i]; - pin_fmt = &base_cfg_ext->pins_fmt[res->nr_input_pins + i]; - - pin_fmt->pin_idx = pin_res->pin_index; - pin_fmt->buf_size = pin_res->buf_size; - - format = &fmt->outputs[pin_res->pin_index].fmt; - fill_pin_params(&pin_fmt->audio_fmt, format); - } - - if (!base_cfg_ext->priv_param_length) - return; - - params = (char *)base_cfg_ext + sizeof(struct skl_base_cfg_ext); - params += (base_cfg_ext->nr_input_pins + base_cfg_ext->nr_output_pins) * - sizeof(struct skl_pin_format); - - memcpy(params, mconfig->formats_config[SKL_PARAM_INIT].caps, - mconfig->formats_config[SKL_PARAM_INIT].caps_size); -} - -/* - * Copies copier capabilities into copier module and updates copier module - * config size. - */ -static void skl_copy_copier_caps(struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - if (mconfig->formats_config[SKL_PARAM_INIT].caps_size == 0) - return; - - memcpy(&cpr_mconfig->gtw_cfg.config_data, - mconfig->formats_config[SKL_PARAM_INIT].caps, - mconfig->formats_config[SKL_PARAM_INIT].caps_size); - - cpr_mconfig->gtw_cfg.config_length = - (mconfig->formats_config[SKL_PARAM_INIT].caps_size) / 4; -} - -#define SKL_NON_GATEWAY_CPR_NODE_ID 0xFFFFFFFF -/* - * Calculate the gatewat settings required for copier module, type of - * gateway and index of gateway to use - */ -static u32 skl_get_node_id(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - union skl_connector_node_id node_id = {0}; - union skl_ssp_dma_node ssp_node = {0}; - struct skl_pipe_params *params = mconfig->pipe->p_params; - - switch (mconfig->dev_type) { - case SKL_DEVICE_BT: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_I2S_LINK_OUTPUT_CLASS : - SKL_DMA_I2S_LINK_INPUT_CLASS; - node_id.node.vindex = params->host_dma_id + - (mconfig->vbus_id << 3); - break; - - case SKL_DEVICE_I2S: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_I2S_LINK_OUTPUT_CLASS : - SKL_DMA_I2S_LINK_INPUT_CLASS; - ssp_node.dma_node.time_slot_index = mconfig->time_slot; - ssp_node.dma_node.i2s_instance = mconfig->vbus_id; - node_id.node.vindex = ssp_node.val; - break; - - case SKL_DEVICE_DMIC: - node_id.node.dma_type = SKL_DMA_DMIC_LINK_INPUT_CLASS; - node_id.node.vindex = mconfig->vbus_id + - (mconfig->time_slot); - break; - - case SKL_DEVICE_HDALINK: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_HDA_LINK_OUTPUT_CLASS : - SKL_DMA_HDA_LINK_INPUT_CLASS; - node_id.node.vindex = params->link_dma_id; - break; - - case SKL_DEVICE_HDAHOST: - node_id.node.dma_type = - (SKL_CONN_SOURCE == mconfig->hw_conn_type) ? - SKL_DMA_HDA_HOST_OUTPUT_CLASS : - SKL_DMA_HDA_HOST_INPUT_CLASS; - node_id.node.vindex = params->host_dma_id; - break; - - default: - node_id.val = 0xFFFFFFFF; - break; - } - - return node_id.val; -} - -static void skl_setup_cpr_gateway_cfg(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - u32 dma_io_buf; - struct skl_module_res *res; - int res_idx = mconfig->res_idx; - - cpr_mconfig->gtw_cfg.node_id = skl_get_node_id(skl, mconfig); - - if (cpr_mconfig->gtw_cfg.node_id == SKL_NON_GATEWAY_CPR_NODE_ID) { - cpr_mconfig->cpr_feature_mask = 0; - return; - } - - if (skl->nr_modules) { - res = &mconfig->module->resources[mconfig->res_idx]; - cpr_mconfig->gtw_cfg.dma_buffer_size = res->dma_buffer_size; - goto skip_buf_size_calc; - } else { - res = &mconfig->module->resources[res_idx]; - } - - switch (mconfig->hw_conn_type) { - case SKL_CONN_SOURCE: - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - dma_io_buf = res->ibs; - else - dma_io_buf = res->obs; - break; - - case SKL_CONN_SINK: - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - dma_io_buf = res->obs; - else - dma_io_buf = res->ibs; - break; - - default: - dev_warn(skl->dev, "wrong connection type: %d\n", - mconfig->hw_conn_type); - return; - } - - cpr_mconfig->gtw_cfg.dma_buffer_size = - mconfig->dma_buffer_size * dma_io_buf; - - /* fallback to 2ms default value */ - if (!cpr_mconfig->gtw_cfg.dma_buffer_size) { - if (mconfig->hw_conn_type == SKL_CONN_SOURCE) - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->obs; - else - cpr_mconfig->gtw_cfg.dma_buffer_size = 2 * res->ibs; - } - -skip_buf_size_calc: - cpr_mconfig->cpr_feature_mask = 0; - cpr_mconfig->gtw_cfg.config_length = 0; - - skl_copy_copier_caps(mconfig, cpr_mconfig); -} - -#define DMA_CONTROL_ID 5 -#define DMA_I2S_BLOB_SIZE 21 - -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id) -{ - struct skl_dma_control *dma_ctrl; - struct skl_ipc_large_config_msg msg = {0}; - int err = 0; - - - /* - * if blob size zero, then return - */ - if (caps_size == 0) - return 0; - - msg.large_param_id = DMA_CONTROL_ID; - msg.param_data_size = sizeof(struct skl_dma_control) + caps_size; - - dma_ctrl = kzalloc(msg.param_data_size, GFP_KERNEL); - if (dma_ctrl == NULL) - return -ENOMEM; - - dma_ctrl->node_id = node_id; - - /* - * NHLT blob may contain additional configs along with i2s blob. - * firmware expects only the i2s blob size as the config_length. - * So fix to i2s blob size. - * size in dwords. - */ - dma_ctrl->config_length = DMA_I2S_BLOB_SIZE; - - memcpy(dma_ctrl->config_data, caps, caps_size); - - err = skl_ipc_set_large_config(&skl->ipc, &msg, (u32 *)dma_ctrl); - - kfree(dma_ctrl); - return err; -} -EXPORT_SYMBOL_GPL(skl_dsp_set_dma_control); - -static void skl_setup_out_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_audio_data_format *out_fmt) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *fmt = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *format = &fmt->outputs[0].fmt; - - out_fmt->number_of_channels = (u8)format->channels; - out_fmt->s_freq = format->s_freq; - out_fmt->bit_depth = format->bit_depth; - out_fmt->valid_bit_depth = format->valid_bit_depth; - out_fmt->ch_cfg = format->ch_cfg; - - out_fmt->channel_map = format->ch_map; - out_fmt->interleaving = format->interleaving_style; - out_fmt->sample_type = format->sample_type; - - dev_dbg(skl->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", - out_fmt->number_of_channels, format->s_freq, format->bit_depth); -} - -/* - * DSP needs SRC module for frequency conversion, SRC takes base module - * configuration and the target frequency as extra parameter passed as src - * config - */ -static void skl_set_src_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_src_module_cfg *src_mconfig) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - - skl_set_base_module_format(skl, mconfig, - (struct skl_base_cfg *)src_mconfig); - - src_mconfig->src_cfg = fmt->s_freq; -} - -/* - * DSP needs updown module to do channel conversion. updown module take base - * module configuration and channel configuration - * It also take coefficients and now we have defaults applied here - */ -static void skl_set_updown_mixer_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_up_down_mixer_cfg *mixer_mconfig) -{ - struct skl_module *module = mconfig->module; - struct skl_module_iface *iface = &module->formats[mconfig->fmt_idx]; - struct skl_module_fmt *fmt = &iface->outputs[0].fmt; - - skl_set_base_module_format(skl, mconfig, - (struct skl_base_cfg *)mixer_mconfig); - mixer_mconfig->out_ch_cfg = fmt->ch_cfg; - mixer_mconfig->ch_map = fmt->ch_map; -} - -/* - * 'copier' is DSP internal module which copies data from Host DMA (HDA host - * dma) or link (hda link, SSP, PDM) - * Here we calculate the copier module parameters, like PCM format, output - * format, gateway settings - * copier_module_config is sent as input buffer with INIT_INSTANCE IPC msg - */ -static void skl_set_copier_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_cpr_cfg *cpr_mconfig) -{ - struct skl_audio_data_format *out_fmt = &cpr_mconfig->out_fmt; - struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)cpr_mconfig; - - skl_set_base_module_format(skl, mconfig, base_cfg); - - skl_setup_out_format(skl, mconfig, out_fmt); - skl_setup_cpr_gateway_cfg(skl, mconfig, cpr_mconfig); -} - -/* - * Mic select module allows selecting one or many input channels, thus - * acting as a demux. - * - * Mic select module take base module configuration and out-format - * configuration - */ -static void skl_set_base_outfmt_format(struct skl_dev *skl, - struct skl_module_cfg *mconfig, - struct skl_base_outfmt_cfg *base_outfmt_mcfg) -{ - struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; - struct skl_base_cfg *base_cfg = - (struct skl_base_cfg *)base_outfmt_mcfg; - - skl_set_base_module_format(skl, mconfig, base_cfg); - skl_setup_out_format(skl, mconfig, out_fmt); -} - -static u16 skl_get_module_param_size(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_module_res *res; - struct skl_module *module = mconfig->module; - u16 param_size; - - switch (mconfig->m_type) { - case SKL_MODULE_TYPE_COPIER: - param_size = sizeof(struct skl_cpr_cfg); - param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; - return param_size; - - case SKL_MODULE_TYPE_SRCINT: - return sizeof(struct skl_src_module_cfg); - - case SKL_MODULE_TYPE_UPDWMIX: - return sizeof(struct skl_up_down_mixer_cfg); - - case SKL_MODULE_TYPE_BASE_OUTFMT: - case SKL_MODULE_TYPE_MIC_SELECT: - return sizeof(struct skl_base_outfmt_cfg); - - case SKL_MODULE_TYPE_MIXER: - case SKL_MODULE_TYPE_KPB: - return sizeof(struct skl_base_cfg); - - case SKL_MODULE_TYPE_ALGO: - default: - res = &module->resources[mconfig->res_idx]; - - param_size = sizeof(struct skl_base_cfg) + sizeof(struct skl_base_cfg_ext); - param_size += (res->nr_input_pins + res->nr_output_pins) * - sizeof(struct skl_pin_format); - param_size += mconfig->formats_config[SKL_PARAM_INIT].caps_size; - - return param_size; - } - - return 0; -} - -/* - * DSP firmware supports various modules like copier, SRC, updown etc. - * These modules required various parameters to be calculated and sent for - * the module initialization to DSP. By default a generic module needs only - * base module format configuration - */ - -static int skl_set_module_format(struct skl_dev *skl, - struct skl_module_cfg *module_config, - u16 *module_config_size, - void **param_data) -{ - u16 param_size; - - param_size = skl_get_module_param_size(skl, module_config); - - *param_data = kzalloc(param_size, GFP_KERNEL); - if (NULL == *param_data) - return -ENOMEM; - - *module_config_size = param_size; - - switch (module_config->m_type) { - case SKL_MODULE_TYPE_COPIER: - skl_set_copier_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_SRCINT: - skl_set_src_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_UPDWMIX: - skl_set_updown_mixer_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_BASE_OUTFMT: - case SKL_MODULE_TYPE_MIC_SELECT: - skl_set_base_outfmt_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_MIXER: - case SKL_MODULE_TYPE_KPB: - skl_set_base_module_format(skl, module_config, *param_data); - break; - - case SKL_MODULE_TYPE_ALGO: - default: - skl_set_base_module_format(skl, module_config, *param_data); - skl_set_base_ext_module_format(skl, module_config, - *param_data + - sizeof(struct skl_base_cfg)); - break; - } - - dev_dbg(skl->dev, "Module type=%d id=%d config size: %d bytes\n", - module_config->m_type, module_config->id.module_id, - param_size); - print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, - *param_data, param_size, false); - return 0; -} - -static int skl_get_queue_index(struct skl_module_pin *mpin, - struct skl_module_inst_id id, int max) -{ - int i; - - for (i = 0; i < max; i++) { - if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id) - return i; - } - - return -EINVAL; -} - -/* - * Allocates queue for each module. - * if dynamic, the pin_index is allocated 0 to max_pin. - * In static, the pin_index is fixed based on module_id and instance id - */ -static int skl_alloc_queue(struct skl_module_pin *mpin, - struct skl_module_cfg *tgt_cfg, int max) -{ - int i; - struct skl_module_inst_id id = tgt_cfg->id; - /* - * if pin in dynamic, find first free pin - * otherwise find match module and instance id pin as topology will - * ensure a unique pin is assigned to this so no need to - * allocate/free - */ - for (i = 0; i < max; i++) { - if (mpin[i].is_dynamic) { - if (!mpin[i].in_use && - mpin[i].pin_state == SKL_PIN_UNBIND) { - - mpin[i].in_use = true; - mpin[i].id.module_id = id.module_id; - mpin[i].id.instance_id = id.instance_id; - mpin[i].id.pvt_id = id.pvt_id; - mpin[i].tgt_mcfg = tgt_cfg; - return i; - } - } else { - if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id && - mpin[i].pin_state == SKL_PIN_UNBIND) { - - mpin[i].tgt_mcfg = tgt_cfg; - return i; - } - } - } - - return -EINVAL; -} - -static void skl_free_queue(struct skl_module_pin *mpin, int q_index) -{ - if (mpin[q_index].is_dynamic) { - mpin[q_index].in_use = false; - mpin[q_index].id.module_id = 0; - mpin[q_index].id.instance_id = 0; - mpin[q_index].id.pvt_id = 0; - } - mpin[q_index].pin_state = SKL_PIN_UNBIND; - mpin[q_index].tgt_mcfg = NULL; -} - -/* Module state will be set to unint, if all the out pin state is UNBIND */ - -static void skl_clear_module_state(struct skl_module_pin *mpin, int max, - struct skl_module_cfg *mcfg) -{ - int i; - bool found = false; - - for (i = 0; i < max; i++) { - if (mpin[i].pin_state == SKL_PIN_UNBIND) - continue; - found = true; - break; - } - - if (!found) - mcfg->m_state = SKL_MODULE_INIT_DONE; - return; -} - -/* - * A module needs to be instanataited in DSP. A mdoule is present in a - * collection of module referred as a PIPE. - * We first calculate the module format, based on module type and then - * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper - */ -int skl_init_module(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - u16 module_config_size = 0; - void *param_data = NULL; - int ret; - struct skl_ipc_init_instance_msg msg; - - dev_dbg(skl->dev, "%s: module_id = %d instance=%d\n", __func__, - mconfig->id.module_id, mconfig->id.pvt_id); - - if (mconfig->pipe->state != SKL_PIPE_CREATED) { - dev_err(skl->dev, "Pipe not created state= %d pipe_id= %d\n", - mconfig->pipe->state, mconfig->pipe->ppl_id); - return -EIO; - } - - ret = skl_set_module_format(skl, mconfig, - &module_config_size, ¶m_data); - if (ret < 0) { - dev_err(skl->dev, "Failed to set module format ret=%d\n", ret); - return ret; - } - - msg.module_id = mconfig->id.module_id; - msg.instance_id = mconfig->id.pvt_id; - msg.ppl_instance_id = mconfig->pipe->ppl_id; - msg.param_data_size = module_config_size; - msg.core_id = mconfig->core_id; - msg.domain = mconfig->domain; - - ret = skl_ipc_init_instance(&skl->ipc, &msg, param_data); - if (ret < 0) { - dev_err(skl->dev, "Failed to init instance ret=%d\n", ret); - kfree(param_data); - return ret; - } - mconfig->m_state = SKL_MODULE_INIT_DONE; - kfree(param_data); - return ret; -} - -static void skl_dump_bind_info(struct skl_dev *skl, struct skl_module_cfg - *src_module, struct skl_module_cfg *dst_module) -{ - dev_dbg(skl->dev, "%s: src module_id = %d src_instance=%d\n", - __func__, src_module->id.module_id, src_module->id.pvt_id); - dev_dbg(skl->dev, "%s: dst_module=%d dst_instance=%d\n", __func__, - dst_module->id.module_id, dst_module->id.pvt_id); - - dev_dbg(skl->dev, "src_module state = %d dst module state = %d\n", - src_module->m_state, dst_module->m_state); -} - -/* - * On module freeup, we need to unbind the module with modules - * it is already bind. - * Find the pin allocated and unbind then using bind_unbind IPC - */ -int skl_unbind_modules(struct skl_dev *skl, - struct skl_module_cfg *src_mcfg, - struct skl_module_cfg *dst_mcfg) -{ - int ret; - struct skl_ipc_bind_unbind_msg msg; - struct skl_module_inst_id src_id = src_mcfg->id; - struct skl_module_inst_id dst_id = dst_mcfg->id; - int in_max = dst_mcfg->module->max_input_pins; - int out_max = src_mcfg->module->max_output_pins; - int src_index, dst_index, src_pin_state, dst_pin_state; - - skl_dump_bind_info(skl, src_mcfg, dst_mcfg); - - /* get src queue index */ - src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); - if (src_index < 0) - return 0; - - msg.src_queue = src_index; - - /* get dst queue index */ - dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); - if (dst_index < 0) - return 0; - - msg.dst_queue = dst_index; - - src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; - dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; - - if (src_pin_state != SKL_PIN_BIND_DONE || - dst_pin_state != SKL_PIN_BIND_DONE) - return 0; - - msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.pvt_id; - msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.pvt_id; - msg.bind = false; - - ret = skl_ipc_bind_unbind(&skl->ipc, &msg); - if (!ret) { - /* free queue only if unbind is success */ - skl_free_queue(src_mcfg->m_out_pin, src_index); - skl_free_queue(dst_mcfg->m_in_pin, dst_index); - - /* - * check only if src module bind state, bind is - * always from src -> sink - */ - skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); - } - - return ret; -} - -#define CPR_SINK_FMT_PARAM_ID 2 - -/* - * Once a module is instantiated it need to be 'bind' with other modules in - * the pipeline. For binding we need to find the module pins which are bind - * together - * This function finds the pins and then sends bund_unbind IPC message to - * DSP using IPC helper - */ -int skl_bind_modules(struct skl_dev *skl, - struct skl_module_cfg *src_mcfg, - struct skl_module_cfg *dst_mcfg) -{ - int ret = 0; - struct skl_ipc_bind_unbind_msg msg; - int in_max = dst_mcfg->module->max_input_pins; - int out_max = src_mcfg->module->max_output_pins; - int src_index, dst_index; - struct skl_module_fmt *format; - struct skl_cpr_pin_fmt pin_fmt; - struct skl_module *module; - struct skl_module_iface *fmt; - - skl_dump_bind_info(skl, src_mcfg, dst_mcfg); - - if (src_mcfg->m_state < SKL_MODULE_INIT_DONE || - dst_mcfg->m_state < SKL_MODULE_INIT_DONE) - return 0; - - src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); - if (src_index < 0) - return -EINVAL; - - msg.src_queue = src_index; - dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); - if (dst_index < 0) { - skl_free_queue(src_mcfg->m_out_pin, src_index); - return -EINVAL; - } - - /* - * Copier module requires the separate large_config_set_ipc to - * configure the pins other than 0 - */ - if (src_mcfg->m_type == SKL_MODULE_TYPE_COPIER && src_index > 0) { - pin_fmt.sink_id = src_index; - module = src_mcfg->module; - fmt = &module->formats[src_mcfg->fmt_idx]; - - /* Input fmt is same as that of src module input cfg */ - format = &fmt->inputs[0].fmt; - fill_pin_params(&(pin_fmt.src_fmt), format); - - format = &fmt->outputs[src_index].fmt; - fill_pin_params(&(pin_fmt.dst_fmt), format); - ret = skl_set_module_params(skl, (void *)&pin_fmt, - sizeof(struct skl_cpr_pin_fmt), - CPR_SINK_FMT_PARAM_ID, src_mcfg); - - if (ret < 0) - goto out; - } - - msg.dst_queue = dst_index; - - dev_dbg(skl->dev, "src queue = %d dst queue =%d\n", - msg.src_queue, msg.dst_queue); - - msg.module_id = src_mcfg->id.module_id; - msg.instance_id = src_mcfg->id.pvt_id; - msg.dst_module_id = dst_mcfg->id.module_id; - msg.dst_instance_id = dst_mcfg->id.pvt_id; - msg.bind = true; - - ret = skl_ipc_bind_unbind(&skl->ipc, &msg); - - if (!ret) { - src_mcfg->m_state = SKL_MODULE_BIND_DONE; - src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; - dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; - return ret; - } -out: - /* error case , if IPC fails, clear the queue index */ - skl_free_queue(src_mcfg->m_out_pin, src_index); - skl_free_queue(dst_mcfg->m_in_pin, dst_index); - - return ret; -} - -static int skl_set_pipe_state(struct skl_dev *skl, struct skl_pipe *pipe, - enum skl_ipc_pipeline_state state) -{ - dev_dbg(skl->dev, "%s: pipe_state = %d\n", __func__, state); - - return skl_ipc_set_pipeline_state(&skl->ipc, pipe->ppl_id, state); -} - -/* - * A pipeline is a collection of modules. Before a module in instantiated a - * pipeline needs to be created for it. - * This function creates pipeline, by sending create pipeline IPC messages - * to FW - */ -int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); - - ret = skl_ipc_create_pipeline(&skl->ipc, pipe->memory_pages, - pipe->pipe_priority, pipe->ppl_id, - pipe->lp_mode); - if (ret < 0) { - dev_err(skl->dev, "Failed to create pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_CREATED; - - return 0; -} - -/* - * A pipeline needs to be deleted on cleanup. If a pipeline is running, - * then pause it first. Before actual deletion, pipeline should enter - * reset state. Finish the procedure by sending delete pipeline IPC. - * DSP will stop the DMA engines and release resources - */ -int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to delete it */ - if (pipe->state < SKL_PIPE_CREATED) - return 0; - - /* If pipe is started, do stop the pipe in FW. */ - if (pipe->state >= SKL_PIPE_STARTED) { - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_err(skl->dev, "Failed to stop pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - } - - /* reset pipe state before deletion */ - ret = skl_set_pipe_state(skl, pipe, PPL_RESET); - if (ret < 0) { - dev_err(skl->dev, "Failed to reset pipe ret=%d\n", ret); - return ret; - } - - pipe->state = SKL_PIPE_RESET; - - ret = skl_ipc_delete_pipeline(&skl->ipc, pipe->ppl_id); - if (ret < 0) { - dev_err(skl->dev, "Failed to delete pipeline\n"); - return ret; - } - - pipe->state = SKL_PIPE_INVALID; - - return ret; -} - -/* - * A pipeline is also a scheduling entity in DSP which can be run, stopped - * For processing data the pipe need to be run by sending IPC set pipe state - * to DSP - */ -int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_CREATED) - return 0; - - /* Pipe has to be paused before it is started */ - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_err(skl->dev, "Failed to pause pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - - ret = skl_set_pipe_state(skl, pipe, PPL_RUNNING); - if (ret < 0) { - dev_err(skl->dev, "Failed to start pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_STARTED; - - return 0; -} - -/* - * Stop the pipeline by sending set pipe state IPC - * DSP doesnt implement stop so we always send pause message - */ -int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - dev_dbg(skl->dev, "In %s pipe=%d\n", __func__, pipe->ppl_id); - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_PAUSED) - return 0; - - ret = skl_set_pipe_state(skl, pipe, PPL_PAUSED); - if (ret < 0) { - dev_dbg(skl->dev, "Failed to stop pipe\n"); - return ret; - } - - pipe->state = SKL_PIPE_PAUSED; - - return 0; -} - -/* - * Reset the pipeline by sending set pipe state IPC this will reset the DMA - * from the DSP side - */ -int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe) -{ - int ret; - - /* If pipe was not created in FW, do not try to pause or delete */ - if (pipe->state < SKL_PIPE_PAUSED) - return 0; - - ret = skl_set_pipe_state(skl, pipe, PPL_RESET); - if (ret < 0) { - dev_dbg(skl->dev, "Failed to reset pipe ret=%d\n", ret); - return ret; - } - - pipe->state = SKL_PIPE_RESET; - - return 0; -} - -/* Algo parameter set helper function */ -int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg) -{ - struct skl_ipc_large_config_msg msg; - - msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.pvt_id; - msg.param_data_size = size; - msg.large_param_id = param_id; - - return skl_ipc_set_large_config(&skl->ipc, &msg, params); -} - -int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg) -{ - struct skl_ipc_large_config_msg msg; - size_t bytes = size; - - msg.module_id = mcfg->id.module_id; - msg.instance_id = mcfg->id.pvt_id; - msg.param_data_size = size; - msg.large_param_id = param_id; - - return skl_ipc_get_large_config(&skl->ipc, &msg, ¶ms, &bytes); -} diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c deleted file mode 100644 index e617b4c335a4..000000000000 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ /dev/null @@ -1,269 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-nhlt.c - Intel SKL Platform NHLT parsing - * - * Copyright (C) 2015 Intel Corp - * Author: Sanjiv Kumar <sanjiv.kumar@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <linux/pci.h> -#include <sound/intel-nhlt.h> -#include "skl.h" -#include "skl-i2s.h" - -static void skl_nhlt_trim_space(char *trim) -{ - char *s = trim; - int cnt; - int i; - - cnt = 0; - for (i = 0; s[i]; i++) { - if (!isspace(s[i])) - s[cnt++] = s[i]; - } - - s[cnt] = '\0'; -} - -int skl_nhlt_update_topology_bin(struct skl_dev *skl) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct hdac_bus *bus = skl_to_bus(skl); - struct device *dev = bus->dev; - - dev_dbg(dev, "oem_id %.6s, oem_table_id %.8s oem_revision %d\n", - nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision); - - snprintf(skl->tplg_name, sizeof(skl->tplg_name), "%x-%.6s-%.8s-%d%s", - skl->pci_id, nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision, "-tplg.bin"); - - skl_nhlt_trim_space(skl->tplg_name); - - return 0; -} - -static ssize_t platform_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - char platform_id[32]; - - sprintf(platform_id, "%x-%.6s-%.8s-%d", skl->pci_id, - nhlt->header.oem_id, nhlt->header.oem_table_id, - nhlt->header.oem_revision); - - skl_nhlt_trim_space(platform_id); - return sysfs_emit(buf, "%s\n", platform_id); -} - -static DEVICE_ATTR_RO(platform_id); - -int skl_nhlt_create_sysfs(struct skl_dev *skl) -{ - struct device *dev = &skl->pci->dev; - - if (sysfs_create_file(&dev->kobj, &dev_attr_platform_id.attr)) - dev_warn(dev, "Error creating sysfs entry\n"); - - return 0; -} - -void skl_nhlt_remove_sysfs(struct skl_dev *skl) -{ - struct device *dev = &skl->pci->dev; - - if (skl->nhlt) - sysfs_remove_file(&dev->kobj, &dev_attr_platform_id.attr); -} - -/* - * Queries NHLT for all the fmt configuration for a particular endpoint and - * stores all possible rates supported in a rate table for the corresponding - * sclk/sclkfs. - */ -static void skl_get_ssp_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks, - struct nhlt_fmt *fmt, u8 id) -{ - struct skl_i2s_config_blob_ext *i2s_config_ext; - struct skl_i2s_config_blob_legacy *i2s_config; - struct skl_clk_parent_src *parent; - struct skl_ssp_clk *sclk, *sclkfs; - struct nhlt_fmt_cfg *fmt_cfg; - struct wav_fmt_ext *wav_fmt; - unsigned long rate; - int rate_index = 0; - u16 channels, bps; - u8 clk_src; - int i, j; - u32 fs; - - sclk = &ssp_clks[SKL_SCLK_OFS]; - sclkfs = &ssp_clks[SKL_SCLKFS_OFS]; - - if (fmt->fmt_count == 0) - return; - - fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - for (i = 0; i < fmt->fmt_count; i++) { - struct nhlt_fmt_cfg *saved_fmt_cfg = fmt_cfg; - bool present = false; - - wav_fmt = &saved_fmt_cfg->fmt_ext; - - channels = wav_fmt->fmt.channels; - bps = wav_fmt->fmt.bits_per_sample; - fs = wav_fmt->fmt.samples_per_sec; - - /* - * In case of TDM configuration on a ssp, there can - * be more than one blob in which channel masks are - * different for each usecase for a specific rate and bps. - * But the sclk rate will be generated for the total - * number of channels used for that endpoint. - * - * So for the given fs and bps, choose blob which has - * the superset of all channels for that endpoint and - * derive the rate. - */ - for (j = i; j < fmt->fmt_count; j++) { - struct nhlt_fmt_cfg *tmp_fmt_cfg = fmt_cfg; - - wav_fmt = &tmp_fmt_cfg->fmt_ext; - if ((fs == wav_fmt->fmt.samples_per_sec) && - (bps == wav_fmt->fmt.bits_per_sample)) { - channels = max_t(u16, channels, - wav_fmt->fmt.channels); - saved_fmt_cfg = tmp_fmt_cfg; - } - /* Move to the next nhlt_fmt_cfg */ - tmp_fmt_cfg = (struct nhlt_fmt_cfg *)(tmp_fmt_cfg->config.caps + - tmp_fmt_cfg->config.size); - } - - rate = channels * bps * fs; - - /* check if the rate is added already to the given SSP's sclk */ - for (j = 0; (j < SKL_MAX_CLK_RATES) && - (sclk[id].rate_cfg[j].rate != 0); j++) { - if (sclk[id].rate_cfg[j].rate == rate) { - present = true; - break; - } - } - - /* Fill rate and parent for sclk/sclkfs */ - if (!present) { - struct nhlt_fmt_cfg *first_fmt_cfg; - - first_fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - i2s_config_ext = (struct skl_i2s_config_blob_ext *) - first_fmt_cfg->config.caps; - - /* MCLK Divider Source Select */ - if (is_legacy_blob(i2s_config_ext->hdr.sig)) { - i2s_config = ext_to_legacy_blob(i2s_config_ext); - clk_src = get_clk_src(i2s_config->mclk, - SKL_MNDSS_DIV_CLK_SRC_MASK); - } else { - clk_src = get_clk_src(i2s_config_ext->mclk, - SKL_MNDSS_DIV_CLK_SRC_MASK); - } - - parent = skl_get_parent_clk(clk_src); - - /* Move to the next nhlt_fmt_cfg */ - fmt_cfg = (struct nhlt_fmt_cfg *)(fmt_cfg->config.caps + - fmt_cfg->config.size); - /* - * Do not copy the config data if there is no parent - * clock available for this clock source select - */ - if (!parent) - continue; - - sclk[id].rate_cfg[rate_index].rate = rate; - sclk[id].rate_cfg[rate_index].config = saved_fmt_cfg; - sclkfs[id].rate_cfg[rate_index].rate = rate; - sclkfs[id].rate_cfg[rate_index].config = saved_fmt_cfg; - sclk[id].parent_name = parent->name; - sclkfs[id].parent_name = parent->name; - - rate_index++; - } - } -} - -static void skl_get_mclk(struct skl_dev *skl, struct skl_ssp_clk *mclk, - struct nhlt_fmt *fmt, u8 id) -{ - struct skl_i2s_config_blob_ext *i2s_config_ext; - struct skl_i2s_config_blob_legacy *i2s_config; - struct nhlt_fmt_cfg *fmt_cfg; - struct skl_clk_parent_src *parent; - u32 clkdiv, div_ratio; - u8 clk_src; - - fmt_cfg = (struct nhlt_fmt_cfg *)fmt->fmt_config; - i2s_config_ext = (struct skl_i2s_config_blob_ext *)fmt_cfg->config.caps; - - /* MCLK Divider Source Select and divider */ - if (is_legacy_blob(i2s_config_ext->hdr.sig)) { - i2s_config = ext_to_legacy_blob(i2s_config_ext); - clk_src = get_clk_src(i2s_config->mclk, - SKL_MCLK_DIV_CLK_SRC_MASK); - clkdiv = i2s_config->mclk.mdivr & - SKL_MCLK_DIV_RATIO_MASK; - } else { - clk_src = get_clk_src(i2s_config_ext->mclk, - SKL_MCLK_DIV_CLK_SRC_MASK); - clkdiv = i2s_config_ext->mclk.mdivr[0] & - SKL_MCLK_DIV_RATIO_MASK; - } - - /* bypass divider */ - div_ratio = 1; - - if (clkdiv != SKL_MCLK_DIV_RATIO_MASK) - /* Divider is 2 + clkdiv */ - div_ratio = clkdiv + 2; - - /* Calculate MCLK rate from source using div value */ - parent = skl_get_parent_clk(clk_src); - if (!parent) - return; - - mclk[id].rate_cfg[0].rate = parent->rate/div_ratio; - mclk[id].rate_cfg[0].config = fmt_cfg; - mclk[id].parent_name = parent->name; -} - -void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks) -{ - struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - struct nhlt_endpoint *epnt; - struct nhlt_fmt *fmt; - int i; - u8 id; - - epnt = (struct nhlt_endpoint *)nhlt->desc; - for (i = 0; i < nhlt->endpoint_count; i++) { - if (epnt->linktype == NHLT_LINK_SSP) { - id = epnt->virtual_bus_id; - - fmt = (struct nhlt_fmt *)(epnt->config.caps - + epnt->config.size); - - skl_get_ssp_clks(skl, ssp_clks, fmt, id); - skl_get_mclk(skl, ssp_clks, fmt, id); - } - epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); - } -} diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c deleted file mode 100644 index 613b27b8da13..000000000000 --- a/sound/soc/intel/skylake/skl-pcm.c +++ /dev/null @@ -1,1507 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/pci.h> -#include <linux/pm_runtime.h> -#include <linux/delay.h> -#include <sound/hdaudio.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include "skl.h" -#include "skl-topology.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" - -#define HDA_MONO 1 -#define HDA_STEREO 2 -#define HDA_QUAD 4 -#define HDA_MAX 8 - -static const struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_RESUME | - SNDRV_PCM_INFO_SYNC_START | - SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ - SNDRV_PCM_INFO_HAS_LINK_ATIME | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .rate_min = 8000, - .rate_max = 48000, - .channels_min = 1, - .channels_max = 8, - .buffer_bytes_max = AZX_MAX_BUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = AZX_MAX_BUF_SIZE / 2, - .periods_min = 2, - .periods_max = AZX_MAX_FRAG, - .fifo_size = 0, -}; - -static inline -struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) -{ - return substream->runtime->private_data; -} - -static struct hdac_bus *get_bus_ctx(struct snd_pcm_substream *substream) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_stream *hstream = hdac_stream(stream); - struct hdac_bus *bus = hstream->bus; - return bus; -} - -static int skl_substream_alloc_pages(struct hdac_bus *bus, - struct snd_pcm_substream *substream, - size_t size) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - - hdac_stream(stream)->bufsize = 0; - hdac_stream(stream)->period_bytes = 0; - hdac_stream(stream)->format_val = 0; - - return 0; -} - -static void skl_set_pcm_constrains(struct hdac_bus *bus, - struct snd_pcm_runtime *runtime) -{ - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - - /* avoid wrap-around with wall-clock */ - snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, - 20, 178000000); -} - -static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_bus *bus) -{ - if (bus->ppcap) - return HDAC_EXT_STREAM_TYPE_HOST; - else - return HDAC_EXT_STREAM_TYPE_COUPLED; -} - -/* - * check if the stream opened is marked as ignore_suspend by machine, if so - * then enable suspend_active refcount - * - * The count supend_active does not need lock as it is used in open/close - * and suspend context - */ -static void skl_set_suspend_active(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai, bool enable) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_soc_dapm_widget *w; - struct skl_dev *skl = bus_to_skl(bus); - - w = snd_soc_dai_get_widget(dai, substream->stream); - - if (w->ignore_suspend && enable) - skl->supend_active++; - else if (w->ignore_suspend && !enable) - skl->supend_active--; -} - -int skl_pcm_host_dma_prepare(struct device *dev, struct skl_pipe_params *params) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - unsigned int format_val; - struct hdac_stream *hstream; - struct hdac_ext_stream *stream; - unsigned int bits; - int err; - - hstream = snd_hdac_get_stream(bus, params->stream, - params->host_dma_id + 1); - if (!hstream) - return -EINVAL; - - stream = stream_to_hdac_ext_stream(hstream); - snd_hdac_ext_stream_decouple(bus, stream, true); - - bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, - params->host_bps); - format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); - - dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", - format_val, params->s_freq, params->ch, params->format); - - snd_hdac_stream_reset(hdac_stream(stream)); - err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); - if (err < 0) - return err; - - err = snd_hdac_ext_host_stream_setup(stream, false); - if (err < 0) - return err; - - hdac_stream(stream)->prepared = 1; - - return 0; -} - -int skl_pcm_link_dma_prepare(struct device *dev, struct skl_pipe_params *params) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - unsigned int format_val; - struct hdac_stream *hstream; - struct hdac_ext_stream *stream; - struct hdac_ext_link *link; - unsigned char stream_tag; - unsigned int bits; - - hstream = snd_hdac_get_stream(bus, params->stream, - params->link_dma_id + 1); - if (!hstream) - return -EINVAL; - - stream = stream_to_hdac_ext_stream(hstream); - snd_hdac_ext_stream_decouple(bus, stream, true); - - bits = snd_hdac_stream_format_bits(params->format, SNDRV_PCM_SUBFORMAT_STD, - params->link_bps); - format_val = snd_hdac_stream_format(params->ch, bits, params->s_freq); - - dev_dbg(dev, "format_val=%d, rate=%d, ch=%d, format=%d\n", - format_val, params->s_freq, params->ch, params->format); - - snd_hdac_ext_stream_reset(stream); - - snd_hdac_ext_stream_setup(stream, format_val); - - stream_tag = hstream->stream_tag; - if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) { - list_for_each_entry(link, &bus->hlink_list, list) { - if (link->index == params->link_index) - snd_hdac_ext_bus_link_set_stream_id(link, - stream_tag); - } - } - - stream->link_prepared = 1; - - return 0; -} - -static int skl_pcm_open(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *stream; - struct snd_pcm_runtime *runtime = substream->runtime; - struct skl_dma_params *dma_params; - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - stream = snd_hdac_ext_stream_assign(bus, substream, - skl_get_host_stream_type(bus)); - if (stream == NULL) - return -EBUSY; - - skl_set_pcm_constrains(bus, runtime); - - /* - * disable WALLCLOCK timestamps for capture streams - * until we figure out how to handle digital inputs - */ - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { - runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ - runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; - } - - runtime->private_data = stream; - - dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); - if (!dma_params) - return -ENOMEM; - - dma_params->stream_tag = hdac_stream(stream)->stream_tag; - snd_soc_dai_set_dma_data(dai, substream, dma_params); - - dev_dbg(dai->dev, "stream tag set in dma params=%d\n", - dma_params->stream_tag); - skl_set_suspend_active(substream, dai, true); - snd_pcm_set_sync(substream); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (!mconfig) { - kfree(dma_params); - return -EINVAL; - } - - skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); - - return 0; -} - -static int skl_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - int ret; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - - /* - * In case of XRUN recovery or in the case when the application - * calls prepare another time, reset the FW pipe to clean state - */ - if (mconfig && - (substream->runtime->state == SNDRV_PCM_STATE_XRUN || - mconfig->pipe->state == SKL_PIPE_CREATED || - mconfig->pipe->state == SKL_PIPE_PAUSED)) { - - ret = skl_reset_pipe(skl, mconfig->pipe); - - if (ret < 0) - return ret; - - ret = skl_pcm_host_dma_prepare(dai->dev, - mconfig->pipe->p_params); - if (ret < 0) - return ret; - } - - return 0; -} - -static int skl_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct skl_pipe_params p_params = {0}; - struct skl_module_cfg *m_cfg; - int ret, dma_id; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - ret = skl_substream_alloc_pages(bus, substream, - params_buffer_bytes(params)); - if (ret < 0) - return ret; - - dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - - dma_id = hdac_stream(stream)->stream_tag - 1; - dev_dbg(dai->dev, "dma_id=%d\n", dma_id); - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.host_dma_id = dma_id; - p_params.stream = substream->stream; - p_params.format = params_format(params); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - p_params.host_bps = dai->driver->playback.sig_bits; - else - p_params.host_bps = dai->driver->capture.sig_bits; - - - m_cfg = skl_tplg_fe_get_cpr_module(dai, p_params.stream); - if (m_cfg) - skl_tplg_update_pipe_params(dai->dev, m_cfg, &p_params); - - return 0; -} - -static void skl_pcm_close(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct skl_dma_params *dma_params = NULL; - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_cfg *mconfig; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(bus)); - - dma_params = snd_soc_dai_get_dma_data(dai, substream); - /* - * now we should set this to NULL as we are freeing by the - * dma_params - */ - snd_soc_dai_set_dma_data(dai, substream, NULL); - skl_set_suspend_active(substream, dai, false); - - /* - * check if close is for "Reference Pin" and set back the - * CGCTL.MISCBDCGE if disabled by driver - */ - if (!strncmp(dai->name, "Reference Pin", 13) && - skl->miscbdcg_disabled) { - skl->enable_miscbdcge(dai->dev, true); - skl->miscbdcg_disabled = false; - } - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (mconfig) - skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); - - kfree(dma_params); -} - -static int skl_pcm_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - int ret; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - - if (mconfig) { - ret = skl_reset_pipe(skl, mconfig->pipe); - if (ret < 0) - dev_err(dai->dev, "%s:Reset failed ret =%d", - __func__, ret); - } - - snd_hdac_stream_cleanup(hdac_stream(stream)); - hdac_stream(stream)->prepared = 0; - - return 0; -} - -static int skl_be_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct skl_pipe_params p_params = {0}; - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.stream = substream->stream; - - return skl_tplg_be_update_params(dai, &p_params); -} - -static int skl_decoupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream; - int start; - unsigned long cookie; - struct hdac_stream *hstr; - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = 1; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = 0; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - if (start) { - snd_hdac_stream_start(hdac_stream(stream)); - snd_hdac_stream_timecounter_init(hstr, 0); - } else { - snd_hdac_stream_stop(hdac_stream(stream)); - } - - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} - -static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig; - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - struct hdac_stream *hstream = hdac_stream(stream); - struct snd_soc_dapm_widget *w; - int ret; - - mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); - if (!mconfig) - return -EIO; - - w = snd_soc_dai_get_widget(dai, substream->stream); - - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - if (!w->ignore_suspend) { - /* - * enable DMA Resume enable bit for the stream, set the - * dpib & lpib position to resume before starting the - * DMA - */ - snd_hdac_stream_drsm_enable(bus, true, hstream->index); - snd_hdac_stream_set_dpibr(bus, hstream, hstream->lpib); - snd_hdac_stream_set_lpib(hstream, hstream->lpib); - } - fallthrough; - - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - /* - * Start HOST DMA and Start FE Pipe.This is to make sure that - * there are no underrun/overrun in the case when the FE - * pipeline is started but there is a delay in starting the - * DMA channel on the host. - */ - ret = skl_decoupled_trigger(substream, cmd); - if (ret < 0) - return ret; - return skl_run_pipe(skl, mconfig->pipe); - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - /* - * Stop FE Pipe first and stop DMA. This is to make sure that - * there are no underrun/overrun in the case if there is a delay - * between the two operations. - */ - ret = skl_stop_pipe(skl, mconfig->pipe); - if (ret < 0) - return ret; - - ret = skl_decoupled_trigger(substream, cmd); - if (ret < 0) - return ret; - - if ((cmd == SNDRV_PCM_TRIGGER_SUSPEND) && !w->ignore_suspend) { - /* save the dpib and lpib positions */ - hstream->dpib = readl(bus->remap_addr + - AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hstream->index)); - - hstream->lpib = snd_hdac_stream_get_pos_lpib(hstream); - - snd_hdac_ext_stream_decouple(bus, stream, false); - } - break; - - default: - return -EINVAL; - } - - return 0; -} - - -static int skl_link_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct hdac_ext_stream *link_dev; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - struct skl_pipe_params p_params = {0}; - struct hdac_ext_link *link; - int stream_tag; - - link_dev = snd_hdac_ext_stream_assign(bus, substream, - HDAC_EXT_STREAM_TYPE_LINK); - if (!link_dev) - return -EBUSY; - - snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); - - link = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name); - if (!link) - return -EINVAL; - - stream_tag = hdac_stream(link_dev)->stream_tag; - - /* set the hdac_stream in the codec dai */ - snd_soc_dai_set_stream(codec_dai, hdac_stream(link_dev), substream->stream); - - p_params.s_fmt = snd_pcm_format_width(params_format(params)); - p_params.s_cont = snd_pcm_format_physical_width(params_format(params)); - p_params.ch = params_channels(params); - p_params.s_freq = params_rate(params); - p_params.stream = substream->stream; - p_params.link_dma_id = stream_tag - 1; - p_params.link_index = link->index; - p_params.format = params_format(params); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - p_params.link_bps = codec_dai->driver->playback.sig_bits; - else - p_params.link_bps = codec_dai->driver->capture.sig_bits; - - return skl_tplg_be_update_params(dai, &p_params); -} - -static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct skl_dev *skl = get_skl_ctx(dai->dev); - struct skl_module_cfg *mconfig = NULL; - - /* In case of XRUN recovery, reset the FW pipe to clean state */ - mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); - if (mconfig && !mconfig->pipe->passthru && - (substream->runtime->state == SNDRV_PCM_STATE_XRUN)) - skl_reset_pipe(skl, mconfig->pipe); - - return 0; -} - -static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); - - dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); - switch (cmd) { - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_hdac_ext_stream_start(link_dev); - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - snd_hdac_ext_stream_clear(link_dev); - if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) - snd_hdac_ext_stream_decouple(bus, stream, false); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int skl_link_hw_free(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct hdac_ext_stream *link_dev = - snd_soc_dai_get_dma_data(dai, substream); - struct hdac_ext_link *link; - unsigned char stream_tag; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - - link_dev->link_prepared = 0; - - link = snd_hdac_ext_bus_get_hlink_by_name(bus, snd_soc_rtd_to_codec(rtd, 0)->component->name); - if (!link) - return -EINVAL; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - stream_tag = hdac_stream(link_dev)->stream_tag; - snd_hdac_ext_bus_link_clear_stream_id(link, stream_tag); - } - - snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); - return 0; -} - -static const struct snd_soc_dai_ops skl_pcm_dai_ops = { - .startup = skl_pcm_open, - .shutdown = skl_pcm_close, - .prepare = skl_pcm_prepare, - .hw_params = skl_pcm_hw_params, - .hw_free = skl_pcm_hw_free, - .trigger = skl_pcm_trigger, -}; - -static const struct snd_soc_dai_ops skl_dmic_dai_ops = { - .hw_params = skl_be_hw_params, -}; - -static const struct snd_soc_dai_ops skl_be_ssp_dai_ops = { - .hw_params = skl_be_hw_params, -}; - -static const struct snd_soc_dai_ops skl_link_dai_ops = { - .prepare = skl_link_pcm_prepare, - .hw_params = skl_link_hw_params, - .hw_free = skl_link_hw_free, - .trigger = skl_link_pcm_trigger, -}; - -static struct snd_soc_dai_driver skl_fe_dai[] = { -{ - .name = "System Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "System Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, - .capture = { - .stream_name = "System Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "System Pin2", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Headset Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Echoref Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "Echoreference Capture", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | - SNDRV_PCM_RATE_8000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Reference Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "Reference Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "Deepbuffer Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Deepbuffer Playback", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "LowLatency Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "Low Latency Playback", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "DMIC Pin", - .ops = &skl_pcm_dai_ops, - .capture = { - .stream_name = "DMIC Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI1 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI1 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI2 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI2 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -{ - .name = "HDMI3 Pin", - .ops = &skl_pcm_dai_ops, - .playback = { - .stream_name = "HDMI3 Playback", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | - SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | - SNDRV_PCM_RATE_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - .sig_bits = 32, - }, -}, -}; - -/* BE CPU Dais */ -static struct snd_soc_dai_driver skl_platform_dai[] = { -{ - .name = "SSP0 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp0 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp0 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP1 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp1 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp1 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP2 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp2 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp2 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP3 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp3 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp3 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP4 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp4 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp4 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "SSP5 Pin", - .ops = &skl_be_ssp_dai_ops, - .playback = { - .stream_name = "ssp5 Tx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, - .capture = { - .stream_name = "ssp5 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "iDisp1 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp1 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "iDisp2 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp2 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| - SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "iDisp3 Pin", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "iDisp3 Tx", - .channels_min = HDA_STEREO, - .channels_max = 8, - .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000| - SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE | - SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "DMIC01 Pin", - .ops = &skl_dmic_dai_ops, - .capture = { - .stream_name = "DMIC01 Rx", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, - }, -}, -{ - .name = "DMIC16k Pin", - .ops = &skl_dmic_dai_ops, - .capture = { - .stream_name = "DMIC16k Rx", - .channels_min = HDA_MONO, - .channels_max = HDA_QUAD, - .rates = SNDRV_PCM_RATE_16000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, - }, -}, -{ - .name = "Analog CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Analog CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Analog CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Alt Analog CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Alt Analog CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Alt Analog CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -{ - .name = "Digital CPU DAI", - .ops = &skl_link_dai_ops, - .playback = { - .stream_name = "Digital CPU Playback", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, - .capture = { - .stream_name = "Digital CPU Capture", - .channels_min = HDA_MONO, - .channels_max = HDA_MAX, - .rates = SNDRV_PCM_RATE_8000_192000, - .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | - SNDRV_PCM_FMTBIT_S32_LE, - }, -}, -}; - -int skl_dai_load(struct snd_soc_component *cmp, int index, - struct snd_soc_dai_driver *dai_drv, - struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai) -{ - dai_drv->ops = &skl_pcm_dai_ops; - - return 0; -} - -static int skl_platform_soc_open(struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai_link *dai_link = rtd->dai_link; - - dev_dbg(snd_soc_rtd_to_cpu(rtd, 0)->dev, "In %s:%s\n", __func__, - dai_link->cpus->dai_name); - - snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); - - return 0; -} - -static int skl_coupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - struct hdac_ext_stream *stream; - struct snd_pcm_substream *s; - bool start; - int sbits = 0; - unsigned long cookie; - struct hdac_stream *hstr; - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = true; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = false; - break; - - default: - return -EINVAL; - } - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - stream = get_hdac_ext_stream(s); - sbits |= 1 << hdac_stream(stream)->index; - snd_pcm_trigger_done(s, substream); - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - /* first, set SYNC bits of corresponding streams */ - snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - stream = get_hdac_ext_stream(s); - if (start) - snd_hdac_stream_start(hdac_stream(stream)); - else - snd_hdac_stream_stop(hdac_stream(stream)); - } - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - snd_hdac_stream_sync(hstr, start, sbits); - - spin_lock_irqsave(&bus->reg_lock, cookie); - - /* reset SYNC bits */ - snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); - if (start) - snd_hdac_stream_timecounter_init(hstr, sbits); - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} - -static int skl_platform_soc_trigger(struct snd_soc_component *component, - struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_bus *bus = get_bus_ctx(substream); - - if (!bus->ppcap) - return skl_coupled_trigger(substream, cmd); - - return 0; -} - -static snd_pcm_uframes_t skl_platform_soc_pointer( - struct snd_soc_component *component, - struct snd_pcm_substream *substream) -{ - struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); - struct hdac_bus *bus = get_bus_ctx(substream); - unsigned int pos; - - /* - * Use DPIB for Playback stream as the periodic DMA Position-in- - * Buffer Writes may be scheduled at the same time or later than - * the MSI and does not guarantee to reflect the Position of the - * last buffer that was transferred. Whereas DPIB register in - * HAD space reflects the actual data that is transferred. - * Use the position buffer for capture, as DPIB write gets - * completed earlier than the actual data written to the DDR. - * - * For capture stream following workaround is required to fix the - * incorrect position reporting. - * - * 1. Wait for 20us before reading the DMA position in buffer once - * the interrupt is generated for stream completion as update happens - * on the HDA frame boundary i.e. 20.833uSec. - * 2. Read DPIB register to flush the DMA position value. This dummy - * read is required to flush DMA position value. - * 3. Read the DMA Position-in-Buffer. This value now will be equal to - * or greater than period boundary. - */ - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - pos = readl(bus->remap_addr + AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hdac_stream(hstream)->index)); - } else { - udelay(20); - readl(bus->remap_addr + - AZX_REG_VS_SDXDPIB_XBASE + - (AZX_REG_VS_SDXDPIB_XINTERVAL * - hdac_stream(hstream)->index)); - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); - } - - if (pos >= hdac_stream(hstream)->bufsize) - pos = 0; - - return bytes_to_frames(substream->runtime, pos); -} - -static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, - u64 nsec) -{ - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); - u64 codec_frames, codec_nsecs; - - if (!codec_dai->driver->ops->delay) - return nsec; - - codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); - codec_nsecs = div_u64(codec_frames * 1000000000LL, - substream->runtime->rate); - - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - return nsec + codec_nsecs; - - return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; -} - -static int skl_platform_soc_get_time_info( - struct snd_soc_component *component, - struct snd_pcm_substream *substream, - struct timespec64 *system_ts, struct timespec64 *audio_ts, - struct snd_pcm_audio_tstamp_config *audio_tstamp_config, - struct snd_pcm_audio_tstamp_report *audio_tstamp_report) -{ - struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); - struct hdac_stream *hstr = hdac_stream(sstream); - u64 nsec; - - if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && - (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { - - snd_pcm_gettime(substream->runtime, system_ts); - - nsec = timecounter_read(&hstr->tc); - if (audio_tstamp_config->report_delay) - nsec = skl_adjust_codec_delay(substream, nsec); - - *audio_ts = ns_to_timespec64(nsec); - - audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; - audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ - audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ - - } else { - audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; - } - - return 0; -} - -#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) - -static int skl_platform_soc_new(struct snd_soc_component *component, - struct snd_soc_pcm_runtime *rtd) -{ - struct snd_soc_dai *dai = snd_soc_rtd_to_cpu(rtd, 0); - struct hdac_bus *bus = dev_get_drvdata(dai->dev); - struct snd_pcm *pcm = rtd->pcm; - unsigned int size; - struct skl_dev *skl = bus_to_skl(bus); - - if (dai->driver->playback.channels_min || - dai->driver->capture.channels_min) { - /* buffer pre-allocation */ - size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; - if (size > MAX_PREALLOC_SIZE) - size = MAX_PREALLOC_SIZE; - snd_pcm_set_managed_buffer_all(pcm, - SNDRV_DMA_TYPE_DEV_SG, - &skl->pci->dev, - size, MAX_PREALLOC_SIZE); - } - - return 0; -} - -static int skl_get_module_info(struct skl_dev *skl, - struct skl_module_cfg *mconfig) -{ - struct skl_module_inst_id *pin_id; - guid_t *uuid_mod, *uuid_tplg; - struct skl_module *skl_module; - struct uuid_module *module; - int i, ret = -EIO; - - uuid_mod = (guid_t *)mconfig->guid; - - if (list_empty(&skl->uuid_list)) { - dev_err(skl->dev, "Module list is empty\n"); - return -EIO; - } - - for (i = 0; i < skl->nr_modules; i++) { - skl_module = skl->modules[i]; - uuid_tplg = &skl_module->uuid; - if (guid_equal(uuid_mod, uuid_tplg)) { - mconfig->module = skl_module; - ret = 0; - break; - } - } - - if (skl->nr_modules && ret) - return ret; - - ret = -EIO; - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - mconfig->id.module_id = module->id; - mconfig->module->loadable = module->is_loadable; - ret = 0; - } - - for (i = 0; i < MAX_IN_QUEUE; i++) { - pin_id = &mconfig->m_in_pin[i].id; - if (guid_equal(&pin_id->mod_uuid, &module->uuid)) - pin_id->module_id = module->id; - } - - for (i = 0; i < MAX_OUT_QUEUE; i++) { - pin_id = &mconfig->m_out_pin[i].id; - if (guid_equal(&pin_id->mod_uuid, &module->uuid)) - pin_id->module_id = module->id; - } - } - - return ret; -} - -static int skl_populate_modules(struct skl_dev *skl) -{ - struct skl_pipeline *p; - struct skl_pipe_module *m; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - int ret = 0; - - list_for_each_entry(p, &skl->ppl_list, node) { - list_for_each_entry(m, &p->pipe->w_list, node) { - w = m->w; - mconfig = w->priv; - - ret = skl_get_module_info(skl, mconfig); - if (ret < 0) { - dev_err(skl->dev, - "query module info failed\n"); - return ret; - } - - skl_tplg_add_moduleid_in_bind_params(skl, w); - } - } - - return ret; -} - -static int skl_platform_soc_probe(struct snd_soc_component *component) -{ - struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl_dev *skl = bus_to_skl(bus); - const struct skl_dsp_ops *ops; - int ret; - - ret = pm_runtime_resume_and_get(component->dev); - if (ret < 0 && ret != -EACCES) - return ret; - - if (bus->ppcap) { - skl->component = component; - - /* init debugfs */ - skl->debugfs = skl_debugfs_init(skl); - - ret = skl_tplg_init(component, bus); - if (ret < 0) { - dev_err(component->dev, "Failed to init topology!\n"); - return ret; - } - - /* load the firmwares, since all is set */ - ops = skl_get_dsp_ops(skl->pci->device); - if (!ops) - return -EIO; - - /* - * Disable dynamic clock and power gating during firmware - * and library download - */ - skl->enable_miscbdcge(component->dev, false); - skl->clock_power_gating(component->dev, false); - - ret = ops->init_fw(component->dev, skl); - skl->enable_miscbdcge(component->dev, true); - skl->clock_power_gating(component->dev, true); - if (ret < 0) { - dev_err(component->dev, "Failed to boot first fw: %d\n", ret); - return ret; - } - skl_populate_modules(skl); - skl->update_d0i3c = skl_update_d0i3c; - - if (skl->cfg.astate_cfg != NULL) { - skl_dsp_set_astate_cfg(skl, - skl->cfg.astate_cfg->count, - skl->cfg.astate_cfg); - } - } - pm_runtime_mark_last_busy(component->dev); - pm_runtime_put_autosuspend(component->dev); - - return 0; -} - -static void skl_platform_soc_remove(struct snd_soc_component *component) -{ - struct hdac_bus *bus = dev_get_drvdata(component->dev); - struct skl_dev *skl = bus_to_skl(bus); - - skl_tplg_exit(component, bus); - - skl_debugfs_exit(skl); -} - -static const struct snd_soc_component_driver skl_component = { - .name = "pcm", - .probe = skl_platform_soc_probe, - .remove = skl_platform_soc_remove, - .open = skl_platform_soc_open, - .trigger = skl_platform_soc_trigger, - .pointer = skl_platform_soc_pointer, - .get_time_info = skl_platform_soc_get_time_info, - .pcm_construct = skl_platform_soc_new, - .module_get_upon_open = 1, /* increment refcount when a pcm is opened */ -}; - -int skl_platform_register(struct device *dev) -{ - int ret; - struct snd_soc_dai_driver *dais; - int num_dais = ARRAY_SIZE(skl_platform_dai); - struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl_dev *skl = bus_to_skl(bus); - - skl->dais = kmemdup(skl_platform_dai, sizeof(skl_platform_dai), - GFP_KERNEL); - if (!skl->dais) { - ret = -ENOMEM; - goto err; - } - - if (!skl->use_tplg_pcm) { - dais = krealloc(skl->dais, sizeof(skl_fe_dai) + - sizeof(skl_platform_dai), GFP_KERNEL); - if (!dais) { - kfree(skl->dais); - ret = -ENOMEM; - goto err; - } - - skl->dais = dais; - memcpy(&skl->dais[ARRAY_SIZE(skl_platform_dai)], skl_fe_dai, - sizeof(skl_fe_dai)); - num_dais += ARRAY_SIZE(skl_fe_dai); - } - - ret = devm_snd_soc_register_component(dev, &skl_component, - skl->dais, num_dais); - if (ret) { - kfree(skl->dais); - dev_err(dev, "soc component registration failed %d\n", ret); - } -err: - return ret; -} - -int skl_platform_unregister(struct device *dev) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_deferred_bind *modules, *tmp; - - list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { - list_del(&modules->node); - kfree(modules); - } - - kfree(skl->dais); - - return 0; -} diff --git a/sound/soc/intel/skylake/skl-ssp-clk.c b/sound/soc/intel/skylake/skl-ssp-clk.c deleted file mode 100644 index 50e93c3707e8..000000000000 --- a/sound/soc/intel/skylake/skl-ssp-clk.c +++ /dev/null @@ -1,428 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -// Copyright(c) 2015-17 Intel Corporation - -/* - * skl-ssp-clk.c - ASoC skylake ssp clock driver - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/err.h> -#include <linux/platform_device.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> -#include <sound/intel-nhlt.h> -#include "skl.h" -#include "skl-ssp-clk.h" -#include "skl-topology.h" - -#define to_skl_clk(_hw) container_of(_hw, struct skl_clk, hw) - -struct skl_clk_parent { - struct clk_hw *hw; - struct clk_lookup *lookup; -}; - -struct skl_clk { - struct clk_hw hw; - struct clk_lookup *lookup; - unsigned long rate; - struct skl_clk_pdata *pdata; - u32 id; -}; - -struct skl_clk_data { - struct skl_clk_parent parent[SKL_MAX_CLK_SRC]; - struct skl_clk *clk[SKL_MAX_CLK_CNT]; - u8 avail_clk_cnt; -}; - -static int skl_get_clk_type(u32 index) -{ - switch (index) { - case 0 ... (SKL_SCLK_OFS - 1): - return SKL_MCLK; - - case SKL_SCLK_OFS ... (SKL_SCLKFS_OFS - 1): - return SKL_SCLK; - - case SKL_SCLKFS_OFS ... (SKL_MAX_CLK_CNT - 1): - return SKL_SCLK_FS; - - default: - return -EINVAL; - } -} - -static int skl_get_vbus_id(u32 index, u8 clk_type) -{ - switch (clk_type) { - case SKL_MCLK: - return index; - - case SKL_SCLK: - return index - SKL_SCLK_OFS; - - case SKL_SCLK_FS: - return index - SKL_SCLKFS_OFS; - - default: - return -EINVAL; - } -} - -static void skl_fill_clk_ipc(struct skl_clk_rate_cfg_table *rcfg, u8 clk_type) -{ - struct nhlt_fmt_cfg *fmt_cfg; - union skl_clk_ctrl_ipc *ipc; - struct wav_fmt *wfmt; - - if (!rcfg) - return; - - ipc = &rcfg->dma_ctl_ipc; - if (clk_type == SKL_SCLK_FS) { - fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config; - wfmt = &fmt_cfg->fmt_ext.fmt; - - /* Remove TLV Header size */ - ipc->sclk_fs.hdr.size = sizeof(struct skl_dmactrl_sclkfs_cfg) - - sizeof(struct skl_tlv_hdr); - ipc->sclk_fs.sampling_frequency = wfmt->samples_per_sec; - ipc->sclk_fs.bit_depth = wfmt->bits_per_sample; - ipc->sclk_fs.valid_bit_depth = - fmt_cfg->fmt_ext.sample.valid_bits_per_sample; - ipc->sclk_fs.number_of_channels = wfmt->channels; - } else { - ipc->mclk.hdr.type = DMA_CLK_CONTROLS; - /* Remove TLV Header size */ - ipc->mclk.hdr.size = sizeof(struct skl_dmactrl_mclk_cfg) - - sizeof(struct skl_tlv_hdr); - } -} - -/* Sends dma control IPC to turn the clock ON/OFF */ -static int skl_send_clk_dma_control(struct skl_dev *skl, - struct skl_clk_rate_cfg_table *rcfg, - u32 vbus_id, u8 clk_type, - bool enable) -{ - struct nhlt_specific_cfg *sp_cfg; - u32 i2s_config_size, node_id = 0; - struct nhlt_fmt_cfg *fmt_cfg; - union skl_clk_ctrl_ipc *ipc; - void *i2s_config = NULL; - u8 *data, size; - int ret; - - if (!rcfg) - return -EIO; - - ipc = &rcfg->dma_ctl_ipc; - fmt_cfg = (struct nhlt_fmt_cfg *)rcfg->config; - sp_cfg = &fmt_cfg->config; - - if (clk_type == SKL_SCLK_FS) { - ipc->sclk_fs.hdr.type = - enable ? DMA_TRANSMITION_START : DMA_TRANSMITION_STOP; - data = (u8 *)&ipc->sclk_fs; - size = sizeof(struct skl_dmactrl_sclkfs_cfg); - } else { - /* 1 to enable mclk, 0 to enable sclk */ - if (clk_type == SKL_SCLK) - ipc->mclk.mclk = 0; - else - ipc->mclk.mclk = 1; - - ipc->mclk.keep_running = enable; - ipc->mclk.warm_up_over = enable; - ipc->mclk.clk_stop_over = !enable; - data = (u8 *)&ipc->mclk; - size = sizeof(struct skl_dmactrl_mclk_cfg); - } - - i2s_config_size = sp_cfg->size + size; - i2s_config = kzalloc(i2s_config_size, GFP_KERNEL); - if (!i2s_config) - return -ENOMEM; - - /* copy blob */ - memcpy(i2s_config, sp_cfg->caps, sp_cfg->size); - - /* copy additional dma controls information */ - memcpy(i2s_config + sp_cfg->size, data, size); - - node_id = ((SKL_DMA_I2S_LINK_INPUT_CLASS << 8) | (vbus_id << 4)); - ret = skl_dsp_set_dma_control(skl, (u32 *)i2s_config, - i2s_config_size, node_id); - kfree(i2s_config); - - return ret; -} - -static struct skl_clk_rate_cfg_table *skl_get_rate_cfg( - struct skl_clk_rate_cfg_table *rcfg, - unsigned long rate) -{ - int i; - - for (i = 0; (i < SKL_MAX_CLK_RATES) && rcfg[i].rate; i++) { - if (rcfg[i].rate == rate) - return &rcfg[i]; - } - - return NULL; -} - -static int skl_clk_change_status(struct skl_clk *clkdev, - bool enable) -{ - struct skl_clk_rate_cfg_table *rcfg; - int vbus_id, clk_type; - - clk_type = skl_get_clk_type(clkdev->id); - if (clk_type < 0) - return clk_type; - - vbus_id = skl_get_vbus_id(clkdev->id, clk_type); - if (vbus_id < 0) - return vbus_id; - - rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, - clkdev->rate); - if (!rcfg) - return -EINVAL; - - return skl_send_clk_dma_control(clkdev->pdata->pvt_data, rcfg, - vbus_id, clk_type, enable); -} - -static int skl_clk_prepare(struct clk_hw *hw) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - return skl_clk_change_status(clkdev, true); -} - -static void skl_clk_unprepare(struct clk_hw *hw) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - skl_clk_change_status(clkdev, false); -} - -static int skl_clk_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - struct skl_clk_rate_cfg_table *rcfg; - int clk_type; - - if (!rate) - return -EINVAL; - - rcfg = skl_get_rate_cfg(clkdev->pdata->ssp_clks[clkdev->id].rate_cfg, - rate); - if (!rcfg) - return -EINVAL; - - clk_type = skl_get_clk_type(clkdev->id); - if (clk_type < 0) - return clk_type; - - skl_fill_clk_ipc(rcfg, clk_type); - clkdev->rate = rate; - - return 0; -} - -static unsigned long skl_clk_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct skl_clk *clkdev = to_skl_clk(hw); - - if (clkdev->rate) - return clkdev->rate; - - return 0; -} - -/* Not supported by clk driver. Implemented to satisfy clk fw */ -static long skl_clk_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) -{ - return rate; -} - -/* - * prepare/unprepare are used instead of enable/disable as IPC will be sent - * in non-atomic context. - */ -static const struct clk_ops skl_clk_ops = { - .prepare = skl_clk_prepare, - .unprepare = skl_clk_unprepare, - .set_rate = skl_clk_set_rate, - .round_rate = skl_clk_round_rate, - .recalc_rate = skl_clk_recalc_rate, -}; - -static void unregister_parent_src_clk(struct skl_clk_parent *pclk, - unsigned int id) -{ - while (id--) { - clkdev_drop(pclk[id].lookup); - clk_hw_unregister_fixed_rate(pclk[id].hw); - } -} - -static void unregister_src_clk(struct skl_clk_data *dclk) -{ - while (dclk->avail_clk_cnt--) - clkdev_drop(dclk->clk[dclk->avail_clk_cnt]->lookup); -} - -static int skl_register_parent_clks(struct device *dev, - struct skl_clk_parent *parent, - struct skl_clk_parent_src *pclk) -{ - int i, ret; - - for (i = 0; i < SKL_MAX_CLK_SRC; i++) { - - /* Register Parent clock */ - parent[i].hw = clk_hw_register_fixed_rate(dev, pclk[i].name, - pclk[i].parent_name, 0, pclk[i].rate); - if (IS_ERR(parent[i].hw)) { - ret = PTR_ERR(parent[i].hw); - goto err; - } - - parent[i].lookup = clkdev_hw_create(parent[i].hw, pclk[i].name, - NULL); - if (!parent[i].lookup) { - clk_hw_unregister_fixed_rate(parent[i].hw); - ret = -ENOMEM; - goto err; - } - } - - return 0; -err: - unregister_parent_src_clk(parent, i); - return ret; -} - -/* Assign fmt_config to clk_data */ -static struct skl_clk *register_skl_clk(struct device *dev, - struct skl_ssp_clk *clk, - struct skl_clk_pdata *clk_pdata, int id) -{ - struct clk_init_data init; - struct skl_clk *clkdev; - int ret; - - clkdev = devm_kzalloc(dev, sizeof(*clkdev), GFP_KERNEL); - if (!clkdev) - return ERR_PTR(-ENOMEM); - - init.name = clk->name; - init.ops = &skl_clk_ops; - init.flags = CLK_SET_RATE_GATE; - init.parent_names = &clk->parent_name; - init.num_parents = 1; - clkdev->hw.init = &init; - clkdev->pdata = clk_pdata; - - clkdev->id = id; - ret = devm_clk_hw_register(dev, &clkdev->hw); - if (ret) { - clkdev = ERR_PTR(ret); - return clkdev; - } - - clkdev->lookup = clkdev_hw_create(&clkdev->hw, init.name, NULL); - if (!clkdev->lookup) - clkdev = ERR_PTR(-ENOMEM); - - return clkdev; -} - -static int skl_clk_dev_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct device *parent_dev = dev->parent; - struct skl_clk_parent_src *parent_clks; - struct skl_clk_pdata *clk_pdata; - struct skl_clk_data *data; - struct skl_ssp_clk *clks; - int ret, i; - - clk_pdata = dev_get_platdata(&pdev->dev); - parent_clks = clk_pdata->parent_clks; - clks = clk_pdata->ssp_clks; - if (!parent_clks || !clks) - return -EIO; - - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - /* Register Parent clock */ - ret = skl_register_parent_clks(parent_dev, data->parent, parent_clks); - if (ret < 0) - return ret; - - for (i = 0; i < clk_pdata->num_clks; i++) { - /* - * Only register valid clocks - * i.e. for which nhlt entry is present. - */ - if (clks[i].rate_cfg[0].rate == 0) - continue; - - data->clk[data->avail_clk_cnt] = register_skl_clk(dev, - &clks[i], clk_pdata, i); - - if (IS_ERR(data->clk[data->avail_clk_cnt])) { - ret = PTR_ERR(data->clk[data->avail_clk_cnt]); - goto err_unreg_skl_clk; - } - - data->avail_clk_cnt++; - } - - platform_set_drvdata(pdev, data); - - return 0; - -err_unreg_skl_clk: - unregister_src_clk(data); - unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); - - return ret; -} - -static void skl_clk_dev_remove(struct platform_device *pdev) -{ - struct skl_clk_data *data; - - data = platform_get_drvdata(pdev); - unregister_src_clk(data); - unregister_parent_src_clk(data->parent, SKL_MAX_CLK_SRC); -} - -static struct platform_driver skl_clk_driver = { - .driver = { - .name = "skl-ssp-clk", - }, - .probe = skl_clk_dev_probe, - .remove_new = skl_clk_dev_remove, -}; - -module_platform_driver(skl_clk_driver); - -MODULE_DESCRIPTION("Skylake clock driver"); -MODULE_AUTHOR("Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com>"); -MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:skl-ssp-clk"); diff --git a/sound/soc/intel/skylake/skl-ssp-clk.h b/sound/soc/intel/skylake/skl-ssp-clk.h deleted file mode 100644 index b7852c7f277b..000000000000 --- a/sound/soc/intel/skylake/skl-ssp-clk.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl-ssp-clk.h - Skylake ssp clock information and ipc structure - * - * Copyright (C) 2017 Intel Corp - * Author: Jaikrishna Nemallapudi <jaikrishnax.nemallapudi@intel.com> - * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef SOUND_SOC_SKL_SSP_CLK_H -#define SOUND_SOC_SKL_SSP_CLK_H - -#define SKL_MAX_SSP 6 -/* xtal/cardinal/pll, parent of ssp clocks and mclk */ -#define SKL_MAX_CLK_SRC 3 -#define SKL_MAX_SSP_CLK_TYPES 3 /* mclk, sclk, sclkfs */ - -#define SKL_MAX_CLK_CNT (SKL_MAX_SSP * SKL_MAX_SSP_CLK_TYPES) - -/* Max number of configurations supported for each clock */ -#define SKL_MAX_CLK_RATES 10 - -#define SKL_SCLK_OFS SKL_MAX_SSP -#define SKL_SCLKFS_OFS (SKL_SCLK_OFS + SKL_MAX_SSP) - -enum skl_clk_type { - SKL_MCLK, - SKL_SCLK, - SKL_SCLK_FS, -}; - -enum skl_clk_src_type { - SKL_XTAL, - SKL_CARDINAL, - SKL_PLL, -}; - -struct skl_clk_parent_src { - u8 clk_id; - const char *name; - unsigned long rate; - const char *parent_name; -}; - -struct skl_tlv_hdr { - u32 type; - u32 size; -}; - -struct skl_dmactrl_mclk_cfg { - struct skl_tlv_hdr hdr; - /* DMA Clk TLV params */ - u32 clk_warm_up:16; - u32 mclk:1; - u32 warm_up_over:1; - u32 rsvd0:14; - u32 clk_stop_delay:16; - u32 keep_running:1; - u32 clk_stop_over:1; - u32 rsvd1:14; -}; - -struct skl_dmactrl_sclkfs_cfg { - struct skl_tlv_hdr hdr; - /* DMA SClk&FS TLV params */ - u32 sampling_frequency; - u32 bit_depth; - u32 channel_map; - u32 channel_config; - u32 interleaving_style; - u32 number_of_channels : 8; - u32 valid_bit_depth : 8; - u32 sample_type : 8; - u32 reserved : 8; -}; - -union skl_clk_ctrl_ipc { - struct skl_dmactrl_mclk_cfg mclk; - struct skl_dmactrl_sclkfs_cfg sclk_fs; -}; - -struct skl_clk_rate_cfg_table { - unsigned long rate; - union skl_clk_ctrl_ipc dma_ctl_ipc; - void *config; -}; - -/* - * rate for mclk will be in rates[0]. For sclk and sclkfs, rates[] store - * all possible clocks ssp can generate for that platform. - */ -struct skl_ssp_clk { - const char *name; - const char *parent_name; - struct skl_clk_rate_cfg_table rate_cfg[SKL_MAX_CLK_RATES]; -}; - -struct skl_clk_pdata { - struct skl_clk_parent_src *parent_clks; - int num_clks; - struct skl_ssp_clk *ssp_clks; - void *pvt_data; -}; - -#endif /* SOUND_SOC_SKL_SSP_CLK_H */ diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c deleted file mode 100644 index b0204ea00f07..000000000000 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ /dev/null @@ -1,373 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-cldma.c - Code Loader DMA handler - * - * Copyright (C) 2015, Intel Corporation. - * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/device.h> -#include <linux/io.h> -#include <linux/mm.h> -#include <linux/delay.h> -#include <sound/hda_register.h> -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -static void skl_cldma_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); -} - -void skl_cldma_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); -} - -static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable) -{ - unsigned char val; - int timeout; - - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable)); - - udelay(3); - timeout = 300; - do { - /* waiting for hardware to report that the stream Run bit set */ - val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) & - CL_SD_CTL_RUN_MASK; - if (enable && val) - break; - else if (!enable && !val) - break; - udelay(3); - } while (--timeout); - - if (timeout == 0) - dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable); -} - -static void skl_cldma_stream_clear(struct sst_dsp *ctx) -{ - /* make sure Run bit is cleared before setting stream register */ - skl_cldma_stream_run(ctx, 0); - - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); -} - -/* Code loader helper APIs */ -static void skl_cldma_setup_bdle(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp, int size, int with_ioc) -{ - __le32 *bdl = *bdlp; - int remaining = ctx->cl_dev.bufsize; - int offset = 0; - - ctx->cl_dev.frags = 0; - while (remaining > 0) { - phys_addr_t addr; - int chunk; - - addr = snd_sgbuf_get_addr(dmab_data, offset); - bdl[0] = cpu_to_le32(lower_32_bits(addr)); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - chunk = snd_sgbuf_get_chunk_size(dmab_data, offset, size); - bdl[2] = cpu_to_le32(chunk); - - remaining -= chunk; - bdl[3] = (remaining > 0) ? 0 : cpu_to_le32(0x01); - - bdl += 4; - offset += chunk; - ctx->cl_dev.frags++; - } -} - -/* - * Setup controller - * Configure the registers to update the dma buffer address and - * enable interrupts. - * Note: Using the channel 1 for transfer - */ -static void skl_cldma_setup_controller(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_bdl, unsigned int max_size, - u32 count) -{ - skl_cldma_stream_clear(ctx); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, - CL_SD_BDLPLBA(dmab_bdl->addr)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, - CL_SD_BDLPUBA(dmab_bdl->addr)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); -} - -static void skl_cldma_setup_spb(struct sst_dsp *ctx, - unsigned int size, bool enable) -{ - if (enable) - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - CL_SPBFIFO_SPBFCCTL_SPIBE(1)); - - sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); -} - -static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, - CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, - CL_SPBFIFO_SPBFCCTL_SPIBE(0)); - - sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); -} - -static void skl_cldma_cleanup(struct sst_dsp *ctx) -{ - skl_cldma_cleanup_spb(ctx); - skl_cldma_stream_clear(ctx); - - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); -} - -int skl_cldma_wait_interruptible(struct sst_dsp *ctx) -{ - int ret = 0; - - if (!wait_event_timeout(ctx->cl_dev.wait_queue, - ctx->cl_dev.wait_condition, - msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { - dev_err(ctx->dev, "%s: Wait timeout\n", __func__); - ret = -EIO; - goto cleanup; - } - - dev_dbg(ctx->dev, "%s: Event wake\n", __func__); - if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { - dev_err(ctx->dev, "%s: DMA Error\n", __func__); - ret = -EIO; - } - -cleanup: - ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; - return ret; -} - -static void skl_cldma_stop(struct sst_dsp *ctx) -{ - skl_cldma_stream_run(ctx, false); -} - -static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, - const void *curr_pos, bool intr_enable, bool trigger) -{ - dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); - dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", - ctx->cl_dev.dma_buffer_offset, trigger); - dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); - - /* - * Check if the size exceeds buffer boundary. If it exceeds - * max_buffer size, then copy till buffer size and then copy - * remaining buffer from the start of ring buffer. - */ - if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) { - unsigned int size_b = ctx->cl_dev.bufsize - - ctx->cl_dev.dma_buffer_offset; - memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, - curr_pos, size_b); - size -= size_b; - curr_pos += size_b; - ctx->cl_dev.dma_buffer_offset = 0; - } - - memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, - curr_pos, size); - - if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) - ctx->cl_dev.dma_buffer_offset = 0; - else - ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; - - ctx->cl_dev.wait_condition = false; - - if (intr_enable) - skl_cldma_int_enable(ctx); - - ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); - if (trigger) - ctx->cl_dev.ops.cl_trigger(ctx, true); -} - -/* - * The CL dma doesn't have any way to update the transfer status until a BDL - * buffer is fully transferred - * - * So Copying is divided in two parts. - * 1. Interrupt on buffer done where the size to be transferred is more than - * ring buffer size. - * 2. Polling on fw register to identify if data left to transferred doesn't - * fill the ring buffer. Caller takes care of polling the required status - * register to identify the transfer status. - * 3. if wait flag is set, waits for DBL interrupt to copy the next chunk till - * bytes_left is 0. - * if wait flag is not set, doesn't wait for BDL interrupt. after ccopying - * the first chunk return the no of bytes_left to be copied. - */ -static int -skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, - u32 total_size, bool wait) -{ - int ret; - bool start = true; - unsigned int excess_bytes; - u32 size; - unsigned int bytes_left = total_size; - const void *curr_pos = bin; - - if (total_size <= 0) - return -EINVAL; - - dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); - - while (bytes_left) { - if (bytes_left > ctx->cl_dev.bufsize) { - - /* - * dma transfers only till the write pointer as - * updated in spib - */ - if (ctx->cl_dev.curr_spib_pos == 0) - ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; - - size = ctx->cl_dev.bufsize; - skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); - - if (wait) { - start = false; - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) { - skl_cldma_stop(ctx); - return ret; - } - } - } else { - skl_cldma_int_disable(ctx); - - if ((ctx->cl_dev.curr_spib_pos + bytes_left) - <= ctx->cl_dev.bufsize) { - ctx->cl_dev.curr_spib_pos += bytes_left; - } else { - excess_bytes = bytes_left - - (ctx->cl_dev.bufsize - - ctx->cl_dev.curr_spib_pos); - ctx->cl_dev.curr_spib_pos = excess_bytes; - } - - size = bytes_left; - skl_cldma_fill_buffer(ctx, size, - curr_pos, false, start); - } - bytes_left -= size; - curr_pos = curr_pos + size; - if (!wait) - return bytes_left; - } - - return bytes_left; -} - -void skl_cldma_process_intr(struct sst_dsp *ctx) -{ - u8 cl_dma_intr_status; - - cl_dma_intr_status = - sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); - - if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) - ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; - else - ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; - - ctx->cl_dev.wait_condition = true; - wake_up(&ctx->cl_dev.wait_queue); -} - -int skl_cldma_prepare(struct sst_dsp *ctx) -{ - int ret; - __le32 *bdl; - - ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; - - /* Allocate cl ops */ - ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; - ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; - ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; - ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; - ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run; - ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; - ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; - ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; - - /* Allocate buffer*/ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV_SG, ctx->dev, ctx->cl_dev.bufsize, - &ctx->cl_dev.dmab_data); - if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for base fw failed: %x\n", ret); - return ret; - } - - /* Setup Code loader BDL */ - ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, ctx->dev, BDL_SIZE, &ctx->cl_dev.dmab_bdl); - if (ret < 0) { - dev_err(ctx->dev, "Alloc buffer for blde failed: %x\n", ret); - ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); - return ret; - } - bdl = (__le32 *)ctx->cl_dev.dmab_bdl.area; - - /* Allocate BDLs */ - ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, - &bdl, ctx->cl_dev.bufsize, 1); - ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, - ctx->cl_dev.bufsize, ctx->cl_dev.frags); - - ctx->cl_dev.curr_spib_pos = 0; - ctx->cl_dev.dma_buffer_offset = 0; - init_waitqueue_head(&ctx->cl_dev.wait_queue); - - return ret; -} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h deleted file mode 100644 index d5e285a69baa..000000000000 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ /dev/null @@ -1,243 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel Code Loader DMA support - * - * Copyright (C) 2015, Intel Corporation. - */ - -#ifndef SKL_SST_CLDMA_H_ -#define SKL_SST_CLDMA_H_ - -#define FW_CL_STREAM_NUMBER 0x1 - -#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 -#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) - -#define SKL_ADSPIC_CL_DMA 0x2 -#define SKL_ADSPIS_CL_DMA 0x2 -#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ -#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ - -/* Intel HD Audio Code Loader DMA Registers */ - -#define HDA_ADSP_LOADER_BASE 0x80 - -/* Stream Registers */ -#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) -#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) -#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) -#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) -#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) -#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) -#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) -#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) -#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) -#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) -#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) - -/* CL: Software Position Based FIFO Capability Registers */ -#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) -#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) -#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) -#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) -#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) - -/* CL: Stream Descriptor x Control */ - -/* Stream Reset */ -#define CL_SD_CTL_SRST_SHIFT 0 -#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) -#define CL_SD_CTL_SRST(x) \ - ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) - -/* Stream Run */ -#define CL_SD_CTL_RUN_SHIFT 1 -#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) -#define CL_SD_CTL_RUN(x) \ - ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) - -/* Interrupt On Completion Enable */ -#define CL_SD_CTL_IOCE_SHIFT 2 -#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) -#define CL_SD_CTL_IOCE(x) \ - ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) - -/* FIFO Error Interrupt Enable */ -#define CL_SD_CTL_FEIE_SHIFT 3 -#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) -#define CL_SD_CTL_FEIE(x) \ - ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) - -/* Descriptor Error Interrupt Enable */ -#define CL_SD_CTL_DEIE_SHIFT 4 -#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) -#define CL_SD_CTL_DEIE(x) \ - ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) - -/* FIFO Limit Change */ -#define CL_SD_CTL_FIFOLC_SHIFT 5 -#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) -#define CL_SD_CTL_FIFOLC(x) \ - ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) - -/* Stripe Control */ -#define CL_SD_CTL_STRIPE_SHIFT 16 -#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) -#define CL_SD_CTL_STRIPE(x) \ - ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) - -/* Traffic Priority */ -#define CL_SD_CTL_TP_SHIFT 18 -#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) -#define CL_SD_CTL_TP(x) \ - ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) - -/* Bidirectional Direction Control */ -#define CL_SD_CTL_DIR_SHIFT 19 -#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) -#define CL_SD_CTL_DIR(x) \ - ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) - -/* Stream Number */ -#define CL_SD_CTL_STRM_SHIFT 20 -#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) -#define CL_SD_CTL_STRM(x) \ - ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) - -/* CL: Stream Descriptor x Status */ - -/* Buffer Completion Interrupt Status */ -#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) - -/* FIFO Error */ -#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) - -/* Descriptor Error */ -#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) - -/* FIFO Ready */ -#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) - - -/* CL: Stream Descriptor x Last Valid Index */ -#define CL_SD_LVI_SHIFT 0 -#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) -#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) - -/* CL: Stream Descriptor x FIFO Eviction Watermark */ -#define CL_SD_FIFOW_SHIFT 0 -#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) -#define CL_SD_FIFOW(x) \ - ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) - -/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ - -/* Protect Bits */ -#define CL_SD_BDLPLBA_PROT_SHIFT 0 -#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) -#define CL_SD_BDLPLBA_PROT(x) \ - ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) - -/* Buffer Descriptor List Lower Base Address */ -#define CL_SD_BDLPLBA_SHIFT 7 -#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) -#define CL_SD_BDLPLBA(x) \ - ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) - -/* Buffer Descriptor List Upper Base Address */ -#define CL_SD_BDLPUBA_SHIFT 0 -#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) -#define CL_SD_BDLPUBA(x) \ - ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) - -/* - * Code Loader - Software Position Based FIFO - * Capability Registers x Software Position Based FIFO Header - */ - -/* Next Capability Pointer */ -#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 -#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) -#define CL_SPBFIFO_SPBFCH_PTR(x) \ - ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) - -/* Capability Identifier */ -#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 -#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) -#define CL_SPBFIFO_SPBFCH_ID(x) \ - ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) - -/* Capability Version */ -#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 -#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) -#define CL_SPBFIFO_SPBFCH_VER(x) \ - ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) - -/* Software Position in Buffer Enable */ -#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 -#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) -#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ - ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) - -/* SST IPC SKL defines */ -#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ -#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) - -enum skl_cl_dma_wake_states { - SKL_CL_DMA_STATUS_NONE = 0, - SKL_CL_DMA_BUF_COMPLETE, - SKL_CL_DMA_ERR, /* TODO: Expand the error states */ -}; - -struct sst_dsp; - -struct skl_cl_dev_ops { - void (*cl_setup_bdle)(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_data, - __le32 **bdlp, int size, int with_ioc); - void (*cl_setup_controller)(struct sst_dsp *ctx, - struct snd_dma_buffer *dmab_bdl, - unsigned int max_size, u32 page_count); - void (*cl_setup_spb)(struct sst_dsp *ctx, - unsigned int size, bool enable); - void (*cl_cleanup_spb)(struct sst_dsp *ctx); - void (*cl_trigger)(struct sst_dsp *ctx, bool enable); - void (*cl_cleanup_controller)(struct sst_dsp *ctx); - int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, - const void *bin, u32 size, bool wait); - void (*cl_stop_dma)(struct sst_dsp *ctx); -}; - -/** - * skl_cl_dev - holds information for code loader dma transfer - * - * @dmab_data: buffer pointer - * @dmab_bdl: buffer descriptor list - * @bufsize: ring buffer size - * @frags: Last valid buffer descriptor index in the BDL - * @curr_spib_pos: Current position in ring buffer - * @dma_buffer_offset: dma buffer offset - * @ops: operations supported on CL dma - * @wait_queue: wait queue to wake for wake event - * @wake_status: DMA wake status - * @wait_condition: condition to wait on wait queue - * @cl_dma_lock: for synchronized access to cldma - */ -struct skl_cl_dev { - struct snd_dma_buffer dmab_data; - struct snd_dma_buffer dmab_bdl; - - unsigned int bufsize; - unsigned int frags; - - unsigned int curr_spib_pos; - unsigned int dma_buffer_offset; - struct skl_cl_dev_ops ops; - - wait_queue_head_t wait_queue; - int wake_status; - bool wait_condition; -}; - -#endif /* SKL_SST_CLDMA_H_ */ diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c deleted file mode 100644 index 4ae3eae0d1fd..000000000000 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ /dev/null @@ -1,462 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-dsp.c - SKL SST library generic function - * - * Copyright (C) 2014-15, Intel Corporation. - * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ -#include <sound/pcm.h> - -#include "../common/sst-dsp.h" -#include "../common/sst-ipc.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -/* various timeout values */ -#define SKL_DSP_PU_TO 50 -#define SKL_DSP_PD_TO 50 -#define SKL_DSP_RESET_TO 50 - -void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) -{ - mutex_lock(&ctx->mutex); - ctx->sst_state = state; - mutex_unlock(&ctx->mutex); -} - -/* - * Initialize core power state and usage count. To be called after - * successful first boot. Hence core 0 will be running and other cores - * will be reset - */ -void skl_dsp_init_core_state(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - int i; - - skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; - skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1; - - for (i = SKL_DSP_CORE0_ID + 1; i < skl->cores.count; i++) { - skl->cores.state[i] = SKL_DSP_RESET; - skl->cores.usage_count[i] = 0; - } -} - -/* Get the mask for all enabled cores */ -unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) -{ - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask, en_cores_mask; - u32 val; - - core_mask = SKL_DSP_CORES_MASK(skl->cores.count); - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); - - /* Cores having CPA bit set */ - en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >> - SKL_ADSPCS_CPA_SHIFT; - - /* And cores having CRST bit cleared */ - en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >> - SKL_ADSPCS_CRST_SHIFT; - - /* And cores having CSTALL bit cleared */ - en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >> - SKL_ADSPCS_CSTALL_SHIFT; - en_cores_mask &= core_mask; - - dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask); - - return en_cores_mask; -} - -static int -skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask), - SKL_ADSPCS_CRST_MASK(core_mask)); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), - SKL_ADSPCS_CRST_MASK(core_mask), - SKL_DSP_RESET_TO, - "Set reset"); - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CRST_MASK(core_mask)) != - SKL_ADSPCS_CRST_MASK(core_mask)) { - dev_err(ctx->dev, "Set reset state failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_unset_reset_state( - struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - dev_dbg(ctx->dev, "In %s\n", __func__); - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), 0); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CRST_MASK(core_mask), - 0, - SKL_DSP_RESET_TO, - "Unset reset"); - - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CRST_MASK(core_mask)) != 0) { - dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -static bool -is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) -{ - int val; - bool is_enable; - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); - - is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) && - (val & SKL_ADSPCS_SPA_MASK(core_mask)) && - !(val & SKL_ADSPCS_CRST_MASK(core_mask)) && - !(val & SKL_ADSPCS_CSTALL_MASK(core_mask))); - - dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n", - is_enable, core_mask); - - return is_enable; -} - -static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* stall core */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CSTALL_MASK(core_mask), - SKL_ADSPCS_CSTALL_MASK(core_mask)); - - /* set reset state */ - return skl_dsp_core_set_reset_state(ctx, core_mask); -} - -int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* unset reset state */ - ret = skl_dsp_core_unset_reset_state(ctx, core_mask); - if (ret < 0) - return ret; - - /* run core */ - dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask); - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CSTALL_MASK(core_mask), 0); - - if (!is_skl_dsp_core_enable(ctx, core_mask)) { - skl_dsp_reset_core(ctx, core_mask); - dev_err(ctx->dev, "DSP start core failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_SPA_MASK(core_mask), - SKL_ADSPCS_SPA_MASK(core_mask)); - - /* poll with timeout to check if operation successful */ - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CPA_MASK(core_mask), - SKL_ADSPCS_CPA_MASK(core_mask), - SKL_DSP_PU_TO, - "Power up"); - - if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & - SKL_ADSPCS_CPA_MASK(core_mask)) != - SKL_ADSPCS_CPA_MASK(core_mask)) { - dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n", - core_mask); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) -{ - /* update bits */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_SPA_MASK(core_mask), 0); - - /* poll with timeout to check if operation successful */ - return sst_dsp_register_poll(ctx, - SKL_ADSP_REG_ADSPCS, - SKL_ADSPCS_CPA_MASK(core_mask), - 0, - SKL_DSP_PD_TO, - "Power down"); -} - -int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - /* power up */ - ret = skl_dsp_core_power_up(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n", - core_mask); - return ret; - } - - return skl_dsp_start_core(ctx, core_mask); -} - -int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) -{ - int ret; - - ret = skl_dsp_reset_core(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n", - core_mask); - return ret; - } - - /* power down core*/ - ret = skl_dsp_core_power_down(ctx, core_mask); - if (ret < 0) { - dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n", - core_mask, ret); - return ret; - } - - if (is_skl_dsp_core_enable(ctx, core_mask)) { - dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n", - core_mask, ret); - ret = -EIO; - } - - return ret; -} - -int skl_dsp_boot(struct sst_dsp *ctx) -{ - int ret; - - if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) { - ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret); - return ret; - } - - ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret); - return ret; - } - } else { - ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - if (ret < 0) { - dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret); - return ret; - } - ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK); - } - - return ret; -} - -irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) -{ - struct sst_dsp *ctx = dev_id; - u32 val; - irqreturn_t result = IRQ_NONE; - - spin_lock(&ctx->spinlock); - - val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); - ctx->intr_status = val; - - if (val == 0xffffffff) { - spin_unlock(&ctx->spinlock); - return IRQ_NONE; - } - - if (val & SKL_ADSPIS_IPC) { - skl_ipc_int_disable(ctx); - result = IRQ_WAKE_THREAD; - } - - if (val & SKL_ADSPIS_CL_DMA) { - skl_cldma_int_disable(ctx); - result = IRQ_WAKE_THREAD; - } - - spin_unlock(&ctx->spinlock); - - return result; -} -/* - * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context - * within the dapm mutex. Hence no separate lock is used. - */ -int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - if (core_id >= skl->cores.count) { - dev_err(ctx->dev, "invalid core id: %d\n", core_id); - return -EINVAL; - } - - skl->cores.usage_count[core_id]++; - - if (skl->cores.state[core_id] == SKL_DSP_RESET) { - ret = ctx->fw_ops.set_state_D0(ctx, core_id); - if (ret < 0) { - dev_err(ctx->dev, "unable to get core%d\n", core_id); - goto out; - } - } - -out: - dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", - core_id, skl->cores.state[core_id], - skl->cores.usage_count[core_id]); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_dsp_get_core); - -int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) -{ - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - if (core_id >= skl->cores.count) { - dev_err(ctx->dev, "invalid core id: %d\n", core_id); - return -EINVAL; - } - - if ((--skl->cores.usage_count[core_id] == 0) && - (skl->cores.state[core_id] != SKL_DSP_RESET)) { - ret = ctx->fw_ops.set_state_D3(ctx, core_id); - if (ret < 0) { - dev_err(ctx->dev, "unable to put core %d: %d\n", - core_id, ret); - skl->cores.usage_count[core_id]++; - } - } - - dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", - core_id, skl->cores.state[core_id], - skl->cores.usage_count[core_id]); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_dsp_put_core); - -int skl_dsp_wake(struct sst_dsp *ctx) -{ - return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID); -} -EXPORT_SYMBOL_GPL(skl_dsp_wake); - -int skl_dsp_sleep(struct sst_dsp *ctx) -{ - return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID); -} -EXPORT_SYMBOL_GPL(skl_dsp_sleep); - -struct sst_dsp *skl_dsp_ctx_init(struct device *dev, - struct sst_dsp_device *sst_dev, int irq) -{ - int ret; - struct sst_dsp *sst; - - sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); - if (sst == NULL) - return NULL; - - spin_lock_init(&sst->spinlock); - mutex_init(&sst->mutex); - sst->dev = dev; - sst->sst_dev = sst_dev; - sst->irq = irq; - sst->ops = sst_dev->ops; - sst->thread_context = sst_dev->thread_context; - - /* Initialise SST Audio DSP */ - if (sst->ops->init) { - ret = sst->ops->init(sst); - if (ret < 0) - return NULL; - } - - return sst; -} - -int skl_dsp_acquire_irq(struct sst_dsp *sst) -{ - struct sst_dsp_device *sst_dev = sst->sst_dev; - int ret; - - /* Register the ISR */ - ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, - sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); - if (ret) - dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", - sst->irq); - - return ret; -} - -void skl_dsp_free(struct sst_dsp *dsp) -{ - skl_ipc_int_disable(dsp); - - free_irq(dsp->irq, dsp); - skl_ipc_op_int_disable(dsp); - skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); -} -EXPORT_SYMBOL_GPL(skl_dsp_free); - -bool is_skl_dsp_running(struct sst_dsp *ctx) -{ - return (ctx->sst_state == SKL_DSP_RUNNING); -} -EXPORT_SYMBOL_GPL(is_skl_dsp_running); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h deleted file mode 100644 index 1df9ef422f61..000000000000 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Skylake SST DSP Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ - -#ifndef __SKL_SST_DSP_H__ -#define __SKL_SST_DSP_H__ - -#include <linux/interrupt.h> -#include <linux/uuid.h> -#include <linux/firmware.h> -#include <sound/memalloc.h> -#include "skl-sst-cldma.h" - -struct sst_dsp; -struct sst_dsp_device; -struct skl_lib_info; -struct skl_dev; - -/* Intel HD Audio General DSP Registers */ -#define SKL_ADSP_GEN_BASE 0x0 -#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) -#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08) -#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C) -#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10) -#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14) - -/* Intel HD Audio Inter-Processor Communication Registers */ -#define SKL_ADSP_IPC_BASE 0x40 -#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00) -#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04) -#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08) -#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C) -#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10) - -/* HIPCI */ -#define SKL_ADSP_REG_HIPCI_BUSY BIT(31) - -/* HIPCIE */ -#define SKL_ADSP_REG_HIPCIE_DONE BIT(30) - -/* HIPCCTL */ -#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1) -#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0) - -/* HIPCT */ -#define SKL_ADSP_REG_HIPCT_BUSY BIT(31) - -/* FW base IDs */ -#define SKL_INSTANCE_ID 0 -#define SKL_BASE_FW_MODULE_ID 0 - -/* Intel HD Audio SRAM Window 1 */ -#define SKL_ADSP_SRAM1_BASE 0xA000 - -#define SKL_ADSP_MMIO_LEN 0x10000 - -#define SKL_ADSP_W0_STAT_SZ 0x1000 - -#define SKL_ADSP_W0_UP_SZ 0x1000 - -#define SKL_ADSP_W1_SZ 0x1000 - -#define SKL_FW_STS_MASK 0xf - -#define SKL_FW_INIT 0x1 -#define SKL_FW_RFW_START 0xf -#define BXT_FW_ROM_INIT_RETRY 3 -#define BXT_INIT_TIMEOUT 300 - -#define SKL_ADSPIC_IPC 1 -#define SKL_ADSPIS_IPC 1 - -/* Core ID of core0 */ -#define SKL_DSP_CORE0_ID 0 - -/* Mask for a given core index, c = 0.. number of supported cores - 1 */ -#define SKL_DSP_CORE_MASK(c) BIT(c) - -/* - * Core 0 mask = SKL_DSP_CORE_MASK(0); Defined separately - * since Core0 is primary core and it is used often - */ -#define SKL_DSP_CORE0_MASK BIT(0) - -/* - * Mask for a given number of cores - * nc = number of supported cores - */ -#define SKL_DSP_CORES_MASK(nc) GENMASK((nc - 1), 0) - -/* ADSPCS - Audio DSP Control & Status */ - -/* - * Core Reset - asserted high - * CRST Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CRST_SHIFT 0 -#define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT) - -/* - * Core run/stall - when set to '1' core is stalled - * CSTALL Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CSTALL_SHIFT 8 -#define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT) - -/* - * Set Power Active - when set to '1' turn cores on - * SPA Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_SPA_SHIFT 16 -#define SKL_ADSPCS_SPA_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT) - -/* - * Current Power Active - power status of cores, set by hardware - * CPA Mask for a given core mask pattern, cm - */ -#define SKL_ADSPCS_CPA_SHIFT 24 -#define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) - -/* DSP Core state */ -enum skl_dsp_states { - SKL_DSP_RUNNING = 1, - /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ - SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/ - SKL_DSP_RESET, -}; - -/* D0i3 substates */ -enum skl_dsp_d0i3_states { - SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ - SKL_DSP_D0I3_NON_STREAMING = 0, - SKL_DSP_D0I3_STREAMING = 1, -}; - -struct skl_dsp_fw_ops { - int (*load_fw)(struct sst_dsp *ctx); - /* FW module parser/loader */ - int (*load_library)(struct sst_dsp *ctx, - struct skl_lib_info *linfo, int lib_count); - int (*parse_fw)(struct sst_dsp *ctx); - int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); - int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); - int (*set_state_D0i3)(struct sst_dsp *ctx); - int (*set_state_D0i0)(struct sst_dsp *ctx); - unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); - int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); - int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); - -}; - -struct skl_dsp_loader_ops { - int stream_tag; - - int (*alloc_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab, size_t size); - int (*free_dma_buf)(struct device *dev, - struct snd_dma_buffer *dmab); - int (*prepare)(struct device *dev, unsigned int format, - unsigned int byte_size, - struct snd_dma_buffer *bufp); - int (*trigger)(struct device *dev, bool start, int stream_tag); - - int (*cleanup)(struct device *dev, struct snd_dma_buffer *dmab, - int stream_tag); -}; - -#define MAX_INSTANCE_BUFF 2 - -struct uuid_module { - guid_t uuid; - int id; - int is_loadable; - int max_instance; - u64 pvt_id[MAX_INSTANCE_BUFF]; - int *instance_id; - - struct list_head list; -}; - -struct skl_load_module_info { - u16 mod_id; - const struct firmware *fw; -}; - -struct skl_module_table { - struct skl_load_module_info *mod_info; - unsigned int usage_cnt; - struct list_head list; -}; - -void skl_cldma_process_intr(struct sst_dsp *ctx); -void skl_cldma_int_disable(struct sst_dsp *ctx); -int skl_cldma_prepare(struct sst_dsp *ctx); -int skl_cldma_wait_interruptible(struct sst_dsp *ctx); - -void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); -struct sst_dsp *skl_dsp_ctx_init(struct device *dev, - struct sst_dsp_device *sst_dev, int irq); -int skl_dsp_acquire_irq(struct sst_dsp *sst); -bool is_skl_dsp_running(struct sst_dsp *ctx); - -unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx); -void skl_dsp_init_core_state(struct sst_dsp *ctx); -int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask); -int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx, - unsigned int core_mask); -int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask); - -irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); -int skl_dsp_wake(struct sst_dsp *ctx); -int skl_dsp_sleep(struct sst_dsp *ctx); -void skl_dsp_free(struct sst_dsp *dsp); - -int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id); -int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id); - -int skl_dsp_boot(struct sst_dsp *ctx); -int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp); -int skl_sst_init_fw(struct device *dev, struct skl_dev *skl); -int bxt_sst_init_fw(struct device *dev, struct skl_dev *skl); -void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); -void bxt_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl); - -int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, - unsigned int offset, int index); -int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id); -int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id); -int skl_get_pvt_instance_id_map(struct skl_dev *skl, - int module_id, int instance_id); -void skl_freeup_uuid_list(struct skl_dev *skl); - -int skl_dsp_strip_extended_manifest(struct firmware *fw); - -void skl_dsp_set_astate_cfg(struct skl_dev *skl, u32 cnt, void *data); - -int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, - struct sst_dsp_device *skl_dev); -int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, - struct firmware *stripped_fw, - unsigned int hdr_offset, int index); -void skl_release_library(struct skl_lib_info *linfo, int lib_count); - -#endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c deleted file mode 100644 index fd9624ad5f72..000000000000 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ /dev/null @@ -1,1071 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-ipc.c - Intel skl IPC Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ -#include <linux/device.h> - -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "sound/hdaudio_ext.h" - - -#define IPC_IXC_STATUS_BITS 24 - -/* Global Message - Generic */ -#define IPC_GLB_TYPE_SHIFT 24 -#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) -#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) - -/* Global Message - Reply */ -#define IPC_GLB_REPLY_STATUS_SHIFT 24 -#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) -#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) - -#define IPC_GLB_REPLY_TYPE_SHIFT 29 -#define IPC_GLB_REPLY_TYPE_MASK 0x1F -#define IPC_GLB_REPLY_TYPE(x) (((x) >> IPC_GLB_REPLY_TYPE_SHIFT) \ - & IPC_GLB_RPLY_TYPE_MASK) - -#define IPC_TIMEOUT_MSECS 3000 - -#define IPC_EMPTY_LIST_SIZE 8 - -#define IPC_MSG_TARGET_SHIFT 30 -#define IPC_MSG_TARGET_MASK 0x1 -#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ - << IPC_MSG_TARGET_SHIFT) - -#define IPC_MSG_DIR_SHIFT 29 -#define IPC_MSG_DIR_MASK 0x1 -#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ - << IPC_MSG_DIR_SHIFT) -/* Global Notification Message */ -#define IPC_GLB_NOTIFY_TYPE_SHIFT 16 -#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF -#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ - & IPC_GLB_NOTIFY_TYPE_MASK) - -#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 -#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F -#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ - & IPC_GLB_NOTIFY_MSG_TYPE_MASK) - -#define IPC_GLB_NOTIFY_RSP_SHIFT 29 -#define IPC_GLB_NOTIFY_RSP_MASK 0x1 -#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ - & IPC_GLB_NOTIFY_RSP_MASK) - -/* Pipeline operations */ - -/* Create pipeline message */ -#define IPC_PPL_MEM_SIZE_SHIFT 0 -#define IPC_PPL_MEM_SIZE_MASK 0x7FF -#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ - << IPC_PPL_MEM_SIZE_SHIFT) - -#define IPC_PPL_TYPE_SHIFT 11 -#define IPC_PPL_TYPE_MASK 0x1F -#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ - << IPC_PPL_TYPE_SHIFT) - -#define IPC_INSTANCE_ID_SHIFT 16 -#define IPC_INSTANCE_ID_MASK 0xFF -#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ - << IPC_INSTANCE_ID_SHIFT) - -#define IPC_PPL_LP_MODE_SHIFT 0 -#define IPC_PPL_LP_MODE_MASK 0x1 -#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ - << IPC_PPL_LP_MODE_SHIFT) - -/* Set pipeline state message */ -#define IPC_PPL_STATE_SHIFT 0 -#define IPC_PPL_STATE_MASK 0x1F -#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ - << IPC_PPL_STATE_SHIFT) - -/* Module operations primary register */ -#define IPC_MOD_ID_SHIFT 0 -#define IPC_MOD_ID_MASK 0xFFFF -#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ - << IPC_MOD_ID_SHIFT) - -#define IPC_MOD_INSTANCE_ID_SHIFT 16 -#define IPC_MOD_INSTANCE_ID_MASK 0xFF -#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ - << IPC_MOD_INSTANCE_ID_SHIFT) - -/* Init instance message extension register */ -#define IPC_PARAM_BLOCK_SIZE_SHIFT 0 -#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF -#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ - << IPC_PARAM_BLOCK_SIZE_SHIFT) - -#define IPC_PPL_INSTANCE_ID_SHIFT 16 -#define IPC_PPL_INSTANCE_ID_MASK 0xFF -#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ - << IPC_PPL_INSTANCE_ID_SHIFT) - -#define IPC_CORE_ID_SHIFT 24 -#define IPC_CORE_ID_MASK 0x1F -#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ - << IPC_CORE_ID_SHIFT) - -#define IPC_DOMAIN_SHIFT 28 -#define IPC_DOMAIN_MASK 0x1 -#define IPC_DOMAIN(x) (((x) & IPC_DOMAIN_MASK) \ - << IPC_DOMAIN_SHIFT) - -/* Bind/Unbind message extension register */ -#define IPC_DST_MOD_ID_SHIFT 0 -#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ - << IPC_DST_MOD_ID_SHIFT) - -#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 -#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ - << IPC_DST_MOD_INSTANCE_ID_SHIFT) - -#define IPC_DST_QUEUE_SHIFT 24 -#define IPC_DST_QUEUE_MASK 0x7 -#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ - << IPC_DST_QUEUE_SHIFT) - -#define IPC_SRC_QUEUE_SHIFT 27 -#define IPC_SRC_QUEUE_MASK 0x7 -#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ - << IPC_SRC_QUEUE_SHIFT) -/* Load Module count */ -#define IPC_LOAD_MODULE_SHIFT 0 -#define IPC_LOAD_MODULE_MASK 0xFF -#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ - << IPC_LOAD_MODULE_SHIFT) - -/* Save pipeline messgae extension register */ -#define IPC_DMA_ID_SHIFT 0 -#define IPC_DMA_ID_MASK 0x1F -#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ - << IPC_DMA_ID_SHIFT) -/* Large Config message extension register */ -#define IPC_DATA_OFFSET_SZ_SHIFT 0 -#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF -#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ - << IPC_DATA_OFFSET_SZ_SHIFT) -#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ - << IPC_DATA_OFFSET_SZ_SHIFT) - -#define IPC_LARGE_PARAM_ID_SHIFT 20 -#define IPC_LARGE_PARAM_ID_MASK 0xFF -#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ - << IPC_LARGE_PARAM_ID_SHIFT) - -#define IPC_FINAL_BLOCK_SHIFT 28 -#define IPC_FINAL_BLOCK_MASK 0x1 -#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ - << IPC_FINAL_BLOCK_SHIFT) - -#define IPC_INITIAL_BLOCK_SHIFT 29 -#define IPC_INITIAL_BLOCK_MASK 0x1 -#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ - << IPC_INITIAL_BLOCK_SHIFT) -#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ - << IPC_INITIAL_BLOCK_SHIFT) -/* Set D0ix IPC extension register */ -#define IPC_D0IX_WAKE_SHIFT 0 -#define IPC_D0IX_WAKE_MASK 0x1 -#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ - << IPC_D0IX_WAKE_SHIFT) - -#define IPC_D0IX_STREAMING_SHIFT 1 -#define IPC_D0IX_STREAMING_MASK 0x1 -#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ - << IPC_D0IX_STREAMING_SHIFT) - - -enum skl_ipc_msg_target { - IPC_FW_GEN_MSG = 0, - IPC_MOD_MSG = 1 -}; - -enum skl_ipc_msg_direction { - IPC_MSG_REQUEST = 0, - IPC_MSG_REPLY = 1 -}; - -/* Global Message Types */ -enum skl_ipc_glb_type { - IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ - IPC_GLB_LOAD_MULTIPLE_MODS = 15, - IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, - IPC_GLB_CREATE_PPL = 17, - IPC_GLB_DELETE_PPL = 18, - IPC_GLB_SET_PPL_STATE = 19, - IPC_GLB_GET_PPL_STATE = 20, - IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, - IPC_GLB_SAVE_PPL = 22, - IPC_GLB_RESTORE_PPL = 23, - IPC_GLB_LOAD_LIBRARY = 24, - IPC_GLB_NOTIFY = 26, - IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ -}; - -enum skl_ipc_glb_reply { - IPC_GLB_REPLY_SUCCESS = 0, - - IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, - IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, - - IPC_GLB_REPLY_BUSY = 3, - IPC_GLB_REPLY_PENDING = 4, - IPC_GLB_REPLY_FAILURE = 5, - IPC_GLB_REPLY_INVALID_REQUEST = 6, - - IPC_GLB_REPLY_OUT_OF_MEMORY = 7, - IPC_GLB_REPLY_OUT_OF_MIPS = 8, - - IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, - IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, - - IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, - IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, - IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, - - IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, - IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, - - IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, - IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, - IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, - IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, - IPC_GLB_REPLY_SCLK_ALREADY_RUNNING = 150, - IPC_GLB_REPLY_MCLK_ALREADY_RUNNING = 151, - - IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, - IPC_GLB_REPLY_PPL_NOT_EXIST = 161, - IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, - IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, - - IPC_MAX_STATUS = ((1<<IPC_IXC_STATUS_BITS)-1) -}; - -enum skl_ipc_notification_type { - IPC_GLB_NOTIFY_GLITCH = 0, - IPC_GLB_NOTIFY_OVERRUN = 1, - IPC_GLB_NOTIFY_UNDERRUN = 2, - IPC_GLB_NOTIFY_END_STREAM = 3, - IPC_GLB_NOTIFY_PHRASE_DETECTED = 4, - IPC_GLB_NOTIFY_RESOURCE_EVENT = 5, - IPC_GLB_NOTIFY_LOG_BUFFER_STATUS = 6, - IPC_GLB_NOTIFY_TIMESTAMP_CAPTURED = 7, - IPC_GLB_NOTIFY_FW_READY = 8 -}; - -/* Module Message Types */ -enum skl_ipc_module_msg { - IPC_MOD_INIT_INSTANCE = 0, - IPC_MOD_CONFIG_GET = 1, - IPC_MOD_CONFIG_SET = 2, - IPC_MOD_LARGE_CONFIG_GET = 3, - IPC_MOD_LARGE_CONFIG_SET = 4, - IPC_MOD_BIND = 5, - IPC_MOD_UNBIND = 6, - IPC_MOD_SET_DX = 7, - IPC_MOD_SET_D0IX = 8 -}; - -void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, - size_t tx_size) -{ - if (tx_size) - memcpy(msg->tx.data, tx_data, tx_size); -} - -static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) -{ - u32 hipci; - - hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); - return (hipci & SKL_ADSP_REG_HIPCI_BUSY); -} - -/* Lock to be held by caller */ -static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) -{ - struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->tx.header); - - if (msg->tx.size) - sst_dsp_outbox_write(ipc->dsp, msg->tx.data, msg->tx.size); - sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, - header->extension); - sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, - header->primary | SKL_ADSP_REG_HIPCI_BUSY); -} - -int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) -{ - int ret; - - /* check D0i3 support */ - if (!dsp->fw_ops.set_state_D0i0) - return 0; - - /* Attempt D0i0 or D0i3 based on state */ - if (state) - ret = dsp->fw_ops.set_state_D0i0(dsp); - else - ret = dsp->fw_ops.set_state_D0i3(dsp); - - return ret; -} - -static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, - u64 ipc_header) -{ - struct ipc_message *msg = NULL; - struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); - - if (list_empty(&ipc->rx_list)) { - dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", - header->primary); - goto out; - } - - msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); - - list_del(&msg->list); -out: - return msg; - -} - -int skl_ipc_process_notification(struct sst_generic_ipc *ipc, - struct skl_ipc_header header) -{ - struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); - - if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { - - case IPC_GLB_NOTIFY_UNDERRUN: - dev_err(ipc->dev, "FW Underrun %x\n", header.primary); - break; - - case IPC_GLB_NOTIFY_RESOURCE_EVENT: - dev_err(ipc->dev, "MCPS Budget Violation: %x\n", - header.primary); - break; - - case IPC_GLB_NOTIFY_FW_READY: - skl->boot_complete = true; - wake_up(&skl->boot_wait); - break; - - case IPC_GLB_NOTIFY_PHRASE_DETECTED: - dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); - - /* - * Per HW recomendation, After phrase detection, - * clear the CGCTL.MISCBDCGE. - * - * This will be set back on stream closure - */ - skl->enable_miscbdcge(ipc->dev, false); - skl->miscbdcg_disabled = true; - break; - - default: - dev_err(ipc->dev, "ipc: Unhandled error msg=%x\n", - header.primary); - break; - } - } - - return 0; -} - -struct skl_ipc_err_map { - const char *msg; - enum skl_ipc_glb_reply reply; - int err; -}; - -static struct skl_ipc_err_map skl_err_map[] = { - {"DSP out of memory", IPC_GLB_REPLY_OUT_OF_MEMORY, -ENOMEM}, - {"DSP busy", IPC_GLB_REPLY_BUSY, -EBUSY}, - {"SCLK already running", IPC_GLB_REPLY_SCLK_ALREADY_RUNNING, - IPC_GLB_REPLY_SCLK_ALREADY_RUNNING}, - {"MCLK already running", IPC_GLB_REPLY_MCLK_ALREADY_RUNNING, - IPC_GLB_REPLY_MCLK_ALREADY_RUNNING}, -}; - -static int skl_ipc_set_reply_error_code(struct sst_generic_ipc *ipc, u32 reply) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(skl_err_map); i++) { - if (skl_err_map[i].reply == reply) - break; - } - - if (i == ARRAY_SIZE(skl_err_map)) { - dev_err(ipc->dev, "ipc FW reply: %d FW Error Code: %u\n", - reply, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - return -EINVAL; - } - - if (skl_err_map[i].err < 0) - dev_err(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", - skl_err_map[i].msg, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - else - dev_info(ipc->dev, "ipc FW reply: %s FW Error Code: %u\n", - skl_err_map[i].msg, - ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); - - return skl_err_map[i].err; -} - -void skl_ipc_process_reply(struct sst_generic_ipc *ipc, - struct skl_ipc_header header) -{ - struct ipc_message *msg; - u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; - u64 *ipc_header = (u64 *)(&header); - struct skl_dev *skl = container_of(ipc, struct skl_dev, ipc); - unsigned long flags; - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - msg = skl_ipc_reply_get_msg(ipc, *ipc_header); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - if (msg == NULL) { - dev_dbg(ipc->dev, "ipc: rx list is empty\n"); - return; - } - - msg->rx.header = *ipc_header; - /* first process the header */ - if (reply == IPC_GLB_REPLY_SUCCESS) { - dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); - /* copy the rx data from the mailbox */ - sst_dsp_inbox_read(ipc->dsp, msg->rx.data, msg->rx.size); - switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - case IPC_GLB_LOAD_MULTIPLE_MODS: - case IPC_GLB_LOAD_LIBRARY: - skl->mod_load_complete = true; - skl->mod_load_status = true; - wake_up(&skl->mod_load_wait); - break; - - default: - break; - - } - } else { - msg->errno = skl_ipc_set_reply_error_code(ipc, reply); - switch (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { - case IPC_GLB_LOAD_MULTIPLE_MODS: - case IPC_GLB_LOAD_LIBRARY: - skl->mod_load_complete = true; - skl->mod_load_status = false; - wake_up(&skl->mod_load_wait); - break; - - default: - break; - - } - } - - spin_lock_irqsave(&ipc->dsp->spinlock, flags); - sst_ipc_tx_msg_reply_complete(ipc, msg); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); -} - -irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) -{ - struct sst_dsp *dsp = context; - struct skl_dev *skl = dsp->thread_context; - struct sst_generic_ipc *ipc = &skl->ipc; - struct skl_ipc_header header = {0}; - u32 hipcie, hipct, hipcte; - int ipc_irq = 0; - - if (dsp->intr_status & SKL_ADSPIS_CL_DMA) - skl_cldma_process_intr(dsp); - - /* Here we handle IPC interrupts only */ - if (!(dsp->intr_status & SKL_ADSPIS_IPC)) - return IRQ_NONE; - - hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); - hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); - hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); - - /* reply message from DSP */ - if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { - sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* clear DONE bit - tell DSP we have completed the operation */ - sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, - SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); - - ipc_irq = 1; - - /* unmask Done interrupt */ - sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); - } - - /* New message from DSP */ - if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { - header.primary = hipct; - header.extension = hipcte; - dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x\n", - header.primary); - dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x\n", - header.extension); - - if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { - /* Handle Immediate reply from DSP Core */ - skl_ipc_process_reply(ipc, header); - } else { - dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); - skl_ipc_process_notification(ipc, header); - } - /* clear busy interrupt */ - sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, - SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); - ipc_irq = 1; - } - - if (ipc_irq == 0) - return IRQ_NONE; - - skl_ipc_int_enable(dsp); - - /* continue to send any remaining messages... */ - schedule_work(&ipc->kwork); - - return IRQ_HANDLED; -} - -void skl_ipc_int_enable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); -} - -void skl_ipc_int_disable(struct sst_dsp *ctx) -{ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, - SKL_ADSPIC_IPC, 0); -} - -void skl_ipc_op_int_enable(struct sst_dsp *ctx) -{ - /* enable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); - - /* Enable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); -} - -void skl_ipc_op_int_disable(struct sst_dsp *ctx) -{ - /* disable IPC DONE interrupt */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* Disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, 0); - -} - -bool skl_ipc_int_status(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read_unlocked(ctx, - SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; -} - -int skl_ipc_init(struct device *dev, struct skl_dev *skl) -{ - struct sst_generic_ipc *ipc; - int err; - - ipc = &skl->ipc; - ipc->dsp = skl->dsp; - ipc->dev = dev; - - ipc->tx_data_max_size = SKL_ADSP_W1_SZ; - ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; - - err = sst_ipc_init(ipc); - if (err) - return err; - - ipc->ops.tx_msg = skl_ipc_tx_msg; - ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; - ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; - - return 0; -} - -void skl_ipc_free(struct sst_generic_ipc *ipc) -{ - /* Disable IPC DONE interrupt */ - sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_DONE, 0); - - /* Disable IPC BUSY interrupt */ - sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, - SKL_ADSP_REG_HIPCCTL_BUSY, 0); - - sst_ipc_fini(ipc); -} - -int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - header.primary |= IPC_PPL_TYPE(ppl_type); - header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); - - header.extension = IPC_PPL_LP_MODE(lp_mode); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); - -int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); - -int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, - u8 instance_id, enum skl_ipc_pipeline_state state) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); - header.primary |= IPC_INSTANCE_ID(instance_id); - header.primary |= IPC_PPL_STATE(state); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); - return ret; - } - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); - -int -skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - - header.extension = IPC_DMA_ID(dma_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); - -int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); - header.primary |= IPC_INSTANCE_ID(instance_id); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); - -int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, - u16 module_id, struct skl_ipc_dxstate_info *dx) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); - header.primary |= IPC_MOD_INSTANCE_ID(instance_id); - header.primary |= IPC_MOD_ID(module_id); - - request.header = *(u64 *)(&header); - request.data = dx; - request.size = sizeof(*dx); - - dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, - header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_dx); - -int skl_ipc_init_instance(struct sst_generic_ipc *ipc, - struct skl_ipc_init_instance_msg *msg, void *param_data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - u32 *buffer = (u32 *)param_data; - /* param_block_size must be in dwords */ - u16 param_block_size = msg->param_data_size / sizeof(u32); - - print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE, - 16, 4, buffer, param_block_size, false); - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_CORE_ID(msg->core_id); - header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); - header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); - header.extension |= IPC_DOMAIN(msg->domain); - - request.header = *(u64 *)(&header); - request.data = param_data; - request.size = msg->param_data_size; - - dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, - header.primary, header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - - if (ret < 0) { - dev_err(ipc->dev, "ipc: init instance failed\n"); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_init_instance); - -int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, - struct skl_ipc_bind_unbind_msg *msg) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(bind_unbind); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DST_MOD_ID(msg->dst_module_id); - header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); - header.extension |= IPC_DST_QUEUE(msg->dst_queue); - header.extension |= IPC_SRC_QUEUE(msg->src_queue); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, - header.extension); - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, "ipc: bind/unbind failed\n"); - return ret; - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); - -/* - * In order to load a module we need to send IPC to initiate that. DMA will - * performed to load the module memory. The FW supports multiple module load - * at single shot, so we can send IPC with N modules represented by - * module_cnt - */ -int skl_ipc_load_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); - header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - - request.header = *(u64 *)(&header); - request.data = data; - request.size = sizeof(u16) * module_cnt; - - ret = sst_ipc_tx_message_nowait(ipc, request); - if (ret < 0) - dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_load_modules); - -int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, - void *data) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); - header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); - - request.header = *(u64 *)(&header); - request.data = data; - request.size = sizeof(u16) * module_cnt; - - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) - dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); - -int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request; - int ret = 0; - size_t sz_remaining, tx_size, data_offset; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); - header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); - header.extension |= IPC_FINAL_BLOCK(0); - header.extension |= IPC_INITIAL_BLOCK(1); - - sz_remaining = msg->param_data_size; - data_offset = 0; - while (sz_remaining != 0) { - tx_size = sz_remaining > SKL_ADSP_W1_SZ - ? SKL_ADSP_W1_SZ : sz_remaining; - if (tx_size == sz_remaining) - header.extension |= IPC_FINAL_BLOCK(1); - - dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, - header.primary, header.extension); - dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", - (unsigned)data_offset, (unsigned)tx_size); - - request.header = *(u64 *)(&header); - request.data = ((char *)param) + data_offset; - request.size = tx_size; - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - if (ret < 0) { - dev_err(ipc->dev, - "ipc: set large config fail, err: %d\n", ret); - return ret; - } - sz_remaining -= tx_size; - data_offset = msg->param_data_size - sz_remaining; - - /* clear the fields */ - header.extension &= IPC_INITIAL_BLOCK_CLEAR; - header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; - /* fill the fields */ - header.extension |= IPC_INITIAL_BLOCK(0); - header.extension |= IPC_DATA_OFFSET_SZ(data_offset); - } - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); - -int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, - u32 **payload, size_t *bytes) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request, reply = {0}; - unsigned int *buf; - int ret; - - reply.data = kzalloc(SKL_ADSP_W1_SZ, GFP_KERNEL); - if (!reply.data) - return -ENOMEM; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); - header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); - header.extension |= IPC_FINAL_BLOCK(1); - header.extension |= IPC_INITIAL_BLOCK(1); - - request.header = *(u64 *)&header; - request.data = *payload; - request.size = *bytes; - reply.size = SKL_ADSP_W1_SZ; - - ret = sst_ipc_tx_message_wait(ipc, request, &reply); - if (ret < 0) - dev_err(ipc->dev, "ipc: get large config fail, err: %d\n", ret); - - reply.size = (reply.header >> 32) & IPC_DATA_OFFSET_SZ_MASK; - buf = krealloc(reply.data, reply.size, GFP_KERNEL); - if (!buf) { - kfree(reply.data); - return -ENOMEM; - } - *payload = buf; - *bytes = reply.size; - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); - -int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id, bool wait) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret = 0; - - header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_LIBRARY); - header.primary |= IPC_MOD_INSTANCE_ID(table_id); - header.primary |= IPC_MOD_ID(dma_id); - request.header = *(u64 *)(&header); - - if (wait) - ret = sst_ipc_tx_message_wait(ipc, request, NULL); - else - ret = sst_ipc_tx_message_nowait(ipc, request); - - if (ret < 0) - dev_err(ipc->dev, "ipc: load lib failed\n"); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); - -int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) -{ - struct skl_ipc_header header = {0}; - struct sst_ipc_message request = {0}; - int ret; - - header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); - header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); - header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); - header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); - header.primary |= IPC_MOD_ID(msg->module_id); - - header.extension = IPC_D0IX_WAKE(msg->wake); - header.extension |= IPC_D0IX_STREAMING(msg->streaming); - request.header = *(u64 *)(&header); - - dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, - header.primary, header.extension); - - /* - * Use the nopm IPC here as we dont want it checking for D0iX - */ - ret = sst_ipc_tx_message_nopm(ipc, request, NULL); - if (ret < 0) - dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); - - return ret; -} -EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h deleted file mode 100644 index aaaab3b3ec42..000000000000 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ /dev/null @@ -1,169 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * Intel SKL IPC Support - * - * Copyright (C) 2014-15, Intel Corporation. - */ - -#ifndef __SKL_IPC_H -#define __SKL_IPC_H - -#include <linux/irqreturn.h> -#include "../common/sst-ipc.h" -#include "skl-sst-dsp.h" - -struct sst_dsp; -struct sst_generic_ipc; - -enum skl_ipc_pipeline_state { - PPL_INVALID_STATE = 0, - PPL_UNINITIALIZED = 1, - PPL_RESET = 2, - PPL_PAUSED = 3, - PPL_RUNNING = 4, - PPL_ERROR_STOP = 5, - PPL_SAVED = 6, - PPL_RESTORED = 7 -}; - -struct skl_ipc_dxstate_info { - u32 core_mask; - u32 dx_mask; -}; - -struct skl_ipc_header { - u32 primary; - u32 extension; -}; - -struct skl_dsp_cores { - unsigned int count; - enum skl_dsp_states *state; - int *usage_count; -}; - -/** - * skl_d0i3_data: skl D0i3 counters data struct - * - * @streaming: Count of usecases that can attempt streaming D0i3 - * @non_streaming: Count of usecases that can attempt non-streaming D0i3 - * @non_d0i3: Count of usecases that cannot attempt D0i3 - * @state: current state - * @work: D0i3 worker thread - */ -struct skl_d0i3_data { - int streaming; - int non_streaming; - int non_d0i3; - enum skl_dsp_d0i3_states state; - struct delayed_work work; -}; - -#define SKL_LIB_NAME_LENGTH 128 -#define SKL_MAX_LIB 16 - -struct skl_lib_info { - char name[SKL_LIB_NAME_LENGTH]; - const struct firmware *fw; -}; - -struct skl_ipc_init_instance_msg { - u32 module_id; - u32 instance_id; - u16 param_data_size; - u8 ppl_instance_id; - u8 core_id; - u8 domain; -}; - -struct skl_ipc_bind_unbind_msg { - u32 module_id; - u32 instance_id; - u32 dst_module_id; - u32 dst_instance_id; - u8 src_queue; - u8 dst_queue; - bool bind; -}; - -struct skl_ipc_large_config_msg { - u32 module_id; - u32 instance_id; - u32 large_param_id; - u32 param_data_size; -}; - -struct skl_ipc_d0ix_msg { - u32 module_id; - u32 instance_id; - u8 streaming; - u8 wake; -}; - -#define SKL_IPC_BOOT_MSECS 3000 - -#define SKL_IPC_D3_MASK 0 -#define SKL_IPC_D0_MASK 3 - -irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); - -int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); - -int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); - -int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, - u8 instance_id, enum skl_ipc_pipeline_state state); - -int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, - u8 instance_id, int dma_id); - -int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); - -int skl_ipc_init_instance(struct sst_generic_ipc *ipc, - struct skl_ipc_init_instance_msg *msg, void *param_data); - -int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, - struct skl_ipc_bind_unbind_msg *msg); - -int skl_ipc_load_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data); - -int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, - u8 module_cnt, void *data); - -int skl_ipc_set_dx(struct sst_generic_ipc *ipc, - u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); - -int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, u32 *param); - -int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, - struct skl_ipc_large_config_msg *msg, - u32 **payload, size_t *bytes); - -int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, - u8 dma_id, u8 table_id, bool wait); - -int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, - struct skl_ipc_d0ix_msg *msg); - -int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); - -void skl_ipc_int_enable(struct sst_dsp *ctx); -void skl_ipc_op_int_enable(struct sst_dsp *ctx); -void skl_ipc_op_int_disable(struct sst_dsp *ctx); -void skl_ipc_int_disable(struct sst_dsp *ctx); - -bool skl_ipc_int_status(struct sst_dsp *ctx); -void skl_ipc_free(struct sst_generic_ipc *ipc); -int skl_ipc_init(struct device *dev, struct skl_dev *skl); -void skl_clear_module_cnt(struct sst_dsp *ctx); - -void skl_ipc_process_reply(struct sst_generic_ipc *ipc, - struct skl_ipc_header header); -int skl_ipc_process_notification(struct sst_generic_ipc *ipc, - struct skl_ipc_header header); -void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, - size_t tx_size); -#endif /* __SKL_IPC_H */ diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c deleted file mode 100644 index b776c58dcf47..000000000000 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ /dev/null @@ -1,425 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst-utils.c - SKL sst utils functions - * - * Copyright (C) 2016 Intel Corp - */ - -#include <linux/device.h> -#include <linux/slab.h> -#include <linux/uuid.h> -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "skl.h" - -#define DEFAULT_HASH_SHA256_LEN 32 - -/* FW Extended Manifest Header id = $AE1 */ -#define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 - -union seg_flags { - u32 ul; - struct { - u32 contents : 1; - u32 alloc : 1; - u32 load : 1; - u32 read_only : 1; - u32 code : 1; - u32 data : 1; - u32 _rsvd0 : 2; - u32 type : 4; - u32 _rsvd1 : 4; - u32 length : 16; - } r; -} __packed; - -struct segment_desc { - union seg_flags flags; - u32 v_base_addr; - u32 file_offset; -}; - -struct module_type { - u32 load_type : 4; - u32 auto_start : 1; - u32 domain_ll : 1; - u32 domain_dp : 1; - u32 rsvd : 25; -} __packed; - -struct adsp_module_entry { - u32 struct_id; - u8 name[8]; - u8 uuid[16]; - struct module_type type; - u8 hash1[DEFAULT_HASH_SHA256_LEN]; - u32 entry_point; - u16 cfg_offset; - u16 cfg_count; - u32 affinity_mask; - u16 instance_max_count; - u16 instance_bss_size; - struct segment_desc segments[3]; -} __packed; - -struct adsp_fw_hdr { - u32 id; - u32 len; - u8 name[8]; - u32 preload_page_count; - u32 fw_image_flags; - u32 feature_mask; - u16 major; - u16 minor; - u16 hotfix; - u16 build; - u32 num_modules; - u32 hw_buf_base; - u32 hw_buf_length; - u32 load_offset; -} __packed; - -struct skl_ext_manifest_hdr { - u32 id; - u32 len; - u16 version_major; - u16 version_minor; - u32 entries; -}; - -static int skl_get_pvtid_map(struct uuid_module *module, int instance_id) -{ - int pvt_id; - - for (pvt_id = 0; pvt_id < module->max_instance; pvt_id++) { - if (module->instance_id[pvt_id] == instance_id) - return pvt_id; - } - return -EINVAL; -} - -int skl_get_pvt_instance_id_map(struct skl_dev *skl, - int module_id, int instance_id) -{ - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (module->id == module_id) - return skl_get_pvtid_map(module, instance_id); - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_get_pvt_instance_id_map); - -static inline int skl_getid_32(struct uuid_module *module, u64 *val, - int word1_mask, int word2_mask) -{ - int index, max_inst, pvt_id; - u32 mask_val; - - max_inst = module->max_instance; - mask_val = (u32)(*val >> word1_mask); - - if (mask_val != 0xffffffff) { - index = ffz(mask_val); - pvt_id = index + word1_mask + word2_mask; - if (pvt_id <= (max_inst - 1)) { - *val |= 1ULL << (index + word1_mask); - return pvt_id; - } - } - - return -EINVAL; -} - -static inline int skl_pvtid_128(struct uuid_module *module) -{ - int j, i, word1_mask, word2_mask = 0, pvt_id; - - for (j = 0; j < MAX_INSTANCE_BUFF; j++) { - word1_mask = 0; - - for (i = 0; i < 2; i++) { - pvt_id = skl_getid_32(module, &module->pvt_id[j], - word1_mask, word2_mask); - if (pvt_id >= 0) - return pvt_id; - - word1_mask += 32; - if ((word1_mask + word2_mask) >= module->max_instance) - return -EINVAL; - } - - word2_mask += 64; - if (word2_mask >= module->max_instance) - return -EINVAL; - } - - return -EINVAL; -} - -/** - * skl_get_pvt_id: generate a private id for use as module id - * - * @skl: driver context - * @uuid_mod: module's uuid - * @instance_id: module's instance id - * - * This generates a 128 bit private unique id for a module TYPE so that - * module instance is unique - */ -int skl_get_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int instance_id) -{ - struct uuid_module *module; - int pvt_id; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - - pvt_id = skl_pvtid_128(module); - if (pvt_id >= 0) { - module->instance_id[pvt_id] = instance_id; - - return pvt_id; - } - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_get_pvt_id); - -/** - * skl_put_pvt_id: free up the private id allocated - * - * @skl: driver context - * @uuid_mod: module's uuid - * @pvt_id: module pvt id - * - * This frees a 128 bit private unique id previously generated - */ -int skl_put_pvt_id(struct skl_dev *skl, guid_t *uuid_mod, int *pvt_id) -{ - int i; - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid_mod, &module->uuid)) { - - if (*pvt_id != 0) - i = (*pvt_id) / 64; - else - i = 0; - - module->pvt_id[i] &= ~(1 << (*pvt_id)); - *pvt_id = -1; - return 0; - } - } - - return -EINVAL; -} -EXPORT_SYMBOL_GPL(skl_put_pvt_id); - -/* - * Parse the firmware binary to get the UUID, module id - * and loadable flags - */ -int snd_skl_parse_uuids(struct sst_dsp *ctx, const struct firmware *fw, - unsigned int offset, int index) -{ - struct adsp_fw_hdr *adsp_hdr; - struct adsp_module_entry *mod_entry; - int i, num_entry, size; - const char *buf; - struct skl_dev *skl = ctx->thread_context; - struct uuid_module *module; - struct firmware stripped_fw; - unsigned int safe_file; - int ret; - - /* Get the FW pointer to derive ADSP header */ - stripped_fw.data = fw->data; - stripped_fw.size = fw->size; - - skl_dsp_strip_extended_manifest(&stripped_fw); - - buf = stripped_fw.data; - - /* check if we have enough space in file to move to header */ - safe_file = sizeof(*adsp_hdr) + offset; - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); - return -EINVAL; - } - - adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); - - /* check 1st module entry is in file */ - safe_file += adsp_hdr->len + sizeof(*mod_entry); - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No module entry\n"); - return -EINVAL; - } - - mod_entry = (struct adsp_module_entry *)(buf + offset + adsp_hdr->len); - - num_entry = adsp_hdr->num_modules; - - /* check all entries are in file */ - safe_file += num_entry * sizeof(*mod_entry); - if (stripped_fw.size <= safe_file) { - dev_err(ctx->dev, "Small fw file size, No modules\n"); - return -EINVAL; - } - - - /* - * Read the UUID(GUID) from FW Manifest. - * - * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX - * Populate the UUID table to store module_id and loadable flags - * for the module. - */ - - for (i = 0; i < num_entry; i++, mod_entry++) { - module = kzalloc(sizeof(*module), GFP_KERNEL); - if (!module) { - ret = -ENOMEM; - goto free_uuid_list; - } - - import_guid(&module->uuid, mod_entry->uuid); - - module->id = (i | (index << 12)); - module->is_loadable = mod_entry->type.load_type; - module->max_instance = mod_entry->instance_max_count; - size = sizeof(int) * mod_entry->instance_max_count; - module->instance_id = devm_kzalloc(ctx->dev, size, GFP_KERNEL); - if (!module->instance_id) { - ret = -ENOMEM; - kfree(module); - goto free_uuid_list; - } - - list_add_tail(&module->list, &skl->uuid_list); - - dev_dbg(ctx->dev, - "Adding uuid :%pUL mod id: %d Loadable: %d\n", - &module->uuid, module->id, module->is_loadable); - } - - return 0; - -free_uuid_list: - skl_freeup_uuid_list(skl); - return ret; -} - -void skl_freeup_uuid_list(struct skl_dev *skl) -{ - struct uuid_module *uuid, *_uuid; - - list_for_each_entry_safe(uuid, _uuid, &skl->uuid_list, list) { - list_del(&uuid->list); - kfree(uuid); - } -} - -/* - * some firmware binary contains some extended manifest. This needs - * to be stripped in that case before we load and use that image. - * - * Get the module id for the module by checking - * the table for the UUID for the module - */ -int skl_dsp_strip_extended_manifest(struct firmware *fw) -{ - struct skl_ext_manifest_hdr *hdr; - - /* check if fw file is greater than header we are looking */ - if (fw->size < sizeof(hdr)) { - pr_err("%s: Firmware file small, no hdr\n", __func__); - return -EINVAL; - } - - hdr = (struct skl_ext_manifest_hdr *)fw->data; - - if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { - fw->size -= hdr->len; - fw->data += hdr->len; - } - - return 0; -} - -int skl_sst_ctx_init(struct device *dev, int irq, const char *fw_name, - struct skl_dsp_loader_ops dsp_ops, struct skl_dev **dsp, - struct sst_dsp_device *skl_dev) -{ - struct skl_dev *skl = *dsp; - struct sst_dsp *sst; - - skl->dev = dev; - skl_dev->thread_context = skl; - INIT_LIST_HEAD(&skl->uuid_list); - skl->dsp = skl_dsp_ctx_init(dev, skl_dev, irq); - if (!skl->dsp) { - dev_err(skl->dev, "%s: no device\n", __func__); - return -ENODEV; - } - - sst = skl->dsp; - sst->fw_name = fw_name; - sst->dsp_ops = dsp_ops; - init_waitqueue_head(&skl->mod_load_wait); - INIT_LIST_HEAD(&sst->module_list); - - skl->is_first_boot = true; - - return 0; -} - -int skl_prepare_lib_load(struct skl_dev *skl, struct skl_lib_info *linfo, - struct firmware *stripped_fw, - unsigned int hdr_offset, int index) -{ - int ret; - struct sst_dsp *dsp = skl->dsp; - - if (linfo->fw == NULL) { - ret = request_firmware(&linfo->fw, linfo->name, - skl->dev); - if (ret < 0) { - dev_err(skl->dev, "Request lib %s failed:%d\n", - linfo->name, ret); - return ret; - } - } - - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(dsp, linfo->fw, hdr_offset, index); - if (ret < 0) - return ret; - } - - stripped_fw->data = linfo->fw->data; - stripped_fw->size = linfo->fw->size; - skl_dsp_strip_extended_manifest(stripped_fw); - - return 0; -} - -void skl_release_library(struct skl_lib_info *linfo, int lib_count) -{ - int i; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - if (linfo[i].fw) { - release_firmware(linfo[i].fw); - linfo[i].fw = NULL; - } - } -} diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c deleted file mode 100644 index 39d027ac16ec..000000000000 --- a/sound/soc/intel/skylake/skl-sst.c +++ /dev/null @@ -1,599 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-sst.c - HDA DSP library functions for SKL platform - * - * Copyright (C) 2014-15, Intel Corporation. - * Author:Rafal Redzimski <rafal.f.redzimski@intel.com> - * Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/err.h> -#include <linux/uuid.h> -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" -#include "../common/sst-ipc.h" -#include "skl.h" - -#define SKL_BASEFW_TIMEOUT 300 -#define SKL_INIT_TIMEOUT 1000 - -/* Intel HD Audio SRAM Window 0*/ -#define SKL_ADSP_SRAM0_BASE 0x8000 - -/* Firmware status window */ -#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE -#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) - -#define SKL_NUM_MODULES 1 - -static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) -{ - u32 cur_sts; - - cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; - - return (cur_sts == status); -} - -static int skl_transfer_firmware(struct sst_dsp *ctx, - const void *basefw, u32 base_fw_size) -{ - int ret = 0; - - ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size, - true); - if (ret < 0) - return ret; - - ret = sst_dsp_register_poll(ctx, - SKL_ADSP_FW_STATUS, - SKL_FW_STS_MASK, - SKL_FW_RFW_START, - SKL_BASEFW_TIMEOUT, - "Firmware boot"); - - ctx->cl_dev.ops.cl_stop_dma(ctx); - - return ret; -} - -#define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284 - -static int skl_load_base_firmware(struct sst_dsp *ctx) -{ - int ret = 0, i; - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - u32 reg; - - skl->boot_complete = false; - init_waitqueue_head(&skl->boot_wait); - - if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request firmware failed %d\n", ret); - return -EIO; - } - } - - /* prase uuids on first boot */ - if (skl->is_first_boot) { - ret = snd_skl_parse_uuids(ctx, ctx->fw, SKL_ADSP_FW_BIN_HDR_OFFSET, 0); - if (ret < 0) { - dev_err(ctx->dev, "UUID parsing err: %d\n", ret); - release_firmware(ctx->fw); - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - return ret; - } - } - - /* check for extended manifest */ - stripped_fw.data = ctx->fw->data; - stripped_fw.size = ctx->fw->size; - - skl_dsp_strip_extended_manifest(&stripped_fw); - - ret = skl_dsp_boot(ctx); - if (ret < 0) { - dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); - goto skl_load_base_firmware_failed; - } - - ret = skl_cldma_prepare(ctx); - if (ret < 0) { - dev_err(ctx->dev, "CL dma prepare failed : %d\n", ret); - goto skl_load_base_firmware_failed; - } - - /* enable Interrupt */ - skl_ipc_int_enable(ctx); - skl_ipc_op_int_enable(ctx); - - /* check ROM Status */ - for (i = SKL_INIT_TIMEOUT; i > 0; --i) { - if (skl_check_fw_status(ctx, SKL_FW_INIT)) { - dev_dbg(ctx->dev, - "ROM loaded, we can continue with FW loading\n"); - break; - } - mdelay(1); - } - if (!i) { - reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); - dev_err(ctx->dev, - "Timeout waiting for ROM init done, reg:0x%x\n", reg); - ret = -EIO; - goto transfer_firmware_failed; - } - - ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size); - if (ret < 0) { - dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); - goto transfer_firmware_failed; - } else { - ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0) { - dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); - ret = -EIO; - goto transfer_firmware_failed; - } - - dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); - skl->fw_loaded = true; - } - return 0; -transfer_firmware_failed: - ctx->cl_dev.ops.cl_cleanup_controller(ctx); -skl_load_base_firmware_failed: - skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); - release_firmware(ctx->fw); - ctx->fw = NULL; - return ret; -} - -static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - /* If core0 is being turned on, we need to load the FW */ - if (core_id == SKL_DSP_CORE0_ID) { - ret = skl_load_base_firmware(ctx); - if (ret < 0) { - dev_err(ctx->dev, "unable to load firmware\n"); - return ret; - } - - /* load libs as they are also lost on D3 */ - if (skl->lib_count > 1) { - ret = ctx->fw_ops.load_library(ctx, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(ctx->dev, "reload libs failed: %d\n", - ret); - return ret; - } - - } - } - - /* - * If any core other than core 0 is being moved to D0, enable the - * core and send the set dx IPC for the core. - */ - if (core_id != SKL_DSP_CORE0_ID) { - ret = skl_dsp_enable_core(ctx, core_mask); - if (ret < 0) - return ret; - - dx.core_mask = core_mask; - dx.dx_mask = core_mask; - - ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, - SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set dsp to D0:core id= %d\n", - core_id); - skl_dsp_disable_core(ctx, core_mask); - } - } - - skl->cores.state[core_id] = SKL_DSP_RUNNING; - - return 0; -} - -static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) -{ - int ret; - struct skl_ipc_dxstate_info dx; - struct skl_dev *skl = ctx->thread_context; - unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); - - dx.core_mask = core_mask; - dx.dx_mask = SKL_IPC_D3_MASK; - - ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) - dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret); - - if (core_id == SKL_DSP_CORE0_ID) { - /* disable Interrupt */ - ctx->cl_dev.ops.cl_cleanup_controller(ctx); - skl_cldma_int_disable(ctx); - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - } - - ret = skl_dsp_disable_core(ctx, core_mask); - if (ret < 0) - return ret; - - skl->cores.state[core_id] = SKL_DSP_RESET; - return ret; -} - -static unsigned int skl_get_errorcode(struct sst_dsp *ctx) -{ - return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); -} - -/* - * since get/set_module are called from DAPM context, - * we don't need lock for usage count - */ -static int skl_get_module(struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return ++module->usage_cnt; - } - - return -EINVAL; -} - -static int skl_put_module(struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return --module->usage_cnt; - } - - return -EINVAL; -} - -static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx, - char *mod_name, int mod_id) -{ - const struct firmware *fw; - struct skl_module_table *skl_module; - unsigned int size; - int ret; - - ret = request_firmware(&fw, mod_name, ctx->dev); - if (ret < 0) { - dev_err(ctx->dev, "Request Module %s failed :%d\n", - mod_name, ret); - return NULL; - } - - skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL); - if (skl_module == NULL) { - release_firmware(fw); - return NULL; - } - - size = sizeof(*skl_module->mod_info); - skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL); - if (skl_module->mod_info == NULL) { - release_firmware(fw); - return NULL; - } - - skl_module->mod_info->mod_id = mod_id; - skl_module->mod_info->fw = fw; - list_add(&skl_module->list, &ctx->module_list); - - return skl_module; -} - -/* get a module from it's unique ID */ -static struct skl_module_table *skl_module_get_from_id( - struct sst_dsp *ctx, u16 mod_id) -{ - struct skl_module_table *module; - - if (list_empty(&ctx->module_list)) { - dev_err(ctx->dev, "Module list is empty\n"); - return NULL; - } - - list_for_each_entry(module, &ctx->module_list, list) { - if (module->mod_info->mod_id == mod_id) - return module; - } - - return NULL; -} - -static int skl_transfer_module(struct sst_dsp *ctx, const void *data, - u32 size, u16 mod_id, u8 table_id, bool is_module) -{ - int ret, bytes_left, curr_pos; - struct skl_dev *skl = ctx->thread_context; - skl->mod_load_complete = false; - - bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, data, size, false); - if (bytes_left < 0) - return bytes_left; - - /* check is_module flag to load module or library */ - if (is_module) - ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, &mod_id); - else - ret = skl_sst_ipc_load_library(&skl->ipc, 0, table_id, false); - - if (ret < 0) { - dev_err(ctx->dev, "Failed to Load %s with err %d\n", - is_module ? "module" : "lib", ret); - goto out; - } - - /* - * if bytes_left > 0 then wait for BDL complete interrupt and - * copy the next chunk till bytes_left is 0. if bytes_left is - * zero, then wait for load module IPC reply - */ - while (bytes_left > 0) { - curr_pos = size - bytes_left; - - ret = skl_cldma_wait_interruptible(ctx); - if (ret < 0) - goto out; - - bytes_left = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, - data + curr_pos, - bytes_left, false); - } - - ret = wait_event_timeout(skl->mod_load_wait, skl->mod_load_complete, - msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); - if (ret == 0 || !skl->mod_load_status) { - dev_err(ctx->dev, "Module Load failed\n"); - ret = -EIO; - } - -out: - ctx->cl_dev.ops.cl_stop_dma(ctx); - - return ret; -} - -static int -skl_load_library(struct sst_dsp *ctx, struct skl_lib_info *linfo, int lib_count) -{ - struct skl_dev *skl = ctx->thread_context; - struct firmware stripped_fw; - int ret, i; - - /* library indices start from 1 to N. 0 represents base FW */ - for (i = 1; i < lib_count; i++) { - ret = skl_prepare_lib_load(skl, &skl->lib_info[i], &stripped_fw, - SKL_ADSP_FW_BIN_HDR_OFFSET, i); - if (ret < 0) - goto load_library_failed; - ret = skl_transfer_module(ctx, stripped_fw.data, - stripped_fw.size, 0, i, false); - if (ret < 0) - goto load_library_failed; - } - - return 0; - -load_library_failed: - skl_release_library(linfo, lib_count); - return ret; -} - -static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, u8 *guid) -{ - struct skl_module_table *module_entry = NULL; - int ret = 0; - char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ - - snprintf(mod_name, sizeof(mod_name), "intel/dsp_fw_%pUL.bin", guid); - - module_entry = skl_module_get_from_id(ctx, mod_id); - if (module_entry == NULL) { - module_entry = skl_fill_module_table(ctx, mod_name, mod_id); - if (module_entry == NULL) { - dev_err(ctx->dev, "Failed to Load module\n"); - return -EINVAL; - } - } - - if (!module_entry->usage_cnt) { - ret = skl_transfer_module(ctx, module_entry->mod_info->fw->data, - module_entry->mod_info->fw->size, - mod_id, 0, true); - if (ret < 0) { - dev_err(ctx->dev, "Failed to Load module\n"); - return ret; - } - } - - ret = skl_get_module(ctx, mod_id); - - return ret; -} - -static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) -{ - int usage_cnt; - struct skl_dev *skl = ctx->thread_context; - int ret = 0; - - usage_cnt = skl_put_module(ctx, mod_id); - if (usage_cnt < 0) { - dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); - return -EIO; - } - - /* if module is used by others return, no need to unload */ - if (usage_cnt > 0) - return 0; - - ret = skl_ipc_unload_modules(&skl->ipc, - SKL_NUM_MODULES, &mod_id); - if (ret < 0) { - dev_err(ctx->dev, "Failed to UnLoad module\n"); - skl_get_module(ctx, mod_id); - return ret; - } - - return ret; -} - -void skl_clear_module_cnt(struct sst_dsp *ctx) -{ - struct skl_module_table *module; - - if (list_empty(&ctx->module_list)) - return; - - list_for_each_entry(module, &ctx->module_list, list) { - module->usage_cnt = 0; - } -} -EXPORT_SYMBOL_GPL(skl_clear_module_cnt); - -static void skl_clear_module_table(struct sst_dsp *ctx) -{ - struct skl_module_table *module, *tmp; - - if (list_empty(&ctx->module_list)) - return; - - list_for_each_entry_safe(module, tmp, &ctx->module_list, list) { - list_del(&module->list); - release_firmware(module->mod_info->fw); - } -} - -static const struct skl_dsp_fw_ops skl_fw_ops = { - .set_state_D0 = skl_set_dsp_D0, - .set_state_D3 = skl_set_dsp_D3, - .load_fw = skl_load_base_firmware, - .get_fw_errcode = skl_get_errorcode, - .load_library = skl_load_library, - .load_mod = skl_load_module, - .unload_mod = skl_unload_module, -}; - -static struct sst_ops skl_ops = { - .irq_handler = skl_dsp_sst_interrupt, - .write = sst_shim32_write, - .read = sst_shim32_read, - .free = skl_dsp_free, -}; - -static struct sst_dsp_device skl_dev = { - .thread = skl_dsp_irq_thread_handler, - .ops = &skl_ops, -}; - -int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - const char *fw_name, struct skl_dsp_loader_ops dsp_ops, - struct skl_dev **dsp) -{ - struct skl_dev *skl; - struct sst_dsp *sst; - int ret; - - ret = skl_sst_ctx_init(dev, irq, fw_name, dsp_ops, dsp, &skl_dev); - if (ret < 0) { - dev_err(dev, "%s: no device\n", __func__); - return ret; - } - - skl = *dsp; - sst = skl->dsp; - sst->addr.lpe = mmio_base; - sst->addr.shim = mmio_base; - sst->addr.sram0_base = SKL_ADSP_SRAM0_BASE; - sst->addr.sram1_base = SKL_ADSP_SRAM1_BASE; - sst->addr.w0_stat_sz = SKL_ADSP_W0_STAT_SZ; - sst->addr.w0_up_sz = SKL_ADSP_W0_UP_SZ; - - sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), - SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); - - ret = skl_ipc_init(dev, skl); - if (ret) { - skl_dsp_free(sst); - return ret; - } - - sst->fw_ops = skl_fw_ops; - - return skl_dsp_acquire_irq(sst); -} -EXPORT_SYMBOL_GPL(skl_sst_dsp_init); - -int skl_sst_init_fw(struct device *dev, struct skl_dev *skl) -{ - int ret; - struct sst_dsp *sst = skl->dsp; - - ret = sst->fw_ops.load_fw(sst); - if (ret < 0) { - dev_err(dev, "Load base fw failed : %d\n", ret); - return ret; - } - - skl_dsp_init_core_state(sst); - - if (skl->lib_count > 1) { - ret = sst->fw_ops.load_library(sst, skl->lib_info, - skl->lib_count); - if (ret < 0) { - dev_err(dev, "Load Library failed : %x\n", ret); - return ret; - } - } - skl->is_first_boot = false; - - return 0; -} -EXPORT_SYMBOL_GPL(skl_sst_init_fw); - -void skl_sst_dsp_cleanup(struct device *dev, struct skl_dev *skl) -{ - - if (skl->dsp->fw) - release_firmware(skl->dsp->fw); - skl_clear_module_table(skl->dsp); - skl_freeup_uuid_list(skl); - skl_ipc_free(&skl->ipc); - skl->dsp->ops->free(skl->dsp); - if (skl->boot_complete) { - skl->dsp->cl_dev.ops.cl_cleanup_controller(skl->dsp); - skl_cldma_int_disable(skl->dsp); - } -} -EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Skylake IPC driver"); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c deleted file mode 100644 index 96cfebded072..000000000000 --- a/sound/soc/intel/skylake/skl-topology.c +++ /dev/null @@ -1,3774 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl-topology.c - Implements Platform component ALSA controls/widget - * handlers. - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/firmware.h> -#include <linux/uuid.h> -#include <sound/intel-nhlt.h> -#include <sound/soc.h> -#include <sound/soc-acpi.h> -#include <sound/soc-topology.h> -#include <uapi/sound/snd_sst_tokens.h> -#include <uapi/sound/skl-tplg-interface.h> -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" -#include "skl-topology.h" -#include "skl.h" -#include "../common/sst-dsp.h" -#include "../common/sst-dsp-priv.h" - -#define SKL_CH_FIXUP_MASK (1 << 0) -#define SKL_RATE_FIXUP_MASK (1 << 1) -#define SKL_FMT_FIXUP_MASK (1 << 2) -#define SKL_IN_DIR_BIT_MASK BIT(0) -#define SKL_PIN_COUNT_MASK GENMASK(7, 4) - -static const int mic_mono_list[] = { -0, 1, 2, 3, -}; -static const int mic_stereo_list[][SKL_CH_STEREO] = { -{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}, -}; -static const int mic_trio_list[][SKL_CH_TRIO] = { -{0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3}, -}; -static const int mic_quatro_list[][SKL_CH_QUATRO] = { -{0, 1, 2, 3}, -}; - -#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \ - ((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq)) - -void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3++; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming++; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming++; - break; - } -} - -void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps) -{ - struct skl_d0i3_data *d0i3 = &skl->d0i3; - - switch (caps) { - case SKL_D0I3_NONE: - d0i3->non_d0i3--; - break; - - case SKL_D0I3_STREAMING: - d0i3->streaming--; - break; - - case SKL_D0I3_NON_STREAMING: - d0i3->non_streaming--; - break; - } -} - -/* - * SKL DSP driver modelling uses only few DAPM widgets so for rest we will - * ignore. This helpers checks if the SKL driver handles this widget type - */ -static int is_skl_dsp_widget_type(struct snd_soc_dapm_widget *w, - struct device *dev) -{ - if (w->dapm->dev != dev) - return false; - - switch (w->id) { - case snd_soc_dapm_dai_link: - case snd_soc_dapm_dai_in: - case snd_soc_dapm_aif_in: - case snd_soc_dapm_aif_out: - case snd_soc_dapm_dai_out: - case snd_soc_dapm_switch: - case snd_soc_dapm_output: - case snd_soc_dapm_mux: - - return false; - default: - return true; - } -} - -static void skl_dump_mconfig(struct skl_dev *skl, struct skl_module_cfg *mcfg) -{ - struct skl_module_iface *iface = &mcfg->module->formats[mcfg->fmt_idx]; - - dev_dbg(skl->dev, "Dumping config\n"); - dev_dbg(skl->dev, "Input Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->inputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->inputs[0].fmt.s_freq); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->inputs[0].fmt.ch_cfg); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->inputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "Output Format:\n"); - dev_dbg(skl->dev, "channels = %d\n", iface->outputs[0].fmt.channels); - dev_dbg(skl->dev, "s_freq = %d\n", iface->outputs[0].fmt.s_freq); - dev_dbg(skl->dev, "valid bit depth = %d\n", - iface->outputs[0].fmt.valid_bit_depth); - dev_dbg(skl->dev, "ch_cfg = %d\n", iface->outputs[0].fmt.ch_cfg); -} - -static void skl_tplg_update_chmap(struct skl_module_fmt *fmt, int chs) -{ - int slot_map = 0xFFFFFFFF; - int start_slot = 0; - int i; - - for (i = 0; i < chs; i++) { - /* - * For 2 channels with starting slot as 0, slot map will - * look like 0xFFFFFF10. - */ - slot_map &= (~(0xF << (4 * i)) | (start_slot << (4 * i))); - start_slot++; - } - fmt->ch_map = slot_map; -} - -static void skl_tplg_update_params(struct skl_module_fmt *fmt, - struct skl_pipe_params *params, int fixup) -{ - if (fixup & SKL_RATE_FIXUP_MASK) - fmt->s_freq = params->s_freq; - if (fixup & SKL_CH_FIXUP_MASK) { - fmt->channels = params->ch; - skl_tplg_update_chmap(fmt, fmt->channels); - } - if (fixup & SKL_FMT_FIXUP_MASK) { - fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); - - /* - * 16 bit is 16 bit container whereas 24 bit is in 32 bit - * container so update bit depth accordingly - */ - switch (fmt->valid_bit_depth) { - case SKL_DEPTH_16BIT: - fmt->bit_depth = fmt->valid_bit_depth; - break; - - default: - fmt->bit_depth = SKL_DEPTH_32BIT; - break; - } - } - -} - -/* - * A pipeline may have modules which impact the pcm parameters, like SRC, - * channel converter, format converter. - * We need to calculate the output params by applying the 'fixup' - * Topology will tell driver which type of fixup is to be applied by - * supplying the fixup mask, so based on that we calculate the output - * - * Now In FE the pcm hw_params is source/target format. Same is applicable - * for BE with its hw_params invoked. - * here based on FE, BE pipeline and direction we calculate the input and - * outfix and then apply that for a module - */ -static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, - struct skl_pipe_params *params, bool is_fe) -{ - int in_fixup, out_fixup; - struct skl_module_fmt *in_fmt, *out_fmt; - - /* Fixups will be applied to pin 0 only */ - in_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].inputs[0].fmt; - out_fmt = &m_cfg->module->formats[m_cfg->fmt_idx].outputs[0].fmt; - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - if (is_fe) { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } else { - if (is_fe) { - out_fixup = m_cfg->params_fixup; - in_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } else { - in_fixup = m_cfg->params_fixup; - out_fixup = (~m_cfg->converter) & - m_cfg->params_fixup; - } - } - - skl_tplg_update_params(in_fmt, params, in_fixup); - skl_tplg_update_params(out_fmt, params, out_fixup); -} - -/* - * A module needs input and output buffers, which are dependent upon pcm - * params, so once we have calculate params, we need buffer calculation as - * well. - */ -static void skl_tplg_update_buffer_size(struct skl_dev *skl, - struct skl_module_cfg *mcfg) -{ - int multiplier = 1; - struct skl_module_fmt *in_fmt, *out_fmt; - struct skl_module_res *res; - - /* Since fixups is applied to pin 0 only, ibs, obs needs - * change for pin 0 only - */ - res = &mcfg->module->resources[mcfg->res_idx]; - in_fmt = &mcfg->module->formats[mcfg->fmt_idx].inputs[0].fmt; - out_fmt = &mcfg->module->formats[mcfg->fmt_idx].outputs[0].fmt; - - if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) - multiplier = 5; - - res->ibs = DIV_ROUND_UP(in_fmt->s_freq, 1000) * - in_fmt->channels * (in_fmt->bit_depth >> 3) * - multiplier; - - res->obs = DIV_ROUND_UP(out_fmt->s_freq, 1000) * - out_fmt->channels * (out_fmt->bit_depth >> 3) * - multiplier; -} - -static u8 skl_tplg_be_dev_type(int dev_type) -{ - int ret; - - switch (dev_type) { - case SKL_DEVICE_BT: - ret = NHLT_DEVICE_BT; - break; - - case SKL_DEVICE_DMIC: - ret = NHLT_DEVICE_DMIC; - break; - - case SKL_DEVICE_I2S: - ret = NHLT_DEVICE_I2S; - break; - - default: - ret = NHLT_DEVICE_INVALID; - break; - } - - return ret; -} - -static int skl_tplg_update_be_blob(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - int link_type, dir; - u32 ch, s_freq, s_fmt, s_cont; - struct nhlt_specific_cfg *cfg; - u8 dev_type = skl_tplg_be_dev_type(m_cfg->dev_type); - int fmt_idx = m_cfg->fmt_idx; - struct skl_module_iface *m_iface = &m_cfg->module->formats[fmt_idx]; - - /* check if we already have blob */ - if (m_cfg->formats_config[SKL_PARAM_INIT].caps_size > 0) - return 0; - - dev_dbg(skl->dev, "Applying default cfg blob\n"); - switch (m_cfg->dev_type) { - case SKL_DEVICE_DMIC: - link_type = NHLT_LINK_DMIC; - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - break; - - case SKL_DEVICE_I2S: - link_type = NHLT_LINK_SSP; - if (m_cfg->hw_conn_type == SKL_CONN_SOURCE) { - dir = SNDRV_PCM_STREAM_PLAYBACK; - s_freq = m_iface->outputs[0].fmt.s_freq; - s_fmt = m_iface->outputs[0].fmt.valid_bit_depth; - s_cont = m_iface->outputs[0].fmt.bit_depth; - ch = m_iface->outputs[0].fmt.channels; - } else { - dir = SNDRV_PCM_STREAM_CAPTURE; - s_freq = m_iface->inputs[0].fmt.s_freq; - s_fmt = m_iface->inputs[0].fmt.valid_bit_depth; - s_cont = m_iface->inputs[0].fmt.bit_depth; - ch = m_iface->inputs[0].fmt.channels; - } - break; - - default: - return -EINVAL; - } - - /* update the blob based on virtual bus_id and default params */ - cfg = intel_nhlt_get_endpoint_blob(skl->dev, skl->nhlt, m_cfg->vbus_id, - link_type, s_fmt, s_cont, ch, - s_freq, dir, dev_type); - if (cfg) { - m_cfg->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; - m_cfg->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; - } else { - dev_err(skl->dev, "Blob NULL for id %x type %d dirn %d\n", - m_cfg->vbus_id, link_type, dir); - dev_err(skl->dev, "PCM: ch %d, freq %d, fmt %d/%d\n", - ch, s_freq, s_fmt, s_cont); - return -EIO; - } - - return 0; -} - -static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *m_cfg = w->priv; - struct skl_pipe_params *params = m_cfg->pipe->p_params; - int p_conn_type = m_cfg->pipe->conn_type; - bool is_fe; - - if (!m_cfg->params_fixup) - return; - - dev_dbg(skl->dev, "Mconfig for widget=%s BEFORE updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); - - if (p_conn_type == SKL_PIPE_CONN_TYPE_FE) - is_fe = true; - else - is_fe = false; - - skl_tplg_update_params_fixup(m_cfg, params, is_fe); - skl_tplg_update_buffer_size(skl, m_cfg); - - dev_dbg(skl->dev, "Mconfig for widget=%s AFTER updation\n", - w->name); - - skl_dump_mconfig(skl, m_cfg); -} - -/* - * some modules can have multiple params set from user control and - * need to be set after module is initialized. If set_param flag is - * set module params will be done after module is initialised. - */ -static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - - if (mconfig->formats_config[SKL_PARAM_SET].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_SET].set_params == SKL_PARAM_SET) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_SET]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_SET) { - ret = skl_set_module_params(skl, - (u32 *)bc->params, bc->size, - bc->param_id, mconfig); - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -/* - * some module param can set from user control and this is required as - * when module is initailzed. if module param is required in init it is - * identifed by set_param flag. if set_param flag is not set, then this - * parameter needs to set as part of module init. - */ -static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) -{ - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_module_cfg *mconfig = w->priv; - int i; - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (struct soc_bytes_ext *)k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params != SKL_PARAM_INIT) - continue; - - mconfig->formats_config[SKL_PARAM_INIT].caps = - (u32 *)bc->params; - mconfig->formats_config[SKL_PARAM_INIT].caps_size = - bc->size; - - break; - } - } - - return 0; -} - -static int skl_tplg_module_prepare(struct skl_dev *skl, struct skl_pipe *pipe, - struct snd_soc_dapm_widget *w, struct skl_module_cfg *mcfg) -{ - switch (mcfg->dev_type) { - case SKL_DEVICE_HDAHOST: - return skl_pcm_host_dma_prepare(skl->dev, pipe->p_params); - - case SKL_DEVICE_HDALINK: - return skl_pcm_link_dma_prepare(skl->dev, pipe->p_params); - } - - return 0; -} - -/* - * Inside a pipe instance, we can have various modules. These modules need - * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by - * skl_init_module() routine, so invoke that for all modules in a pipeline - */ -static int -skl_tplg_init_pipe_modules(struct skl_dev *skl, struct skl_pipe *pipe) -{ - struct skl_pipe_module *w_module; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - u8 cfg_idx; - int ret = 0; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - w = w_module->w; - mconfig = w->priv; - - /* check if module ids are populated */ - if (mconfig->id.module_id < 0) { - dev_err(skl->dev, - "module %pUL id not populated\n", - (guid_t *)mconfig->guid); - return -EIO; - } - - cfg_idx = mconfig->pipe->cur_config_idx; - mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; - mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - - if (mconfig->module->loadable && skl->dsp->fw_ops.load_mod) { - ret = skl->dsp->fw_ops.load_mod(skl->dsp, - mconfig->id.module_id, mconfig->guid); - if (ret < 0) - return ret; - } - - /* prepare the DMA if the module is gateway cpr */ - ret = skl_tplg_module_prepare(skl, pipe, w, mconfig); - if (ret < 0) - return ret; - - /* update blob if blob is null for be with default value */ - skl_tplg_update_be_blob(w, skl); - - /* - * apply fix/conversion to module params based on - * FE/BE params - */ - skl_tplg_update_module_params(w, skl); - uuid_mod = (guid_t *)mconfig->guid; - mconfig->id.pvt_id = skl_get_pvt_id(skl, uuid_mod, - mconfig->id.instance_id); - if (mconfig->id.pvt_id < 0) - return ret; - skl_tplg_set_module_init_data(w); - - ret = skl_dsp_get_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - dev_err(skl->dev, "Failed to wake up core %d ret=%d\n", - mconfig->core_id, ret); - return ret; - } - - ret = skl_init_module(skl, mconfig); - if (ret < 0) { - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - goto err; - } - - ret = skl_tplg_set_module_params(w, skl); - if (ret < 0) - goto err; - } - - return 0; -err: - skl_dsp_put_core(skl->dsp, mconfig->core_id); - return ret; -} - -static int skl_tplg_unload_pipe_modules(struct skl_dev *skl, - struct skl_pipe *pipe) -{ - int ret = 0; - struct skl_pipe_module *w_module; - struct skl_module_cfg *mconfig; - - list_for_each_entry(w_module, &pipe->w_list, node) { - guid_t *uuid_mod; - mconfig = w_module->w->priv; - uuid_mod = (guid_t *)mconfig->guid; - - if (mconfig->module->loadable && skl->dsp->fw_ops.unload_mod) { - ret = skl->dsp->fw_ops.unload_mod(skl->dsp, - mconfig->id.module_id); - if (ret < 0) - return -EIO; - } - skl_put_pvt_id(skl, uuid_mod, &mconfig->id.pvt_id); - - ret = skl_dsp_put_core(skl->dsp, mconfig->core_id); - if (ret < 0) { - /* don't return; continue with other modules */ - dev_err(skl->dev, "Failed to sleep core %d ret=%d\n", - mconfig->core_id, ret); - } - } - - /* no modules to unload in this path, so return */ - return ret; -} - -static void skl_tplg_set_pipe_config_idx(struct skl_pipe *pipe, int idx) -{ - pipe->cur_config_idx = idx; - pipe->memory_pages = pipe->configs[idx].mem_pages; -} - -/* - * Here, we select pipe format based on the pipe type and pipe - * direction to determine the current config index for the pipeline. - * The config index is then used to select proper module resources. - * Intermediate pipes currently have a fixed format hence we select the - * 0th configuratation by default for such pipes. - */ -static int -skl_tplg_get_pipe_config(struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - struct skl_pipe *pipe = mconfig->pipe; - struct skl_pipe_params *params = pipe->p_params; - struct skl_path_config *pconfig = &pipe->configs[0]; - struct skl_pipe_fmt *fmt = NULL; - bool in_fmt = false; - int i; - - if (pipe->nr_cfgs == 0) { - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE || pipe->nr_cfgs == 1) { - dev_dbg(skl->dev, "No conn_type or just 1 pathcfg, taking 0th for %d\n", - pipe->ppl_id); - skl_tplg_set_pipe_config_idx(pipe, 0); - return 0; - } - - if ((pipe->conn_type == SKL_PIPE_CONN_TYPE_FE && - pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) || - (pipe->conn_type == SKL_PIPE_CONN_TYPE_BE && - pipe->direction == SNDRV_PCM_STREAM_CAPTURE)) - in_fmt = true; - - for (i = 0; i < pipe->nr_cfgs; i++) { - pconfig = &pipe->configs[i]; - if (in_fmt) - fmt = &pconfig->in_fmt; - else - fmt = &pconfig->out_fmt; - - if (CHECK_HW_PARAMS(params->ch, params->s_freq, params->s_fmt, - fmt->channels, fmt->freq, fmt->bps)) { - skl_tplg_set_pipe_config_idx(pipe, i); - dev_dbg(skl->dev, "Using pipe config: %d\n", i); - return 0; - } - } - - dev_err(skl->dev, "Invalid pipe config: %d %d %d for pipe: %d\n", - params->ch, params->s_freq, params->s_fmt, pipe->ppl_id); - return -EINVAL; -} - -/* - * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we - * need create the pipeline. So we do following: - * - Create the pipeline - * - Initialize the modules in pipeline - * - finally bind all modules together - */ -static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret; - struct skl_module_cfg *mconfig = w->priv; - struct skl_pipe_module *w_module; - struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_cfg *src_module = NULL, *dst_module, *module; - struct skl_module_deferred_bind *modules; - - ret = skl_tplg_get_pipe_config(skl, mconfig); - if (ret < 0) - return ret; - - /* - * Create a list of modules for pipe. - * This list contains modules from source to sink - */ - ret = skl_create_pipeline(skl, mconfig->pipe); - if (ret < 0) - return ret; - - /* Init all pipe modules from source to sink */ - ret = skl_tplg_init_pipe_modules(skl, s_pipe); - if (ret < 0) - return ret; - - /* Bind modules from source to sink */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - dst_module = w_module->w->priv; - - if (src_module == NULL) { - src_module = dst_module; - continue; - } - - ret = skl_bind_modules(skl, src_module, dst_module); - if (ret < 0) - return ret; - - src_module = dst_module; - } - - /* - * When the destination module is initialized, check for these modules - * in deferred bind list. If found, bind them. - */ - list_for_each_entry(w_module, &s_pipe->w_list, node) { - if (list_empty(&skl->bind_list)) - break; - - list_for_each_entry(modules, &skl->bind_list, node) { - module = w_module->w->priv; - if (modules->dst == module) - skl_bind_modules(skl, modules->src, - modules->dst); - } - } - - return 0; -} - -static int skl_fill_sink_instance_id(struct skl_dev *skl, u32 *params, - int size, struct skl_module_cfg *mcfg) -{ - int i, pvt_id; - - if (mcfg->m_type == SKL_MODULE_TYPE_KPB) { - struct skl_kpb_params *kpb_params = - (struct skl_kpb_params *)params; - struct skl_mod_inst_map *inst = kpb_params->u.map; - - for (i = 0; i < kpb_params->num_modules; i++) { - pvt_id = skl_get_pvt_instance_id_map(skl, inst->mod_id, - inst->inst_id); - if (pvt_id < 0) - return -EINVAL; - - inst->inst_id = pvt_id; - inst++; - } - } - - return 0; -} -/* - * Some modules require params to be set after the module is bound to - * all pins connected. - * - * The module provider initializes set_param flag for such modules and we - * send params after binding - */ -static int skl_tplg_set_module_bind_params(struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mcfg, struct skl_dev *skl) -{ - int i, ret; - struct skl_module_cfg *mconfig = w->priv; - const struct snd_kcontrol_new *k; - struct soc_bytes_ext *sb; - struct skl_algo_data *bc; - struct skl_specific_cfg *sp_cfg; - u32 *params; - - /* - * check all out/in pins are in bind state. - * if so set the module param - */ - for (i = 0; i < mcfg->module->max_output_pins; i++) { - if (mcfg->m_out_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - for (i = 0; i < mcfg->module->max_input_pins; i++) { - if (mcfg->m_in_pin[i].pin_state != SKL_PIN_BIND_DONE) - return 0; - } - - if (mconfig->formats_config[SKL_PARAM_BIND].caps_size > 0 && - mconfig->formats_config[SKL_PARAM_BIND].set_params == - SKL_PARAM_BIND) { - sp_cfg = &mconfig->formats_config[SKL_PARAM_BIND]; - ret = skl_set_module_params(skl, sp_cfg->caps, - sp_cfg->caps_size, - sp_cfg->param_id, mconfig); - if (ret < 0) - return ret; - } - - for (i = 0; i < w->num_kcontrols; i++) { - k = &w->kcontrol_news[i]; - if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (void *) k->private_value; - bc = (struct skl_algo_data *)sb->dobj.private; - - if (bc->set_params == SKL_PARAM_BIND) { - params = kmemdup(bc->params, bc->max, GFP_KERNEL); - if (!params) - return -ENOMEM; - - skl_fill_sink_instance_id(skl, params, bc->max, - mconfig); - - ret = skl_set_module_params(skl, params, - bc->max, bc->param_id, mconfig); - kfree(params); - - if (ret < 0) - return ret; - } - } - } - - return 0; -} - -static int skl_get_module_id(struct skl_dev *skl, guid_t *uuid) -{ - struct uuid_module *module; - - list_for_each_entry(module, &skl->uuid_list, list) { - if (guid_equal(uuid, &module->uuid)) - return module->id; - } - - return -EINVAL; -} - -static int skl_tplg_find_moduleid_from_uuid(struct skl_dev *skl, - const struct snd_kcontrol_new *k) -{ - struct soc_bytes_ext *sb = (void *) k->private_value; - struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; - struct skl_kpb_params *uuid_params, *params; - struct hdac_bus *bus = skl_to_bus(skl); - int i, size, module_id; - - if (bc->set_params == SKL_PARAM_BIND && bc->max) { - uuid_params = (struct skl_kpb_params *)bc->params; - size = struct_size(params, u.map, uuid_params->num_modules); - - params = devm_kzalloc(bus->dev, size, GFP_KERNEL); - if (!params) - return -ENOMEM; - - params->num_modules = uuid_params->num_modules; - - for (i = 0; i < uuid_params->num_modules; i++) { - module_id = skl_get_module_id(skl, - &uuid_params->u.map_uuid[i].mod_uuid); - if (module_id < 0) { - devm_kfree(bus->dev, params); - return -EINVAL; - } - - params->u.map[i].mod_id = module_id; - params->u.map[i].inst_id = - uuid_params->u.map_uuid[i].inst_id; - } - - devm_kfree(bus->dev, bc->params); - bc->params = (char *)params; - bc->max = size; - } - - return 0; -} - -/* - * Retrieve the module id from UUID mentioned in the - * post bind params - */ -void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, - struct snd_soc_dapm_widget *w) -{ - struct skl_module_cfg *mconfig = w->priv; - int i; - - /* - * Post bind params are used for only for KPB - * to set copier instances to drain the data - * in fast mode - */ - if (mconfig->m_type != SKL_MODULE_TYPE_KPB) - return; - - for (i = 0; i < w->num_kcontrols; i++) - if ((w->kcontrol_news[i].access & - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) && - (skl_tplg_find_moduleid_from_uuid(skl, - &w->kcontrol_news[i]) < 0)) - dev_err(skl->dev, - "%s: invalid kpb post bind params\n", - __func__); -} - -static int skl_tplg_module_add_deferred_bind(struct skl_dev *skl, - struct skl_module_cfg *src, struct skl_module_cfg *dst) -{ - struct skl_module_deferred_bind *m_list, *modules; - int i; - - /* only supported for module with static pin connection */ - for (i = 0; i < dst->module->max_input_pins; i++) { - struct skl_module_pin *pin = &dst->m_in_pin[i]; - - if (pin->is_dynamic) - continue; - - if ((pin->id.module_id == src->id.module_id) && - (pin->id.instance_id == src->id.instance_id)) { - - if (!list_empty(&skl->bind_list)) { - list_for_each_entry(modules, &skl->bind_list, node) { - if (modules->src == src && modules->dst == dst) - return 0; - } - } - - m_list = kzalloc(sizeof(*m_list), GFP_KERNEL); - if (!m_list) - return -ENOMEM; - - m_list->src = src; - m_list->dst = dst; - - list_add(&m_list->node, &skl->bind_list); - } - } - - return 0; -} - -static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, - struct skl_dev *skl, - struct snd_soc_dapm_widget *src_w, - struct skl_module_cfg *src_mconfig) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; - struct skl_module_cfg *sink_mconfig; - int ret; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (!p->connect) - continue; - - dev_dbg(skl->dev, - "%s: src widget=%s\n", __func__, w->name); - dev_dbg(skl->dev, - "%s: sink widget=%s\n", __func__, p->sink->name); - - next_sink = p->sink; - - if (!is_skl_dsp_widget_type(p->sink, skl->dev)) - return skl_tplg_bind_sinks(p->sink, skl, src_w, src_mconfig); - - /* - * here we will check widgets in sink pipelines, so that - * can be any widgets type and we are only interested if - * they are ones used for SKL so check that first - */ - if ((p->sink->priv != NULL) && - is_skl_dsp_widget_type(p->sink, skl->dev)) { - - sink = p->sink; - sink_mconfig = sink->priv; - - /* - * Modules other than PGA leaf can be connected - * directly or via switch to a module in another - * pipeline. EX: reference path - * when the path is enabled, the dst module that needs - * to be bound may not be initialized. if the module is - * not initialized, add these modules in the deferred - * bind list and when the dst module is initialised, - * bind this module to the dst_module in deferred list. - */ - if (((src_mconfig->m_state == SKL_MODULE_INIT_DONE) - && (sink_mconfig->m_state == SKL_MODULE_UNINIT))) { - - ret = skl_tplg_module_add_deferred_bind(skl, - src_mconfig, sink_mconfig); - - if (ret < 0) - return ret; - - } - - - if (src_mconfig->m_state == SKL_MODULE_UNINIT || - sink_mconfig->m_state == SKL_MODULE_UNINIT) - continue; - - /* Bind source to sink, mixin is always source */ - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(src_w, - src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, - sink_mconfig, skl); - - /* Start sinks pipe first */ - if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { - if (sink_mconfig->pipe->conn_type != - SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, - sink_mconfig->pipe); - if (ret) - return ret; - } - } - } - - if (!sink && next_sink) - return skl_tplg_bind_sinks(next_sink, skl, src_w, src_mconfig); - - return 0; -} - -/* - * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA - * we need to do following: - * - Bind to sink pipeline - * Since the sink pipes can be running and we don't get mixer event on - * connect for already running mixer, we need to find the sink pipes - * here and bind to them. This way dynamic connect works. - * - Start sink pipeline, if not running - * - Then run current pipe - */ -static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig; - int ret = 0; - - src_mconfig = w->priv; - - /* - * find which sink it is connected to, bind with the sink, - * if sink is not started, start sink pipe first, then start - * this pipe - */ - ret = skl_tplg_bind_sinks(w, skl, w, src_mconfig); - if (ret) - return ret; - - /* Start source pipe last after starting all sinks */ - if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - return skl_run_pipe(skl, src_mconfig->pipe); - - return 0; -} - -static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( - struct snd_soc_dapm_widget *w, struct skl_dev *skl) -{ - struct snd_soc_dapm_path *p; - struct snd_soc_dapm_widget *src_w = NULL; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - src_w = p->source; - if (!p->connect) - continue; - - dev_dbg(skl->dev, "sink widget=%s\n", w->name); - dev_dbg(skl->dev, "src widget=%s\n", p->source->name); - - /* - * here we will check widgets in sink pipelines, so that can - * be any widgets type and we are only interested if they are - * ones used for SKL so check that first - */ - if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source, skl->dev)) { - return p->source; - } - } - - if (src_w != NULL) - return skl_get_src_dsp_widget(src_w, skl); - - return NULL; -} - -/* - * in the Post-PMU event of mixer we need to do following: - * - Check if this pipe is running - * - if not, then - * - bind this pipeline to its source pipeline - * if source pipe is already running, this means it is a dynamic - * connection and we need to bind only to that pipe - * - start this pipeline - */ -static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - int ret = 0; - struct snd_soc_dapm_widget *source, *sink; - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int src_pipe_started = 0; - - sink = w; - sink_mconfig = sink->priv; - - /* - * If source pipe is already started, that means source is driving - * one more sink before this sink got connected, Since source is - * started, bind this sink to source and start this pipe. - */ - source = skl_get_src_dsp_widget(w, skl); - if (source != NULL) { - src_mconfig = source->priv; - sink_mconfig = sink->priv; - src_pipe_started = 1; - - /* - * check pipe state, then no need to bind or start the - * pipe - */ - if (src_mconfig->pipe->state != SKL_PIPE_STARTED) - src_pipe_started = 0; - } - - if (src_pipe_started) { - ret = skl_bind_modules(skl, src_mconfig, sink_mconfig); - if (ret) - return ret; - - /* set module params after bind */ - skl_tplg_set_module_bind_params(source, src_mconfig, skl); - skl_tplg_set_module_bind_params(sink, sink_mconfig, skl); - - if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) - ret = skl_run_pipe(skl, sink_mconfig->pipe); - } - - return ret; -} - -/* - * in the Pre-PMD event of mixer we need to do following: - * - Stop the pipe - * - find the source connections and remove that from dapm_path_list - * - unbind with source pipelines if still connected - */ -static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, i; - - sink_mconfig = w->priv; - - /* Stop the pipe */ - ret = skl_stop_pipe(skl, sink_mconfig->pipe); - if (ret) - return ret; - - for (i = 0; i < sink_mconfig->module->max_input_pins; i++) { - if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { - src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; - if (!src_mconfig) - continue; - - ret = skl_unbind_modules(skl, - src_mconfig, sink_mconfig); - } - } - - return ret; -} - -/* - * in the Post-PMD event of mixer we need to do following: - * - Unbind the modules within the pipeline - * - Delete the pipeline (modules are not required to be explicitly - * deleted, pipeline delete is enough here - */ -static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *mconfig = w->priv; - struct skl_pipe_module *w_module; - struct skl_module_cfg *src_module = NULL, *dst_module; - struct skl_pipe *s_pipe = mconfig->pipe; - struct skl_module_deferred_bind *modules, *tmp; - - if (s_pipe->state == SKL_PIPE_INVALID) - return -EINVAL; - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - if (list_empty(&skl->bind_list)) - break; - - src_module = w_module->w->priv; - - list_for_each_entry_safe(modules, tmp, &skl->bind_list, node) { - /* - * When the destination module is deleted, Unbind the - * modules from deferred bind list. - */ - if (modules->dst == src_module) { - skl_unbind_modules(skl, modules->src, - modules->dst); - } - - /* - * When the source module is deleted, remove this entry - * from the deferred bind list. - */ - if (modules->src == src_module) { - list_del(&modules->node); - modules->src = NULL; - modules->dst = NULL; - kfree(modules); - } - } - } - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - dst_module = w_module->w->priv; - - if (src_module == NULL) { - src_module = dst_module; - continue; - } - - skl_unbind_modules(skl, src_module, dst_module); - src_module = dst_module; - } - - skl_delete_pipe(skl, mconfig->pipe); - - list_for_each_entry(w_module, &s_pipe->w_list, node) { - src_module = w_module->w->priv; - src_module->m_state = SKL_MODULE_UNINIT; - } - - return skl_tplg_unload_pipe_modules(skl, s_pipe); -} - -/* - * in the Post-PMD event of PGA we need to do following: - * - Stop the pipeline - * - In source pipe is connected, unbind with source pipelines - */ -static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, - struct skl_dev *skl) -{ - struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, i; - - src_mconfig = w->priv; - - /* Stop the pipe since this is a mixin module */ - ret = skl_stop_pipe(skl, src_mconfig->pipe); - if (ret) - return ret; - - for (i = 0; i < src_mconfig->module->max_output_pins; i++) { - if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { - sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; - if (!sink_mconfig) - continue; - /* - * This is a connecter and if path is found that means - * unbind between source and sink has not happened yet - */ - ret = skl_unbind_modules(skl, src_mconfig, - sink_mconfig); - } - } - - return ret; -} - -/* - * In modelling, we assume there will be ONLY one mixer in a pipeline. If a - * second one is required that is created as another pipe entity. - * The mixer is responsible for pipe management and represent a pipeline - * instance - */ -static int skl_tplg_mixer_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl_dev *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_mixer_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMU: - return skl_tplg_mixer_dapm_post_pmu_event(w, skl); - - case SND_SOC_DAPM_PRE_PMD: - return skl_tplg_mixer_dapm_pre_pmd_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_mixer_dapm_post_pmd_event(w, skl); - } - - return 0; -} - -/* - * In modelling, we assumed rest of the modules in pipeline are PGA. But we - * are interested in last PGA (leaf PGA) in a pipeline to disconnect with - * the sink when it is running (two FE to one BE or one FE to two BE) - * scenarios - */ -static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *k, int event) - -{ - struct snd_soc_dapm_context *dapm = w->dapm; - struct skl_dev *skl = get_skl_ctx(dapm->dev); - - switch (event) { - case SND_SOC_DAPM_PRE_PMU: - return skl_tplg_pga_dapm_pre_pmu_event(w, skl); - - case SND_SOC_DAPM_POST_PMD: - return skl_tplg_pga_dapm_post_pmd_event(w, skl); - } - - return 0; -} - -static int skl_tplg_multi_config_set_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - bool is_set) -{ - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct hdac_bus *bus = snd_soc_component_get_drvdata(component); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl; - struct skl_pipe *pipe = NULL; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 *pipe_id; - - if (!ec) - return -EINVAL; - - if (is_set && ucontrol->value.enumerated.item[0] > ec->items) - return -EINVAL; - - pipe_id = ec->dobj.private; - - list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == *pipe_id) { - pipe = ppl->pipe; - break; - } - } - if (!pipe) - return -EIO; - - if (is_set) - skl_tplg_set_pipe_config_idx(pipe, ucontrol->value.enumerated.item[0]); - else - ucontrol->value.enumerated.item[0] = pipe->cur_config_idx; - - return 0; -} - -static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); -} - -static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); -} - -static int skl_tplg_multi_config_get_dmic(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, false); -} - -static int skl_tplg_multi_config_set_dmic(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return skl_tplg_multi_config_set_get(kcontrol, ucontrol, true); -} - -static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, - unsigned int __user *data, unsigned int size) -{ - struct soc_bytes_ext *sb = - (struct soc_bytes_ext *)kcontrol->private_value; - struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct skl_dev *skl = get_skl_ctx(w->dapm->dev); - - if (w->power) - skl_get_module_params(skl, (u32 *)bc->params, - bc->size, bc->param_id, mconfig); - - /* decrement size for TLV header */ - size -= 2 * sizeof(u32); - - /* check size as we don't want to send kernel data */ - if (size > bc->max) - size = bc->max; - - if (bc->params) { - if (copy_to_user(data, &bc->param_id, sizeof(u32))) - return -EFAULT; - if (copy_to_user(data + 1, &size, sizeof(u32))) - return -EFAULT; - if (copy_to_user(data + 2, bc->params, size)) - return -EFAULT; - } - - return 0; -} - -#define SKL_PARAM_VENDOR_ID 0xff - -static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, - const unsigned int __user *data, unsigned int size) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct soc_bytes_ext *sb = - (struct soc_bytes_ext *)kcontrol->private_value; - struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; - struct skl_dev *skl = get_skl_ctx(w->dapm->dev); - - if (ac->params) { - if (size > ac->max) - return -EINVAL; - ac->size = size; - - if (copy_from_user(ac->params, data, size)) - return -EFAULT; - - if (w->power) - return skl_set_module_params(skl, - (u32 *)ac->params, ac->size, - ac->param_id, mconfig); - } - - return 0; -} - -static int skl_tplg_mic_control_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 ch_type = *((u32 *)ec->dobj.private); - - if (mconfig->dmic_ch_type == ch_type) - ucontrol->value.enumerated.item[0] = - mconfig->dmic_ch_combo_index; - else - ucontrol->value.enumerated.item[0] = 0; - - return 0; -} - -static int skl_fill_mic_sel_params(struct skl_module_cfg *mconfig, - struct skl_mic_sel_config *mic_cfg, struct device *dev) -{ - struct skl_specific_cfg *sp_cfg = - &mconfig->formats_config[SKL_PARAM_INIT]; - - sp_cfg->caps_size = sizeof(struct skl_mic_sel_config); - sp_cfg->set_params = SKL_PARAM_SET; - sp_cfg->param_id = 0x00; - if (!sp_cfg->caps) { - sp_cfg->caps = devm_kzalloc(dev, sp_cfg->caps_size, GFP_KERNEL); - if (!sp_cfg->caps) - return -ENOMEM; - } - - mic_cfg->mic_switch = SKL_MIC_SEL_SWITCH; - mic_cfg->flags = 0; - memcpy(sp_cfg->caps, mic_cfg, sp_cfg->caps_size); - - return 0; -} - -static int skl_tplg_mic_control_set(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); - struct skl_module_cfg *mconfig = w->priv; - struct skl_mic_sel_config mic_cfg = {0}; - struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; - u32 ch_type = *((u32 *)ec->dobj.private); - const int *list; - u8 in_ch, out_ch, index; - - mconfig->dmic_ch_type = ch_type; - mconfig->dmic_ch_combo_index = ucontrol->value.enumerated.item[0]; - - /* enum control index 0 is INVALID, so no channels to be set */ - if (mconfig->dmic_ch_combo_index == 0) - return 0; - - /* No valid channel selection map for index 0, so offset by 1 */ - index = mconfig->dmic_ch_combo_index - 1; - - switch (ch_type) { - case SKL_CH_MONO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_mono_list)) - return -EINVAL; - - list = &mic_mono_list[index]; - break; - - case SKL_CH_STEREO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_stereo_list)) - return -EINVAL; - - list = mic_stereo_list[index]; - break; - - case SKL_CH_TRIO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_trio_list)) - return -EINVAL; - - list = mic_trio_list[index]; - break; - - case SKL_CH_QUATRO: - if (mconfig->dmic_ch_combo_index > ARRAY_SIZE(mic_quatro_list)) - return -EINVAL; - - list = mic_quatro_list[index]; - break; - - default: - dev_err(w->dapm->dev, - "Invalid channel %d for mic_select module\n", - ch_type); - return -EINVAL; - - } - - /* channel type enum map to number of chanels for that type */ - for (out_ch = 0; out_ch < ch_type; out_ch++) { - in_ch = list[out_ch]; - mic_cfg.blob[out_ch][in_ch] = SKL_DEFAULT_MIC_SEL_GAIN; - } - - return skl_fill_mic_sel_params(mconfig, &mic_cfg, w->dapm->dev); -} - -/* - * Fill the dma id for host and link. In case of passthrough - * pipeline, this will both host and link in the same - * pipeline, so need to copy the link and host based on dev_type - */ -static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, - struct skl_pipe_params *params) -{ - struct skl_pipe *pipe = mcfg->pipe; - - if (pipe->passthru) { - switch (mcfg->dev_type) { - case SKL_DEVICE_HDALINK: - pipe->p_params->link_dma_id = params->link_dma_id; - pipe->p_params->link_index = params->link_index; - pipe->p_params->link_bps = params->link_bps; - break; - - case SKL_DEVICE_HDAHOST: - pipe->p_params->host_dma_id = params->host_dma_id; - pipe->p_params->host_bps = params->host_bps; - break; - - default: - break; - } - pipe->p_params->s_fmt = params->s_fmt; - pipe->p_params->ch = params->ch; - pipe->p_params->s_freq = params->s_freq; - pipe->p_params->stream = params->stream; - pipe->p_params->format = params->format; - - } else { - memcpy(pipe->p_params, params, sizeof(*params)); - } -} - -/* - * The FE params are passed by hw_params of the DAI. - * On hw_params, the params are stored in Gateway module of the FE and we - * need to calculate the format in DSP module configuration, that - * conversion is done here - */ -int skl_tplg_update_pipe_params(struct device *dev, - struct skl_module_cfg *mconfig, - struct skl_pipe_params *params) -{ - struct skl_module_res *res; - struct skl_dev *skl = get_skl_ctx(dev); - struct skl_module_fmt *format = NULL; - u8 cfg_idx = mconfig->pipe->cur_config_idx; - - res = &mconfig->module->resources[mconfig->res_idx]; - skl_tplg_fill_dma_id(mconfig, params); - mconfig->fmt_idx = mconfig->mod_cfg[cfg_idx].fmt_idx; - mconfig->res_idx = mconfig->mod_cfg[cfg_idx].res_idx; - - if (skl->nr_modules) - return 0; - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) - format = &mconfig->module->formats[mconfig->fmt_idx].inputs[0].fmt; - else - format = &mconfig->module->formats[mconfig->fmt_idx].outputs[0].fmt; - - /* set the hw_params */ - format->s_freq = params->s_freq; - format->channels = params->ch; - format->valid_bit_depth = skl_get_bit_depth(params->s_fmt); - - /* - * 16 bit is 16 bit container whereas 24 bit is in 32 bit - * container so update bit depth accordingly - */ - switch (format->valid_bit_depth) { - case SKL_DEPTH_16BIT: - format->bit_depth = format->valid_bit_depth; - break; - - case SKL_DEPTH_24BIT: - case SKL_DEPTH_32BIT: - format->bit_depth = SKL_DEPTH_32BIT; - break; - - default: - dev_err(dev, "Invalid bit depth %x for pipe\n", - format->valid_bit_depth); - return -EINVAL; - } - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - res->ibs = (format->s_freq / 1000) * - (format->channels) * - (format->bit_depth >> 3); - } else { - res->obs = (format->s_freq / 1000) * - (format->channels) * - (format->bit_depth >> 3); - } - - return 0; -} - -/* - * Query the module config for the FE DAI - * This is used to find the hw_params set for that DAI and apply to FE - * pipeline - */ -struct skl_module_cfg * -skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream); - struct snd_soc_dapm_path *p = NULL; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connect && p->sink->power && - !is_skl_dsp_widget_type(p->sink, dai->dev)) - continue; - - if (p->sink->priv) { - dev_dbg(dai->dev, "set params for %s\n", - p->sink->name); - return p->sink->priv; - } - } - } else { - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connect && p->source->power && - !is_skl_dsp_widget_type(p->source, dai->dev)) - continue; - - if (p->source->priv) { - dev_dbg(dai->dev, "set params for %s\n", - p->source->name); - return p->source->priv; - } - } - } - - return NULL; -} - -static struct skl_module_cfg *skl_get_mconfig_pb_cpr( - struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *p; - struct skl_module_cfg *mconfig = NULL; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (w->endpoints[SND_SOC_DAPM_DIR_OUT] > 0) { - if (p->connect && - (p->sink->id == snd_soc_dapm_aif_out) && - p->source->priv) { - mconfig = p->source->priv; - return mconfig; - } - mconfig = skl_get_mconfig_pb_cpr(dai, p->source); - if (mconfig) - return mconfig; - } - } - return mconfig; -} - -static struct skl_module_cfg *skl_get_mconfig_cap_cpr( - struct snd_soc_dai *dai, struct snd_soc_dapm_widget *w) -{ - struct snd_soc_dapm_path *p; - struct skl_module_cfg *mconfig = NULL; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (w->endpoints[SND_SOC_DAPM_DIR_IN] > 0) { - if (p->connect && - (p->source->id == snd_soc_dapm_aif_in) && - p->sink->priv) { - mconfig = p->sink->priv; - return mconfig; - } - mconfig = skl_get_mconfig_cap_cpr(dai, p->sink); - if (mconfig) - return mconfig; - } - } - return mconfig; -} - -struct skl_module_cfg * -skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, int stream) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream); - struct skl_module_cfg *mconfig; - - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - mconfig = skl_get_mconfig_pb_cpr(dai, w); - } else { - mconfig = skl_get_mconfig_cap_cpr(dai, w); - } - return mconfig; -} - -static u8 skl_tplg_be_link_type(int dev_type) -{ - int ret; - - switch (dev_type) { - case SKL_DEVICE_BT: - ret = NHLT_LINK_SSP; - break; - - case SKL_DEVICE_DMIC: - ret = NHLT_LINK_DMIC; - break; - - case SKL_DEVICE_I2S: - ret = NHLT_LINK_SSP; - break; - - case SKL_DEVICE_HDALINK: - ret = NHLT_LINK_HDA; - break; - - default: - ret = NHLT_LINK_INVALID; - break; - } - - return ret; -} - -/* - * Fill the BE gateway parameters - * The BE gateway expects a blob of parameters which are kept in the ACPI - * NHLT blob, so query the blob for interface type (i2s/pdm) and instance. - * The port can have multiple settings so pick based on the pipeline - * parameters - */ -static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, - struct skl_module_cfg *mconfig, - struct skl_pipe_params *params) -{ - struct nhlt_specific_cfg *cfg; - struct skl_pipe *pipe = mconfig->pipe; - struct skl_pipe_params save = *pipe->p_params; - struct skl_pipe_fmt *pipe_fmt; - struct skl_dev *skl = get_skl_ctx(dai->dev); - int link_type = skl_tplg_be_link_type(mconfig->dev_type); - u8 dev_type = skl_tplg_be_dev_type(mconfig->dev_type); - int ret; - - skl_tplg_fill_dma_id(mconfig, params); - - if (link_type == NHLT_LINK_HDA) - return 0; - - *pipe->p_params = *params; - ret = skl_tplg_get_pipe_config(skl, mconfig); - if (ret) - goto err; - - dev_dbg(skl->dev, "%s using pipe config: %d\n", __func__, pipe->cur_config_idx); - if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) - pipe_fmt = &pipe->configs[pipe->cur_config_idx].out_fmt; - else - pipe_fmt = &pipe->configs[pipe->cur_config_idx].in_fmt; - - /* update the blob based on virtual bus_id*/ - cfg = intel_nhlt_get_endpoint_blob(dai->dev, skl->nhlt, - mconfig->vbus_id, link_type, - pipe_fmt->bps, params->s_cont, - pipe_fmt->channels, pipe_fmt->freq, - pipe->direction, dev_type); - if (cfg) { - mconfig->formats_config[SKL_PARAM_INIT].caps_size = cfg->size; - mconfig->formats_config[SKL_PARAM_INIT].caps = (u32 *)&cfg->caps; - } else { - dev_err(dai->dev, "Blob NULL for id:%d type:%d dirn:%d ch:%d, freq:%d, fmt:%d\n", - mconfig->vbus_id, link_type, params->stream, - params->ch, params->s_freq, params->s_fmt); - ret = -EINVAL; - goto err; - } - - return 0; - -err: - *pipe->p_params = save; - return ret; -} - -static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, - struct snd_soc_dapm_widget *w, - struct skl_pipe_params *params) -{ - struct snd_soc_dapm_path *p; - int ret = -EIO; - - snd_soc_dapm_widget_for_each_source_path(w, p) { - if (p->connect && is_skl_dsp_widget_type(p->source, dai->dev) && - p->source->priv) { - - ret = skl_tplg_be_fill_pipe_params(dai, - p->source->priv, params); - if (ret < 0) - return ret; - } else { - ret = skl_tplg_be_set_src_pipe_params(dai, - p->source, params); - if (ret < 0) - return ret; - } - } - - return ret; -} - -static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, - struct snd_soc_dapm_widget *w, struct skl_pipe_params *params) -{ - struct snd_soc_dapm_path *p; - int ret = -EIO; - - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (p->connect && is_skl_dsp_widget_type(p->sink, dai->dev) && - p->sink->priv) { - - ret = skl_tplg_be_fill_pipe_params(dai, - p->sink->priv, params); - if (ret < 0) - return ret; - } else { - ret = skl_tplg_be_set_sink_pipe_params( - dai, p->sink, params); - if (ret < 0) - return ret; - } - } - - return ret; -} - -/* - * BE hw_params can be a source parameters (capture) or sink parameters - * (playback). Based on sink and source we need to either find the source - * list or the sink list and set the pipeline parameters - */ -int skl_tplg_be_update_params(struct snd_soc_dai *dai, - struct skl_pipe_params *params) -{ - struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, params->stream); - - if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { - return skl_tplg_be_set_src_pipe_params(dai, w, params); - } else { - return skl_tplg_be_set_sink_pipe_params(dai, w, params); - } -} - -static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { - {SKL_MIXER_EVENT, skl_tplg_mixer_event}, - {SKL_VMIXER_EVENT, skl_tplg_mixer_event}, - {SKL_PGA_EVENT, skl_tplg_pga_event}, -}; - -static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { - {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, - skl_tplg_tlv_control_set}, -}; - -static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = { - { - .id = SKL_CONTROL_TYPE_MIC_SELECT, - .get = skl_tplg_mic_control_get, - .put = skl_tplg_mic_control_set, - }, - { - .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT, - .get = skl_tplg_multi_config_get, - .put = skl_tplg_multi_config_set, - }, - { - .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC, - .get = skl_tplg_multi_config_get_dmic, - .put = skl_tplg_multi_config_set_dmic, - } -}; - -static int skl_tplg_fill_pipe_cfg(struct device *dev, - struct skl_pipe *pipe, u32 tkn, - u32 tkn_val, int conf_idx, int dir) -{ - struct skl_pipe_fmt *fmt; - struct skl_path_config *config; - - switch (dir) { - case SKL_DIR_IN: - fmt = &pipe->configs[conf_idx].in_fmt; - break; - - case SKL_DIR_OUT: - fmt = &pipe->configs[conf_idx].out_fmt; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - config = &pipe->configs[conf_idx]; - - switch (tkn) { - case SKL_TKN_U32_CFG_FREQ: - fmt->freq = tkn_val; - break; - - case SKL_TKN_U8_CFG_CHAN: - fmt->channels = tkn_val; - break; - - case SKL_TKN_U8_CFG_BPS: - fmt->bps = tkn_val; - break; - - case SKL_TKN_U32_PATH_MEM_PGS: - config->mem_pages = tkn_val; - break; - - default: - dev_err(dev, "Invalid token config: %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_fill_pipe_tkn(struct device *dev, - struct skl_pipe *pipe, u32 tkn, - u32 tkn_val) -{ - - switch (tkn) { - case SKL_TKN_U32_PIPE_CONN_TYPE: - pipe->conn_type = tkn_val; - break; - - case SKL_TKN_U32_PIPE_PRIORITY: - pipe->pipe_priority = tkn_val; - break; - - case SKL_TKN_U32_PIPE_MEM_PGS: - pipe->memory_pages = tkn_val; - break; - - case SKL_TKN_U32_PMODE: - pipe->lp_mode = tkn_val; - break; - - case SKL_TKN_U32_PIPE_DIRECTION: - pipe->direction = tkn_val; - break; - - case SKL_TKN_U32_NUM_CONFIGS: - pipe->nr_cfgs = tkn_val; - break; - - default: - dev_err(dev, "Token not handled %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -/* - * Add pipeline by parsing the relevant tokens - * Return an existing pipe if the pipe already exists. - */ -static int skl_tplg_add_pipe(struct device *dev, - struct skl_module_cfg *mconfig, struct skl_dev *skl, - struct snd_soc_tplg_vendor_value_elem *tkn_elem) -{ - struct skl_pipeline *ppl; - struct skl_pipe *pipe; - struct skl_pipe_params *params; - - list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == tkn_elem->value) { - mconfig->pipe = ppl->pipe; - return -EEXIST; - } - } - - ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); - if (!ppl) - return -ENOMEM; - - pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); - if (!pipe) - return -ENOMEM; - - params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - pipe->p_params = params; - pipe->ppl_id = tkn_elem->value; - INIT_LIST_HEAD(&pipe->w_list); - - ppl->pipe = pipe; - list_add(&ppl->node, &skl->ppl_list); - - mconfig->pipe = pipe; - mconfig->pipe->state = SKL_PIPE_INVALID; - - return 0; -} - -static int skl_tplg_get_uuid(struct device *dev, guid_t *guid, - struct snd_soc_tplg_vendor_uuid_elem *uuid_tkn) -{ - if (uuid_tkn->token == SKL_TKN_UUID) { - import_guid(guid, uuid_tkn->uuid); - return 0; - } - - dev_err(dev, "Not an UUID token %d\n", uuid_tkn->token); - - return -EINVAL; -} - -static int skl_tplg_fill_pin(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_pin *m_pin, - int pin_index) -{ - int ret; - - switch (tkn_elem->token) { - case SKL_TKN_U32_PIN_MOD_ID: - m_pin[pin_index].id.module_id = tkn_elem->value; - break; - - case SKL_TKN_U32_PIN_INST_ID: - m_pin[pin_index].id.instance_id = tkn_elem->value; - break; - - case SKL_TKN_UUID: - ret = skl_tplg_get_uuid(dev, &m_pin[pin_index].id.mod_uuid, - (struct snd_soc_tplg_vendor_uuid_elem *)tkn_elem); - if (ret < 0) - return ret; - - break; - - default: - dev_err(dev, "%d Not a pin token\n", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - -/* - * Parse for pin config specific tokens to fill up the - * module private data - */ -static int skl_tplg_fill_pins_info(struct device *dev, - struct skl_module_cfg *mconfig, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - int dir, int pin_count) -{ - int ret; - struct skl_module_pin *m_pin; - - switch (dir) { - case SKL_DIR_IN: - m_pin = mconfig->m_in_pin; - break; - - case SKL_DIR_OUT: - m_pin = mconfig->m_out_pin; - break; - - default: - dev_err(dev, "Invalid direction value\n"); - return -EINVAL; - } - - ret = skl_tplg_fill_pin(dev, tkn_elem, m_pin, pin_count); - if (ret < 0) - return ret; - - m_pin[pin_count].in_use = false; - m_pin[pin_count].pin_state = SKL_PIN_UNBIND; - - return 0; -} - -/* - * Fill up input/output module config format based - * on the direction - */ -static int skl_tplg_fill_fmt(struct device *dev, - struct skl_module_fmt *dst_fmt, - u32 tkn, u32 value) -{ - switch (tkn) { - case SKL_TKN_U32_FMT_CH: - dst_fmt->channels = value; - break; - - case SKL_TKN_U32_FMT_FREQ: - dst_fmt->s_freq = value; - break; - - case SKL_TKN_U32_FMT_BIT_DEPTH: - dst_fmt->bit_depth = value; - break; - - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - dst_fmt->valid_bit_depth = value; - break; - - case SKL_TKN_U32_FMT_CH_CONFIG: - dst_fmt->ch_cfg = value; - break; - - case SKL_TKN_U32_FMT_INTERLEAVE: - dst_fmt->interleaving_style = value; - break; - - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - dst_fmt->sample_type = value; - break; - - case SKL_TKN_U32_FMT_CH_MAP: - dst_fmt->ch_map = value; - break; - - default: - dev_err(dev, "Invalid token %d\n", tkn); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_widget_fill_fmt(struct device *dev, - struct skl_module_iface *fmt, - u32 tkn, u32 val, u32 dir, int fmt_idx) -{ - struct skl_module_fmt *dst_fmt; - - if (!fmt) - return -EINVAL; - - switch (dir) { - case SKL_DIR_IN: - dst_fmt = &fmt->inputs[fmt_idx].fmt; - break; - - case SKL_DIR_OUT: - dst_fmt = &fmt->outputs[fmt_idx].fmt; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - return skl_tplg_fill_fmt(dev, dst_fmt, tkn, val); -} - -static void skl_tplg_fill_pin_dynamic_val( - struct skl_module_pin *mpin, u32 pin_count, u32 value) -{ - int i; - - for (i = 0; i < pin_count; i++) - mpin[i].is_dynamic = value; -} - -/* - * Resource table in the manifest has pin specific resources - * like pin and pin buffer size - */ -static int skl_tplg_manifest_pin_res_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_res *res, int pin_idx, int dir) -{ - struct skl_module_pin_resources *m_pin; - - switch (dir) { - case SKL_DIR_IN: - m_pin = &res->input[pin_idx]; - break; - - case SKL_DIR_OUT: - m_pin = &res->output[pin_idx]; - break; - - default: - dev_err(dev, "Invalid pin direction: %d\n", dir); - return -EINVAL; - } - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_RES_PIN_ID: - m_pin->pin_index = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_PIN_BUF: - m_pin->buf_size = tkn_elem->value; - break; - - default: - dev_err(dev, "Invalid token: %d\n", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - -/* - * Fill module specific resources from the manifest's resource - * table like CPS, DMA size, mem_pages. - */ -static int skl_tplg_fill_res_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module_res *res, - int pin_idx, int dir) -{ - int ret, tkn_count = 0; - - if (!res) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_DMA_SIZE: - res->dma_buffer_size = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_CPC: - res->cpc = tkn_elem->value; - break; - - case SKL_TKN_U32_MEM_PAGES: - res->is_pages = tkn_elem->value; - break; - - case SKL_TKN_U32_OBS: - res->obs = tkn_elem->value; - break; - - case SKL_TKN_U32_IBS: - res->ibs = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_RES_PIN_ID: - case SKL_TKN_MM_U32_PIN_BUF: - ret = skl_tplg_manifest_pin_res_tkn(dev, tkn_elem, res, - pin_idx, dir); - if (ret < 0) - return ret; - break; - - case SKL_TKN_MM_U32_CPS: - case SKL_TKN_U32_MAX_MCPS: - /* ignore unused tokens */ - break; - - default: - dev_err(dev, "Not a res type token: %d", tkn_elem->token); - return -EINVAL; - - } - tkn_count++; - - return tkn_count; -} - -/* - * Parse tokens to fill up the module private data - */ -static int skl_tplg_get_token(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dev *skl, struct skl_module_cfg *mconfig) -{ - int tkn_count = 0; - int ret; - static int is_pipe_exists; - static int pin_index, dir, conf_idx; - struct skl_module_iface *iface = NULL; - struct skl_module_res *res = NULL; - int res_idx = mconfig->res_idx; - int fmt_idx = mconfig->fmt_idx; - - /* - * If the manifest structure contains no modules, fill all - * the module data to 0th index. - * res_idx and fmt_idx are default set to 0. - */ - if (skl->nr_modules == 0) { - res = &mconfig->module->resources[res_idx]; - iface = &mconfig->module->formats[fmt_idx]; - } - - if (tkn_elem->token > SKL_TKN_MAX) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_U8_IN_QUEUE_COUNT: - mconfig->module->max_input_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_QUEUE_COUNT: - mconfig->module->max_output_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_DYN_IN_PIN: - if (!mconfig->m_in_pin) - mconfig->m_in_pin = - devm_kcalloc(dev, MAX_IN_QUEUE, - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_in_pin) - return -ENOMEM; - - skl_tplg_fill_pin_dynamic_val(mconfig->m_in_pin, MAX_IN_QUEUE, - tkn_elem->value); - break; - - case SKL_TKN_U8_DYN_OUT_PIN: - if (!mconfig->m_out_pin) - mconfig->m_out_pin = - devm_kcalloc(dev, MAX_IN_QUEUE, - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_out_pin) - return -ENOMEM; - - skl_tplg_fill_pin_dynamic_val(mconfig->m_out_pin, MAX_OUT_QUEUE, - tkn_elem->value); - break; - - case SKL_TKN_U8_TIME_SLOT: - mconfig->time_slot = tkn_elem->value; - break; - - case SKL_TKN_U8_CORE_ID: - mconfig->core_id = tkn_elem->value; - break; - - case SKL_TKN_U8_MOD_TYPE: - mconfig->m_type = tkn_elem->value; - break; - - case SKL_TKN_U8_DEV_TYPE: - mconfig->dev_type = tkn_elem->value; - break; - - case SKL_TKN_U8_HW_CONN_TYPE: - mconfig->hw_conn_type = tkn_elem->value; - break; - - case SKL_TKN_U16_MOD_INST_ID: - mconfig->id.instance_id = - tkn_elem->value; - break; - - case SKL_TKN_U32_MEM_PAGES: - case SKL_TKN_U32_MAX_MCPS: - case SKL_TKN_U32_OBS: - case SKL_TKN_U32_IBS: - ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_index, dir); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_VBUS_ID: - mconfig->vbus_id = tkn_elem->value; - break; - - case SKL_TKN_U32_PARAMS_FIXUP: - mconfig->params_fixup = tkn_elem->value; - break; - - case SKL_TKN_U32_CONVERTER: - mconfig->converter = tkn_elem->value; - break; - - case SKL_TKN_U32_D0I3_CAPS: - mconfig->d0i3_caps = tkn_elem->value; - break; - - case SKL_TKN_U32_PIPE_ID: - ret = skl_tplg_add_pipe(dev, - mconfig, skl, tkn_elem); - - if (ret < 0) { - if (ret == -EEXIST) { - is_pipe_exists = 1; - break; - } - return is_pipe_exists; - } - - break; - - case SKL_TKN_U32_PIPE_CONFIG_ID: - conf_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_PIPE_CONN_TYPE: - case SKL_TKN_U32_PIPE_PRIORITY: - case SKL_TKN_U32_PIPE_MEM_PGS: - case SKL_TKN_U32_PMODE: - case SKL_TKN_U32_PIPE_DIRECTION: - case SKL_TKN_U32_NUM_CONFIGS: - if (is_pipe_exists) { - ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, - tkn_elem->token, tkn_elem->value); - if (ret < 0) - return ret; - } - - break; - - case SKL_TKN_U32_PATH_MEM_PGS: - case SKL_TKN_U32_CFG_FREQ: - case SKL_TKN_U8_CFG_CHAN: - case SKL_TKN_U8_CFG_BPS: - if (mconfig->pipe->nr_cfgs) { - ret = skl_tplg_fill_pipe_cfg(dev, mconfig->pipe, - tkn_elem->token, tkn_elem->value, - conf_idx, dir); - if (ret < 0) - return ret; - } - break; - - case SKL_TKN_CFG_MOD_RES_ID: - mconfig->mod_cfg[conf_idx].res_idx = tkn_elem->value; - break; - - case SKL_TKN_CFG_MOD_FMT_ID: - mconfig->mod_cfg[conf_idx].fmt_idx = tkn_elem->value; - break; - - /* - * SKL_TKN_U32_DIR_PIN_COUNT token has the value for both - * direction and the pin count. The first four bits represent - * direction and next four the pin count. - */ - case SKL_TKN_U32_DIR_PIN_COUNT: - dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; - pin_index = (tkn_elem->value & - SKL_PIN_COUNT_MASK) >> 4; - - break; - - case SKL_TKN_U32_FMT_CH: - case SKL_TKN_U32_FMT_FREQ: - case SKL_TKN_U32_FMT_BIT_DEPTH: - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - case SKL_TKN_U32_FMT_CH_CONFIG: - case SKL_TKN_U32_FMT_INTERLEAVE: - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - case SKL_TKN_U32_FMT_CH_MAP: - ret = skl_tplg_widget_fill_fmt(dev, iface, tkn_elem->token, - tkn_elem->value, dir, pin_index); - - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_PIN_MOD_ID: - case SKL_TKN_U32_PIN_INST_ID: - case SKL_TKN_UUID: - ret = skl_tplg_fill_pins_info(dev, - mconfig, tkn_elem, dir, - pin_index); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_U32_FMT_CFG_IDX: - if (tkn_elem->value > SKL_MAX_PARAMS_TYPES) - return -EINVAL; - - mconfig->fmt_cfg_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_CAPS_SIZE: - mconfig->formats_config[mconfig->fmt_cfg_idx].caps_size = - tkn_elem->value; - - break; - - case SKL_TKN_U32_CAPS_SET_PARAMS: - mconfig->formats_config[mconfig->fmt_cfg_idx].set_params = - tkn_elem->value; - break; - - case SKL_TKN_U32_CAPS_PARAMS_ID: - mconfig->formats_config[mconfig->fmt_cfg_idx].param_id = - tkn_elem->value; - break; - - case SKL_TKN_U32_PROC_DOMAIN: - mconfig->domain = - tkn_elem->value; - - break; - - case SKL_TKN_U32_DMA_BUF_SIZE: - mconfig->dma_buffer_size = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_PIN_TYPE: - case SKL_TKN_U8_OUT_PIN_TYPE: - case SKL_TKN_U8_CONN_TYPE: - break; - - default: - dev_err(dev, "Token %d not handled\n", - tkn_elem->token); - return -EINVAL; - } - - tkn_count++; - - return tkn_count; -} - -/* - * Parse the vendor array for specific tokens to construct - * module private data - */ -static int skl_tplg_get_tokens(struct device *dev, - char *pvt_data, struct skl_dev *skl, - struct skl_module_cfg *mconfig, int block_size) -{ - struct snd_soc_tplg_vendor_array *array; - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - int tkn_count = 0, ret; - int off = 0, tuple_size = 0; - bool is_module_guid = true; - - if (block_size <= 0) - return -EINVAL; - - while (tuple_size < block_size) { - array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); - - off += array->size; - - switch (array->type) { - case SND_SOC_TPLG_TUPLE_TYPE_STRING: - dev_warn(dev, "no string tokens expected for skl tplg\n"); - continue; - - case SND_SOC_TPLG_TUPLE_TYPE_UUID: - if (is_module_guid) { - ret = skl_tplg_get_uuid(dev, (guid_t *)mconfig->guid, - array->uuid); - is_module_guid = false; - } else { - ret = skl_tplg_get_token(dev, array->value, skl, - mconfig); - } - - if (ret < 0) - return ret; - - tuple_size += sizeof(*array->uuid); - - continue; - - default: - tkn_elem = array->value; - tkn_count = 0; - break; - } - - while (tkn_count <= (array->num_elems - 1)) { - ret = skl_tplg_get_token(dev, tkn_elem, - skl, mconfig); - - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - tkn_elem++; - } - - tuple_size += tkn_count * sizeof(*tkn_elem); - } - - return off; -} - -/* - * Every data block is preceded by a descriptor to read the number - * of data blocks, they type of the block and it's size - */ -static int skl_tplg_get_desc_blocks(struct device *dev, - struct snd_soc_tplg_vendor_array *array) -{ - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - - tkn_elem = array->value; - - switch (tkn_elem->token) { - case SKL_TKN_U8_NUM_BLOCKS: - case SKL_TKN_U8_BLOCK_TYPE: - case SKL_TKN_U16_BLOCK_SIZE: - return tkn_elem->value; - - default: - dev_err(dev, "Invalid descriptor token %d\n", tkn_elem->token); - break; - } - - return -EINVAL; -} - -/* Functions to parse private data from configuration file format v4 */ - -/* - * Add pipeline from topology binary into driver pipeline list - * - * If already added we return that instance - * Otherwise we create a new instance and add into driver list - */ -static int skl_tplg_add_pipe_v4(struct device *dev, - struct skl_module_cfg *mconfig, struct skl_dev *skl, - struct skl_dfw_v4_pipe *dfw_pipe) -{ - struct skl_pipeline *ppl; - struct skl_pipe *pipe; - struct skl_pipe_params *params; - - list_for_each_entry(ppl, &skl->ppl_list, node) { - if (ppl->pipe->ppl_id == dfw_pipe->pipe_id) { - mconfig->pipe = ppl->pipe; - return 0; - } - } - - ppl = devm_kzalloc(dev, sizeof(*ppl), GFP_KERNEL); - if (!ppl) - return -ENOMEM; - - pipe = devm_kzalloc(dev, sizeof(*pipe), GFP_KERNEL); - if (!pipe) - return -ENOMEM; - - params = devm_kzalloc(dev, sizeof(*params), GFP_KERNEL); - if (!params) - return -ENOMEM; - - pipe->ppl_id = dfw_pipe->pipe_id; - pipe->memory_pages = dfw_pipe->memory_pages; - pipe->pipe_priority = dfw_pipe->pipe_priority; - pipe->conn_type = dfw_pipe->conn_type; - pipe->state = SKL_PIPE_INVALID; - pipe->p_params = params; - INIT_LIST_HEAD(&pipe->w_list); - - ppl->pipe = pipe; - list_add(&ppl->node, &skl->ppl_list); - - mconfig->pipe = pipe; - - return 0; -} - -static void skl_fill_module_pin_info_v4(struct skl_dfw_v4_module_pin *dfw_pin, - struct skl_module_pin *m_pin, - bool is_dynamic, int max_pin) -{ - int i; - - for (i = 0; i < max_pin; i++) { - m_pin[i].id.module_id = dfw_pin[i].module_id; - m_pin[i].id.instance_id = dfw_pin[i].instance_id; - m_pin[i].in_use = false; - m_pin[i].is_dynamic = is_dynamic; - m_pin[i].pin_state = SKL_PIN_UNBIND; - } -} - -static void skl_tplg_fill_fmt_v4(struct skl_module_pin_fmt *dst_fmt, - struct skl_dfw_v4_module_fmt *src_fmt, - int pins) -{ - int i; - - for (i = 0; i < pins; i++) { - dst_fmt[i].fmt.channels = src_fmt[i].channels; - dst_fmt[i].fmt.s_freq = src_fmt[i].freq; - dst_fmt[i].fmt.bit_depth = src_fmt[i].bit_depth; - dst_fmt[i].fmt.valid_bit_depth = src_fmt[i].valid_bit_depth; - dst_fmt[i].fmt.ch_cfg = src_fmt[i].ch_cfg; - dst_fmt[i].fmt.ch_map = src_fmt[i].ch_map; - dst_fmt[i].fmt.interleaving_style = - src_fmt[i].interleaving_style; - dst_fmt[i].fmt.sample_type = src_fmt[i].sample_type; - } -} - -static int skl_tplg_get_pvt_data_v4(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl_dev *skl, struct device *dev, - struct skl_module_cfg *mconfig) -{ - struct skl_dfw_v4_module *dfw = - (struct skl_dfw_v4_module *)tplg_w->priv.data; - int ret; - int idx = mconfig->fmt_cfg_idx; - - dev_dbg(dev, "Parsing Skylake v4 widget topology data\n"); - - ret = guid_parse(dfw->uuid, (guid_t *)mconfig->guid); - if (ret) - return ret; - mconfig->id.module_id = -1; - mconfig->id.instance_id = dfw->instance_id; - mconfig->module->resources[0].cpc = dfw->max_mcps / 1000; - mconfig->module->resources[0].ibs = dfw->ibs; - mconfig->module->resources[0].obs = dfw->obs; - mconfig->core_id = dfw->core_id; - mconfig->module->max_input_pins = dfw->max_in_queue; - mconfig->module->max_output_pins = dfw->max_out_queue; - mconfig->module->loadable = dfw->is_loadable; - skl_tplg_fill_fmt_v4(mconfig->module->formats[0].inputs, dfw->in_fmt, - MAX_IN_QUEUE); - skl_tplg_fill_fmt_v4(mconfig->module->formats[0].outputs, dfw->out_fmt, - MAX_OUT_QUEUE); - - mconfig->params_fixup = dfw->params_fixup; - mconfig->converter = dfw->converter; - mconfig->m_type = dfw->module_type; - mconfig->vbus_id = dfw->vbus_id; - mconfig->module->resources[0].is_pages = dfw->mem_pages; - - ret = skl_tplg_add_pipe_v4(dev, mconfig, skl, &dfw->pipe); - if (ret) - return ret; - - mconfig->dev_type = dfw->dev_type; - mconfig->hw_conn_type = dfw->hw_conn_type; - mconfig->time_slot = dfw->time_slot; - mconfig->formats_config[idx].caps_size = dfw->caps.caps_size; - - mconfig->m_in_pin = devm_kcalloc(dev, - MAX_IN_QUEUE, sizeof(*mconfig->m_in_pin), - GFP_KERNEL); - if (!mconfig->m_in_pin) - return -ENOMEM; - - mconfig->m_out_pin = devm_kcalloc(dev, - MAX_OUT_QUEUE, sizeof(*mconfig->m_out_pin), - GFP_KERNEL); - if (!mconfig->m_out_pin) - return -ENOMEM; - - skl_fill_module_pin_info_v4(dfw->in_pin, mconfig->m_in_pin, - dfw->is_dynamic_in_pin, - mconfig->module->max_input_pins); - skl_fill_module_pin_info_v4(dfw->out_pin, mconfig->m_out_pin, - dfw->is_dynamic_out_pin, - mconfig->module->max_output_pins); - - if (mconfig->formats_config[idx].caps_size) { - mconfig->formats_config[idx].set_params = dfw->caps.set_params; - mconfig->formats_config[idx].param_id = dfw->caps.param_id; - mconfig->formats_config[idx].caps = - devm_kzalloc(dev, mconfig->formats_config[idx].caps_size, - GFP_KERNEL); - if (!mconfig->formats_config[idx].caps) - return -ENOMEM; - memcpy(mconfig->formats_config[idx].caps, dfw->caps.caps, - dfw->caps.caps_size); - } - - return 0; -} - -static int skl_tplg_get_caps_data(struct device *dev, char *data, - struct skl_module_cfg *mconfig) -{ - int idx = mconfig->fmt_cfg_idx; - - if (mconfig->formats_config[idx].caps_size > 0) { - mconfig->formats_config[idx].caps = - devm_kzalloc(dev, mconfig->formats_config[idx].caps_size, - GFP_KERNEL); - if (!mconfig->formats_config[idx].caps) - return -ENOMEM; - memcpy(mconfig->formats_config[idx].caps, data, - mconfig->formats_config[idx].caps_size); - } - - return mconfig->formats_config[idx].caps_size; -} - -/* - * Parse the private data for the token and corresponding value. - * The private data can have multiple data blocks. So, a data block - * is preceded by a descriptor for number of blocks and a descriptor - * for the type and size of the suceeding data block. - */ -static int skl_tplg_get_pvt_data(struct snd_soc_tplg_dapm_widget *tplg_w, - struct skl_dev *skl, struct device *dev, - struct skl_module_cfg *mconfig) -{ - struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size, block_type, off = 0; - char *data; - int ret; - - /* - * v4 configuration files have a valid UUID at the start of - * the widget's private data. - */ - if (uuid_is_valid((char *)tplg_w->priv.data)) - return skl_tplg_get_pvt_data_v4(tplg_w, skl, dev, mconfig); - - /* Read the NUM_DATA_BLOCKS descriptor */ - array = (struct snd_soc_tplg_vendor_array *)tplg_w->priv.data; - ret = skl_tplg_get_desc_blocks(dev, array); - if (ret < 0) - return ret; - num_blocks = ret; - - off += array->size; - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ - while (num_blocks > 0) { - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_type = ret; - off += array->size; - - array = (struct snd_soc_tplg_vendor_array *) - (tplg_w->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_size = ret; - off += array->size; - - data = (tplg_w->priv.data + off); - - if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_tokens(dev, data, - skl, mconfig, block_size); - } else { - ret = skl_tplg_get_caps_data(dev, data, mconfig); - } - - if (ret < 0) - return ret; - - --num_blocks; - off += ret; - } - - return 0; -} - -static void skl_clear_pin_config(struct snd_soc_component *component, - struct snd_soc_dapm_widget *w) -{ - int i; - struct skl_module_cfg *mconfig; - struct skl_pipe *pipe; - - if (!strncmp(w->dapm->component->name, component->name, - strlen(component->name))) { - mconfig = w->priv; - pipe = mconfig->pipe; - for (i = 0; i < mconfig->module->max_input_pins; i++) { - mconfig->m_in_pin[i].in_use = false; - mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; - } - for (i = 0; i < mconfig->module->max_output_pins; i++) { - mconfig->m_out_pin[i].in_use = false; - mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; - } - pipe->state = SKL_PIPE_INVALID; - mconfig->m_state = SKL_MODULE_UNINIT; - } -} - -void skl_cleanup_resources(struct skl_dev *skl) -{ - struct snd_soc_component *soc_component = skl->component; - struct snd_soc_dapm_widget *w; - struct snd_soc_card *card; - - if (soc_component == NULL) - return; - - card = soc_component->card; - if (!snd_soc_card_is_instantiated(card)) - return; - - list_for_each_entry(w, &card->widgets, list) { - if (is_skl_dsp_widget_type(w, skl->dev) && w->priv != NULL) - skl_clear_pin_config(soc_component, w); - } - - skl_clear_module_cnt(skl->dsp); -} - -/* - * Topology core widget load callback - * - * This is used to save the private data for each widget which gives - * information to the driver about module and pipeline parameters which DSP - * FW expects like ids, resource values, formats etc - */ -static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, int index, - struct snd_soc_dapm_widget *w, - struct snd_soc_tplg_dapm_widget *tplg_w) -{ - int ret; - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl_dev *skl = bus_to_skl(bus); - struct skl_module_cfg *mconfig; - - if (!tplg_w->priv.size) - goto bind_event; - - mconfig = devm_kzalloc(bus->dev, sizeof(*mconfig), GFP_KERNEL); - - if (!mconfig) - return -ENOMEM; - - if (skl->nr_modules == 0) { - mconfig->module = devm_kzalloc(bus->dev, - sizeof(*mconfig->module), GFP_KERNEL); - if (!mconfig->module) - return -ENOMEM; - } - - w->priv = mconfig; - - /* - * module binary can be loaded later, so set it to query when - * module is load for a use case - */ - mconfig->id.module_id = -1; - - /* To provide backward compatibility, set default as SKL_PARAM_INIT */ - mconfig->fmt_cfg_idx = SKL_PARAM_INIT; - - /* Parse private data for tuples */ - ret = skl_tplg_get_pvt_data(tplg_w, skl, bus->dev, mconfig); - if (ret < 0) - return ret; - - skl_debug_init_module(skl->debugfs, w, mconfig); - -bind_event: - if (tplg_w->event_type == 0) { - dev_dbg(bus->dev, "ASoC: No event handler required\n"); - return 0; - } - - ret = snd_soc_tplg_widget_bind_event(w, skl_tplg_widget_ops, - ARRAY_SIZE(skl_tplg_widget_ops), - tplg_w->event_type); - - if (ret) { - dev_err(bus->dev, "%s: No matching event handlers found for %d\n", - __func__, tplg_w->event_type); - return -EINVAL; - } - - return 0; -} - -static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, - struct snd_soc_tplg_bytes_control *bc) -{ - struct skl_algo_data *ac; - struct skl_dfw_algo_data *dfw_ac = - (struct skl_dfw_algo_data *)bc->priv.data; - - ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); - if (!ac) - return -ENOMEM; - - /* Fill private data */ - ac->max = dfw_ac->max; - ac->param_id = dfw_ac->param_id; - ac->set_params = dfw_ac->set_params; - ac->size = dfw_ac->max; - - if (ac->max) { - ac->params = devm_kzalloc(dev, ac->max, GFP_KERNEL); - if (!ac->params) - return -ENOMEM; - - memcpy(ac->params, dfw_ac->params, ac->max); - } - - be->dobj.private = ac; - return 0; -} - -static int skl_init_enum_data(struct device *dev, struct soc_enum *se, - struct snd_soc_tplg_enum_control *ec) -{ - - void *data; - - if (ec->priv.size) { - data = devm_kzalloc(dev, sizeof(ec->priv.size), GFP_KERNEL); - if (!data) - return -ENOMEM; - memcpy(data, ec->priv.data, ec->priv.size); - se->dobj.private = data; - } - - return 0; - -} - -static int skl_tplg_control_load(struct snd_soc_component *cmpnt, - int index, - struct snd_kcontrol_new *kctl, - struct snd_soc_tplg_ctl_hdr *hdr) -{ - struct soc_bytes_ext *sb; - struct snd_soc_tplg_bytes_control *tplg_bc; - struct snd_soc_tplg_enum_control *tplg_ec; - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct soc_enum *se; - - switch (hdr->ops.info) { - case SND_SOC_TPLG_CTL_BYTES: - tplg_bc = container_of(hdr, - struct snd_soc_tplg_bytes_control, hdr); - if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - sb = (struct soc_bytes_ext *)kctl->private_value; - if (tplg_bc->priv.size) - return skl_init_algo_data( - bus->dev, sb, tplg_bc); - } - break; - - case SND_SOC_TPLG_CTL_ENUM: - tplg_ec = container_of(hdr, - struct snd_soc_tplg_enum_control, hdr); - if (kctl->access & SNDRV_CTL_ELEM_ACCESS_READ) { - se = (struct soc_enum *)kctl->private_value; - if (tplg_ec->priv.size) - skl_init_enum_data(bus->dev, se, tplg_ec); - } - - /* - * now that the control initializations are done, remove - * write permission for the DMIC configuration enums to - * avoid conflicts between NHLT settings and user interaction - */ - - if (hdr->ops.get == SKL_CONTROL_TYPE_MULTI_IO_SELECT_DMIC) - kctl->access = SNDRV_CTL_ELEM_ACCESS_READ; - - break; - - default: - dev_dbg(bus->dev, "Control load not supported %d:%d:%d\n", - hdr->ops.get, hdr->ops.put, hdr->ops.info); - break; - } - - return 0; -} - -static int skl_tplg_fill_str_mfest_tkn(struct device *dev, - struct snd_soc_tplg_vendor_string_elem *str_elem, - struct skl_dev *skl) -{ - int tkn_count = 0; - static int ref_count; - - switch (str_elem->token) { - case SKL_TKN_STR_LIB_NAME: - if (ref_count > skl->lib_count - 1) { - ref_count = 0; - return -EINVAL; - } - - strncpy(skl->lib_info[ref_count].name, - str_elem->string, - ARRAY_SIZE(skl->lib_info[ref_count].name)); - ref_count++; - break; - - default: - dev_err(dev, "Not a string token %d\n", str_elem->token); - break; - } - tkn_count++; - - return tkn_count; -} - -static int skl_tplg_get_str_tkn(struct device *dev, - struct snd_soc_tplg_vendor_array *array, - struct skl_dev *skl) -{ - int tkn_count = 0, ret; - struct snd_soc_tplg_vendor_string_elem *str_elem; - - str_elem = (struct snd_soc_tplg_vendor_string_elem *)array->value; - while (tkn_count < array->num_elems) { - ret = skl_tplg_fill_str_mfest_tkn(dev, str_elem, skl); - str_elem++; - - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - } - - return tkn_count; -} - -static int skl_tplg_manifest_fill_fmt(struct device *dev, - struct skl_module_iface *fmt, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - u32 dir, int fmt_idx) -{ - struct skl_module_pin_fmt *dst_fmt; - struct skl_module_fmt *mod_fmt; - int ret; - - if (!fmt) - return -EINVAL; - - switch (dir) { - case SKL_DIR_IN: - dst_fmt = &fmt->inputs[fmt_idx]; - break; - - case SKL_DIR_OUT: - dst_fmt = &fmt->outputs[fmt_idx]; - break; - - default: - dev_err(dev, "Invalid direction: %d\n", dir); - return -EINVAL; - } - - mod_fmt = &dst_fmt->fmt; - - switch (tkn_elem->token) { - case SKL_TKN_MM_U32_INTF_PIN_ID: - dst_fmt->id = tkn_elem->value; - break; - - default: - ret = skl_tplg_fill_fmt(dev, mod_fmt, tkn_elem->token, - tkn_elem->value); - if (ret < 0) - return ret; - break; - } - - return 0; -} - -static int skl_tplg_fill_mod_info(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_module *mod) -{ - - if (!mod) - return -EINVAL; - - switch (tkn_elem->token) { - case SKL_TKN_U8_IN_PIN_TYPE: - mod->input_pin_type = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_PIN_TYPE: - mod->output_pin_type = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_QUEUE_COUNT: - mod->max_input_pins = tkn_elem->value; - break; - - case SKL_TKN_U8_OUT_QUEUE_COUNT: - mod->max_output_pins = tkn_elem->value; - break; - - case SKL_TKN_MM_U8_NUM_RES: - mod->nr_resources = tkn_elem->value; - break; - - case SKL_TKN_MM_U8_NUM_INTF: - mod->nr_interfaces = tkn_elem->value; - break; - - default: - dev_err(dev, "Invalid mod info token %d", tkn_elem->token); - return -EINVAL; - } - - return 0; -} - - -static int skl_tplg_get_int_tkn(struct device *dev, - struct snd_soc_tplg_vendor_value_elem *tkn_elem, - struct skl_dev *skl) -{ - int tkn_count = 0, ret; - static int mod_idx, res_val_idx, intf_val_idx, dir, pin_idx; - struct skl_module_res *res = NULL; - struct skl_module_iface *fmt = NULL; - struct skl_module *mod = NULL; - static struct skl_astate_param *astate_table; - static int astate_cfg_idx, count; - int i; - size_t size; - - if (skl->modules) { - mod = skl->modules[mod_idx]; - res = &mod->resources[res_val_idx]; - fmt = &mod->formats[intf_val_idx]; - } - - switch (tkn_elem->token) { - case SKL_TKN_U32_LIB_COUNT: - skl->lib_count = tkn_elem->value; - break; - - case SKL_TKN_U8_NUM_MOD: - skl->nr_modules = tkn_elem->value; - skl->modules = devm_kcalloc(dev, skl->nr_modules, - sizeof(*skl->modules), GFP_KERNEL); - if (!skl->modules) - return -ENOMEM; - - for (i = 0; i < skl->nr_modules; i++) { - skl->modules[i] = devm_kzalloc(dev, - sizeof(struct skl_module), GFP_KERNEL); - if (!skl->modules[i]) - return -ENOMEM; - } - break; - - case SKL_TKN_MM_U8_MOD_IDX: - mod_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_COUNT: - if (astate_table != NULL) { - dev_err(dev, "More than one entry for A-State count"); - return -EINVAL; - } - - if (tkn_elem->value > SKL_MAX_ASTATE_CFG) { - dev_err(dev, "Invalid A-State count %d\n", - tkn_elem->value); - return -EINVAL; - } - - size = struct_size(skl->cfg.astate_cfg, astate_table, - tkn_elem->value); - skl->cfg.astate_cfg = devm_kzalloc(dev, size, GFP_KERNEL); - if (!skl->cfg.astate_cfg) - return -ENOMEM; - - astate_table = skl->cfg.astate_cfg->astate_table; - count = skl->cfg.astate_cfg->count = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_IDX: - if (tkn_elem->value >= count) { - dev_err(dev, "Invalid A-State index %d\n", - tkn_elem->value); - return -EINVAL; - } - - astate_cfg_idx = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_KCPS: - astate_table[astate_cfg_idx].kcps = tkn_elem->value; - break; - - case SKL_TKN_U32_ASTATE_CLK_SRC: - astate_table[astate_cfg_idx].clk_src = tkn_elem->value; - break; - - case SKL_TKN_U8_IN_PIN_TYPE: - case SKL_TKN_U8_OUT_PIN_TYPE: - case SKL_TKN_U8_IN_QUEUE_COUNT: - case SKL_TKN_U8_OUT_QUEUE_COUNT: - case SKL_TKN_MM_U8_NUM_RES: - case SKL_TKN_MM_U8_NUM_INTF: - ret = skl_tplg_fill_mod_info(dev, tkn_elem, mod); - if (ret < 0) - return ret; - break; - - case SKL_TKN_U32_DIR_PIN_COUNT: - dir = tkn_elem->value & SKL_IN_DIR_BIT_MASK; - pin_idx = (tkn_elem->value & SKL_PIN_COUNT_MASK) >> 4; - break; - - case SKL_TKN_MM_U32_RES_ID: - if (!res) - return -EINVAL; - - res->id = tkn_elem->value; - res_val_idx = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_FMT_ID: - if (!fmt) - return -EINVAL; - - fmt->fmt_idx = tkn_elem->value; - intf_val_idx = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_CPS: - case SKL_TKN_MM_U32_DMA_SIZE: - case SKL_TKN_MM_U32_CPC: - case SKL_TKN_U32_MEM_PAGES: - case SKL_TKN_U32_OBS: - case SKL_TKN_U32_IBS: - case SKL_TKN_MM_U32_RES_PIN_ID: - case SKL_TKN_MM_U32_PIN_BUF: - ret = skl_tplg_fill_res_tkn(dev, tkn_elem, res, pin_idx, dir); - if (ret < 0) - return ret; - - break; - - case SKL_TKN_MM_U32_NUM_IN_FMT: - if (!fmt) - return -EINVAL; - - res->nr_input_pins = tkn_elem->value; - break; - - case SKL_TKN_MM_U32_NUM_OUT_FMT: - if (!fmt) - return -EINVAL; - - res->nr_output_pins = tkn_elem->value; - break; - - case SKL_TKN_U32_FMT_CH: - case SKL_TKN_U32_FMT_FREQ: - case SKL_TKN_U32_FMT_BIT_DEPTH: - case SKL_TKN_U32_FMT_SAMPLE_SIZE: - case SKL_TKN_U32_FMT_CH_CONFIG: - case SKL_TKN_U32_FMT_INTERLEAVE: - case SKL_TKN_U32_FMT_SAMPLE_TYPE: - case SKL_TKN_U32_FMT_CH_MAP: - case SKL_TKN_MM_U32_INTF_PIN_ID: - ret = skl_tplg_manifest_fill_fmt(dev, fmt, tkn_elem, - dir, pin_idx); - if (ret < 0) - return ret; - break; - - default: - dev_err(dev, "Not a manifest token %d\n", tkn_elem->token); - return -EINVAL; - } - tkn_count++; - - return tkn_count; -} - -/* - * Fill the manifest structure by parsing the tokens based on the - * type. - */ -static int skl_tplg_get_manifest_tkn(struct device *dev, - char *pvt_data, struct skl_dev *skl, - int block_size) -{ - int tkn_count = 0, ret; - int off = 0, tuple_size = 0; - u8 uuid_index = 0; - struct snd_soc_tplg_vendor_array *array; - struct snd_soc_tplg_vendor_value_elem *tkn_elem; - - if (block_size <= 0) - return -EINVAL; - - while (tuple_size < block_size) { - array = (struct snd_soc_tplg_vendor_array *)(pvt_data + off); - off += array->size; - switch (array->type) { - case SND_SOC_TPLG_TUPLE_TYPE_STRING: - ret = skl_tplg_get_str_tkn(dev, array, skl); - - if (ret < 0) - return ret; - tkn_count = ret; - - tuple_size += tkn_count * - sizeof(struct snd_soc_tplg_vendor_string_elem); - continue; - - case SND_SOC_TPLG_TUPLE_TYPE_UUID: - if (array->uuid->token != SKL_TKN_UUID) { - dev_err(dev, "Not an UUID token: %d\n", - array->uuid->token); - return -EINVAL; - } - if (uuid_index >= skl->nr_modules) { - dev_err(dev, "Too many UUID tokens\n"); - return -EINVAL; - } - import_guid(&skl->modules[uuid_index++]->uuid, - array->uuid->uuid); - - tuple_size += sizeof(*array->uuid); - continue; - - default: - tkn_elem = array->value; - tkn_count = 0; - break; - } - - while (tkn_count <= array->num_elems - 1) { - ret = skl_tplg_get_int_tkn(dev, - tkn_elem, skl); - if (ret < 0) - return ret; - - tkn_count = tkn_count + ret; - tkn_elem++; - } - tuple_size += (tkn_count * sizeof(*tkn_elem)); - tkn_count = 0; - } - - return off; -} - -/* - * Parse manifest private data for tokens. The private data block is - * preceded by descriptors for type and size of data block. - */ -static int skl_tplg_get_manifest_data(struct snd_soc_tplg_manifest *manifest, - struct device *dev, struct skl_dev *skl) -{ - struct snd_soc_tplg_vendor_array *array; - int num_blocks, block_size = 0, block_type, off = 0; - char *data; - int ret; - - /* Read the NUM_DATA_BLOCKS descriptor */ - array = (struct snd_soc_tplg_vendor_array *)manifest->priv.data; - ret = skl_tplg_get_desc_blocks(dev, array); - if (ret < 0) - return ret; - num_blocks = ret; - - off += array->size; - /* Read the BLOCK_TYPE and BLOCK_SIZE descriptor */ - while (num_blocks > 0) { - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_type = ret; - off += array->size; - - array = (struct snd_soc_tplg_vendor_array *) - (manifest->priv.data + off); - - ret = skl_tplg_get_desc_blocks(dev, array); - - if (ret < 0) - return ret; - block_size = ret; - off += array->size; - - data = (manifest->priv.data + off); - - if (block_type == SKL_TYPE_TUPLE) { - ret = skl_tplg_get_manifest_tkn(dev, data, skl, - block_size); - - if (ret < 0) - return ret; - - --num_blocks; - } else { - return -EINVAL; - } - off += ret; - } - - return 0; -} - -static int skl_manifest_load(struct snd_soc_component *cmpnt, int index, - struct snd_soc_tplg_manifest *manifest) -{ - struct hdac_bus *bus = snd_soc_component_get_drvdata(cmpnt); - struct skl_dev *skl = bus_to_skl(bus); - - /* proceed only if we have private data defined */ - if (manifest->priv.size == 0) - return 0; - - skl_tplg_get_manifest_data(manifest, bus->dev, skl); - - if (skl->lib_count > SKL_MAX_LIB) { - dev_err(bus->dev, "Exceeding max Library count. Got:%d\n", - skl->lib_count); - return -EINVAL; - } - - return 0; -} - -static int skl_tplg_complete(struct snd_soc_component *component) -{ - struct snd_soc_dobj *dobj; - struct snd_soc_acpi_mach *mach; - struct snd_ctl_elem_value *val; - int i; - - val = kmalloc(sizeof(*val), GFP_KERNEL); - if (!val) - return -ENOMEM; - - mach = dev_get_platdata(component->card->dev); - list_for_each_entry(dobj, &component->dobj_list, list) { - struct snd_kcontrol *kcontrol = dobj->control.kcontrol; - struct soc_enum *se; - char **texts; - char chan_text[4]; - - if (dobj->type != SND_SOC_DOBJ_ENUM || !kcontrol || - kcontrol->put != skl_tplg_multi_config_set_dmic) - continue; - - se = (struct soc_enum *)kcontrol->private_value; - texts = dobj->control.dtexts; - sprintf(chan_text, "c%d", mach->mach_params.dmic_num); - - for (i = 0; i < se->items; i++) { - if (strstr(texts[i], chan_text)) { - memset(val, 0, sizeof(*val)); - val->value.enumerated.item[0] = i; - kcontrol->put(kcontrol, val); - } - } - } - - kfree(val); - return 0; -} - -static struct snd_soc_tplg_ops skl_tplg_ops = { - .widget_load = skl_tplg_widget_load, - .control_load = skl_tplg_control_load, - .bytes_ext_ops = skl_tlv_ops, - .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), - .io_ops = skl_tplg_kcontrol_ops, - .io_ops_count = ARRAY_SIZE(skl_tplg_kcontrol_ops), - .manifest = skl_manifest_load, - .dai_load = skl_dai_load, - .complete = skl_tplg_complete, -}; - -/* - * A pipe can have multiple modules, each of them will be a DAPM widget as - * well. While managing a pipeline we need to get the list of all the - * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() - * helps to get the SKL type widgets in that pipeline - */ -static int skl_tplg_create_pipe_widget_list(struct snd_soc_component *component) -{ - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mcfg = NULL; - struct skl_pipe_module *p_module = NULL; - struct skl_pipe *pipe; - - list_for_each_entry(w, &component->card->widgets, list) { - if (is_skl_dsp_widget_type(w, component->dev) && w->priv) { - mcfg = w->priv; - pipe = mcfg->pipe; - - p_module = devm_kzalloc(component->dev, - sizeof(*p_module), GFP_KERNEL); - if (!p_module) - return -ENOMEM; - - p_module->w = w; - list_add_tail(&p_module->node, &pipe->w_list); - } - } - - return 0; -} - -static void skl_tplg_set_pipe_type(struct skl_dev *skl, struct skl_pipe *pipe) -{ - struct skl_pipe_module *w_module; - struct snd_soc_dapm_widget *w; - struct skl_module_cfg *mconfig; - bool host_found = false, link_found = false; - - list_for_each_entry(w_module, &pipe->w_list, node) { - w = w_module->w; - mconfig = w->priv; - - if (mconfig->dev_type == SKL_DEVICE_HDAHOST) - host_found = true; - else if (mconfig->dev_type != SKL_DEVICE_NONE) - link_found = true; - } - - if (host_found && link_found) - pipe->passthru = true; - else - pipe->passthru = false; -} - -/* - * SKL topology init routine - */ -int skl_tplg_init(struct snd_soc_component *component, struct hdac_bus *bus) -{ - int ret; - const struct firmware *fw; - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl; - - ret = request_firmware(&fw, skl->tplg_name, bus->dev); - if (ret < 0) { - char alt_tplg_name[64]; - - snprintf(alt_tplg_name, sizeof(alt_tplg_name), "%s-tplg.bin", - skl->mach->drv_name); - dev_info(bus->dev, "tplg fw %s load failed with %d, trying alternative tplg name %s", - skl->tplg_name, ret, alt_tplg_name); - - ret = request_firmware(&fw, alt_tplg_name, bus->dev); - if (!ret) - goto component_load; - - dev_info(bus->dev, "tplg %s failed with %d, falling back to dfw_sst.bin", - alt_tplg_name, ret); - - ret = request_firmware(&fw, "dfw_sst.bin", bus->dev); - if (ret < 0) { - dev_err(bus->dev, "Fallback tplg fw %s load failed with %d\n", - "dfw_sst.bin", ret); - return ret; - } - } - -component_load: - ret = snd_soc_tplg_component_load(component, &skl_tplg_ops, fw); - if (ret < 0) { - dev_err(bus->dev, "tplg component load failed%d\n", ret); - goto err; - } - - ret = skl_tplg_create_pipe_widget_list(component); - if (ret < 0) { - dev_err(bus->dev, "tplg create pipe widget list failed%d\n", - ret); - goto err; - } - - list_for_each_entry(ppl, &skl->ppl_list, node) - skl_tplg_set_pipe_type(skl, ppl->pipe); - -err: - release_firmware(fw); - return ret; -} - -void skl_tplg_exit(struct snd_soc_component *component, struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct skl_pipeline *ppl, *tmp; - - list_for_each_entry_safe(ppl, tmp, &skl->ppl_list, node) - list_del(&ppl->node); - - /* clean up topology */ - snd_soc_tplg_component_remove(component); -} diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h deleted file mode 100644 index 30a0977af943..000000000000 --- a/sound/soc/intel/skylake/skl-topology.h +++ /dev/null @@ -1,524 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl_topology.h - Intel HDA Platform topology header file - * - * Copyright (C) 2014-15 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SKL_TOPOLOGY_H__ -#define __SKL_TOPOLOGY_H__ - -#include <linux/types.h> - -#include <sound/hdaudio_ext.h> -#include <sound/soc.h> -#include <uapi/sound/skl-tplg-interface.h> -#include "skl.h" - -#define BITS_PER_BYTE 8 -#define MAX_TS_GROUPS 8 -#define MAX_DMIC_TS_GROUPS 4 -#define MAX_FIXED_DMIC_PARAMS_SIZE 727 - -/* Maximum number of coefficients up down mixer module */ -#define UP_DOWN_MIXER_MAX_COEFF 8 - -#define MODULE_MAX_IN_PINS 8 -#define MODULE_MAX_OUT_PINS 8 - -#define SKL_MIC_CH_SUPPORT 4 -#define SKL_MIC_MAX_CH_SUPPORT 8 -#define SKL_DEFAULT_MIC_SEL_GAIN 0x3FF -#define SKL_MIC_SEL_SWITCH 0x3 - -#define SKL_OUTPUT_PIN 0 -#define SKL_INPUT_PIN 1 -#define SKL_MAX_PATH_CONFIGS 8 -#define SKL_MAX_MODULES_IN_PIPE 8 -#define SKL_MAX_MODULE_FORMATS 32 -#define SKL_MAX_MODULE_RESOURCES 32 - -enum skl_channel_index { - SKL_CHANNEL_LEFT = 0, - SKL_CHANNEL_RIGHT = 1, - SKL_CHANNEL_CENTER = 2, - SKL_CHANNEL_LEFT_SURROUND = 3, - SKL_CHANNEL_CENTER_SURROUND = 3, - SKL_CHANNEL_RIGHT_SURROUND = 4, - SKL_CHANNEL_LFE = 7, - SKL_CHANNEL_INVALID = 0xF, -}; - -enum skl_bitdepth { - SKL_DEPTH_8BIT = 8, - SKL_DEPTH_16BIT = 16, - SKL_DEPTH_24BIT = 24, - SKL_DEPTH_32BIT = 32, - SKL_DEPTH_INVALID -}; - - -enum skl_s_freq { - SKL_FS_8000 = 8000, - SKL_FS_11025 = 11025, - SKL_FS_12000 = 12000, - SKL_FS_16000 = 16000, - SKL_FS_22050 = 22050, - SKL_FS_24000 = 24000, - SKL_FS_32000 = 32000, - SKL_FS_44100 = 44100, - SKL_FS_48000 = 48000, - SKL_FS_64000 = 64000, - SKL_FS_88200 = 88200, - SKL_FS_96000 = 96000, - SKL_FS_128000 = 128000, - SKL_FS_176400 = 176400, - SKL_FS_192000 = 192000, - SKL_FS_INVALID -}; - -#define SKL_MAX_PARAMS_TYPES 4 - -enum skl_widget_type { - SKL_WIDGET_VMIXER = 1, - SKL_WIDGET_MIXER = 2, - SKL_WIDGET_PGA = 3, - SKL_WIDGET_MUX = 4 -}; - -struct skl_audio_data_format { - enum skl_s_freq s_freq; - enum skl_bitdepth bit_depth; - u32 channel_map; - enum skl_ch_cfg ch_cfg; - enum skl_interleaving interleaving; - u8 number_of_channels; - u8 valid_bit_depth; - u8 sample_type; - u8 reserved; -} __packed; - -struct skl_base_cfg { - u32 cpc; - u32 ibs; - u32 obs; - u32 is_pages; - struct skl_audio_data_format audio_fmt; -}; - -struct skl_cpr_gtw_cfg { - u32 node_id; - u32 dma_buffer_size; - u32 config_length; - /* not mandatory; required only for DMIC/I2S */ - struct { - u32 gtw_attrs; - u32 data[]; - } config_data; -} __packed; - -struct skl_dma_control { - u32 node_id; - u32 config_length; - u32 config_data[]; -} __packed; - -struct skl_cpr_cfg { - struct skl_base_cfg base_cfg; - struct skl_audio_data_format out_fmt; - u32 cpr_feature_mask; - struct skl_cpr_gtw_cfg gtw_cfg; -} __packed; - -struct skl_cpr_pin_fmt { - u32 sink_id; - struct skl_audio_data_format src_fmt; - struct skl_audio_data_format dst_fmt; -} __packed; - -struct skl_src_module_cfg { - struct skl_base_cfg base_cfg; - enum skl_s_freq src_cfg; -} __packed; - -struct skl_up_down_mixer_cfg { - struct skl_base_cfg base_cfg; - enum skl_ch_cfg out_ch_cfg; - /* This should be set to 1 if user coefficients are required */ - u32 coeff_sel; - /* Pass the user coeff in this array */ - s32 coeff[UP_DOWN_MIXER_MAX_COEFF]; - u32 ch_map; -} __packed; - -struct skl_pin_format { - u32 pin_idx; - u32 buf_size; - struct skl_audio_data_format audio_fmt; -} __packed; - -struct skl_base_cfg_ext { - u16 nr_input_pins; - u16 nr_output_pins; - u8 reserved[8]; - u32 priv_param_length; - /* Input pin formats followed by output ones. */ - struct skl_pin_format pins_fmt[]; -} __packed; - -struct skl_algo_cfg { - struct skl_base_cfg base_cfg; - char params[]; -} __packed; - -struct skl_base_outfmt_cfg { - struct skl_base_cfg base_cfg; - struct skl_audio_data_format out_fmt; -} __packed; - -enum skl_dma_type { - SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, - SKL_DMA_HDA_HOST_INPUT_CLASS = 1, - SKL_DMA_HDA_HOST_INOUT_CLASS = 2, - SKL_DMA_HDA_LINK_OUTPUT_CLASS = 8, - SKL_DMA_HDA_LINK_INPUT_CLASS = 9, - SKL_DMA_HDA_LINK_INOUT_CLASS = 0xA, - SKL_DMA_DMIC_LINK_INPUT_CLASS = 0xB, - SKL_DMA_I2S_LINK_OUTPUT_CLASS = 0xC, - SKL_DMA_I2S_LINK_INPUT_CLASS = 0xD, -}; - -union skl_ssp_dma_node { - u8 val; - struct { - u8 time_slot_index:4; - u8 i2s_instance:4; - } dma_node; -}; - -union skl_connector_node_id { - u32 val; - struct { - u32 vindex:8; - u32 dma_type:4; - u32 rsvd:20; - } node; -}; - -struct skl_module_fmt { - u32 channels; - u32 s_freq; - u32 bit_depth; - u32 valid_bit_depth; - u32 ch_cfg; - u32 interleaving_style; - u32 sample_type; - u32 ch_map; -}; - -struct skl_module_cfg; - -struct skl_mod_inst_map { - u16 mod_id; - u16 inst_id; -}; - -struct skl_uuid_inst_map { - u16 inst_id; - u16 reserved; - guid_t mod_uuid; -} __packed; - -struct skl_kpb_params { - u32 num_modules; - union { - DECLARE_FLEX_ARRAY(struct skl_mod_inst_map, map); - DECLARE_FLEX_ARRAY(struct skl_uuid_inst_map, map_uuid); - } u; -}; - -struct skl_module_inst_id { - guid_t mod_uuid; - int module_id; - u32 instance_id; - int pvt_id; -}; - -enum skl_module_pin_state { - SKL_PIN_UNBIND = 0, - SKL_PIN_BIND_DONE = 1, -}; - -struct skl_module_pin { - struct skl_module_inst_id id; - bool is_dynamic; - bool in_use; - enum skl_module_pin_state pin_state; - struct skl_module_cfg *tgt_mcfg; -}; - -struct skl_specific_cfg { - u32 set_params; - u32 param_id; - u32 caps_size; - u32 *caps; -}; - -enum skl_pipe_state { - SKL_PIPE_INVALID = 0, - SKL_PIPE_CREATED = 1, - SKL_PIPE_PAUSED = 2, - SKL_PIPE_STARTED = 3, - SKL_PIPE_RESET = 4 -}; - -struct skl_pipe_module { - struct snd_soc_dapm_widget *w; - struct list_head node; -}; - -struct skl_pipe_params { - u8 host_dma_id; - u8 link_dma_id; - u32 ch; - u32 s_freq; - u32 s_fmt; - u32 s_cont; - u8 linktype; - snd_pcm_format_t format; - int link_index; - int stream; - unsigned int host_bps; - unsigned int link_bps; -}; - -struct skl_pipe_fmt { - u32 freq; - u8 channels; - u8 bps; -}; - -struct skl_pipe_mcfg { - u8 res_idx; - u8 fmt_idx; -}; - -struct skl_path_config { - u8 mem_pages; - struct skl_pipe_fmt in_fmt; - struct skl_pipe_fmt out_fmt; -}; - -struct skl_pipe { - u8 ppl_id; - u8 pipe_priority; - u16 conn_type; - u32 memory_pages; - u8 lp_mode; - struct skl_pipe_params *p_params; - enum skl_pipe_state state; - u8 direction; - u8 cur_config_idx; - u8 nr_cfgs; - struct skl_path_config configs[SKL_MAX_PATH_CONFIGS]; - struct list_head w_list; - bool passthru; -}; - -enum skl_module_state { - SKL_MODULE_UNINIT = 0, - SKL_MODULE_INIT_DONE = 1, - SKL_MODULE_BIND_DONE = 2, -}; - -enum d0i3_capability { - SKL_D0I3_NONE = 0, - SKL_D0I3_STREAMING = 1, - SKL_D0I3_NON_STREAMING = 2, -}; - -struct skl_module_pin_fmt { - u8 id; - struct skl_module_fmt fmt; -}; - -struct skl_module_iface { - u8 fmt_idx; - u8 nr_in_fmt; - u8 nr_out_fmt; - struct skl_module_pin_fmt inputs[MAX_IN_QUEUE]; - struct skl_module_pin_fmt outputs[MAX_OUT_QUEUE]; -}; - -struct skl_module_pin_resources { - u8 pin_index; - u32 buf_size; -}; - -struct skl_module_res { - u8 id; - u32 is_pages; - u32 ibs; - u32 obs; - u32 dma_buffer_size; - u32 cpc; - u8 nr_input_pins; - u8 nr_output_pins; - struct skl_module_pin_resources input[MAX_IN_QUEUE]; - struct skl_module_pin_resources output[MAX_OUT_QUEUE]; -}; - -struct skl_module { - guid_t uuid; - u8 loadable; - u8 input_pin_type; - u8 output_pin_type; - u8 max_input_pins; - u8 max_output_pins; - u8 nr_resources; - u8 nr_interfaces; - struct skl_module_res resources[SKL_MAX_MODULE_RESOURCES]; - struct skl_module_iface formats[SKL_MAX_MODULE_FORMATS]; -}; - -struct skl_module_cfg { - u8 guid[16]; - struct skl_module_inst_id id; - struct skl_module *module; - int res_idx; - int fmt_idx; - int fmt_cfg_idx; - u8 domain; - bool homogenous_inputs; - bool homogenous_outputs; - struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS]; - struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS]; - u8 max_in_queue; - u8 max_out_queue; - u8 in_queue_mask; - u8 out_queue_mask; - u8 in_queue; - u8 out_queue; - u8 is_loadable; - u8 core_id; - u8 dev_type; - u8 dma_id; - u8 time_slot; - u8 dmic_ch_combo_index; - u32 dmic_ch_type; - u32 params_fixup; - u32 converter; - u32 vbus_id; - u32 mem_pages; - enum d0i3_capability d0i3_caps; - u32 dma_buffer_size; /* in milli seconds */ - struct skl_module_pin *m_in_pin; - struct skl_module_pin *m_out_pin; - enum skl_module_type m_type; - enum skl_hw_conn_type hw_conn_type; - enum skl_module_state m_state; - struct skl_pipe *pipe; - struct skl_specific_cfg formats_config[SKL_MAX_PARAMS_TYPES]; - struct skl_pipe_mcfg mod_cfg[SKL_MAX_MODULES_IN_PIPE]; -}; - -struct skl_algo_data { - u32 param_id; - u32 set_params; - u32 max; - u32 size; - char *params; -}; - -struct skl_pipeline { - struct skl_pipe *pipe; - struct list_head node; -}; - -struct skl_module_deferred_bind { - struct skl_module_cfg *src; - struct skl_module_cfg *dst; - struct list_head node; -}; - -struct skl_mic_sel_config { - u16 mic_switch; - u16 flags; - u16 blob[SKL_MIC_MAX_CH_SUPPORT][SKL_MIC_MAX_CH_SUPPORT]; -} __packed; - -enum skl_channel { - SKL_CH_MONO = 1, - SKL_CH_STEREO = 2, - SKL_CH_TRIO = 3, - SKL_CH_QUATRO = 4, -}; - -static inline struct skl_dev *get_skl_ctx(struct device *dev) -{ - struct hdac_bus *bus = dev_get_drvdata(dev); - - return bus_to_skl(bus); -} - -int skl_tplg_be_update_params(struct snd_soc_dai *dai, - struct skl_pipe_params *params); -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id); -void skl_tplg_set_be_dmic_config(struct snd_soc_dai *dai, - struct skl_pipe_params *params, int stream); -int skl_tplg_init(struct snd_soc_component *component, - struct hdac_bus *bus); -void skl_tplg_exit(struct snd_soc_component *component, - struct hdac_bus *bus); -struct skl_module_cfg *skl_tplg_fe_get_cpr_module( - struct snd_soc_dai *dai, int stream); -int skl_tplg_update_pipe_params(struct device *dev, - struct skl_module_cfg *mconfig, struct skl_pipe_params *params); - -void skl_tplg_d0i3_get(struct skl_dev *skl, enum d0i3_capability caps); -void skl_tplg_d0i3_put(struct skl_dev *skl, enum d0i3_capability caps); - -int skl_create_pipeline(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_run_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_pause_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_delete_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_stop_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_reset_pipe(struct skl_dev *skl, struct skl_pipe *pipe); - -int skl_init_module(struct skl_dev *skl, struct skl_module_cfg *mconfig); - -int skl_bind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_mcfg, struct skl_module_cfg *dst_mcfg); - -int skl_unbind_modules(struct skl_dev *skl, struct skl_module_cfg - *src_mcfg, struct skl_module_cfg *dst_mcfg); - -int skl_set_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg); -int skl_get_module_params(struct skl_dev *skl, u32 *params, int size, - u32 param_id, struct skl_module_cfg *mcfg); - -struct skl_module_cfg *skl_tplg_be_get_cpr_module(struct snd_soc_dai *dai, - int stream); -enum skl_bitdepth skl_get_bit_depth(int params); -int skl_pcm_host_dma_prepare(struct device *dev, - struct skl_pipe_params *params); -int skl_pcm_link_dma_prepare(struct device *dev, - struct skl_pipe_params *params); - -int skl_dai_load(struct snd_soc_component *cmp, int index, - struct snd_soc_dai_driver *dai_drv, - struct snd_soc_tplg_pcm *pcm, struct snd_soc_dai *dai); -void skl_tplg_add_moduleid_in_bind_params(struct skl_dev *skl, - struct snd_soc_dapm_widget *w); -#endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c deleted file mode 100644 index 117125187793..000000000000 --- a/sound/soc/intel/skylake/skl.c +++ /dev/null @@ -1,1177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * skl.c - Implementation of ASoC Intel SKL HD Audio driver - * - * Copyright (C) 2014-2015 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * - * Derived mostly from Intel HDA driver with following copyrights: - * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> - * PeiSen Hou <pshou@realtek.com.tw> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/pm_runtime.h> -#include <linux/platform_device.h> -#include <linux/firmware.h> -#include <linux/delay.h> -#include <sound/pcm.h> -#include <sound/soc-acpi.h> -#include <sound/soc-acpi-intel-match.h> -#include <sound/hda_register.h> -#include <sound/hdaudio.h> -#include <sound/hda_i915.h> -#include <sound/hda_codec.h> -#include <sound/intel-nhlt.h> -#include <sound/intel-dsp-config.h> -#include "skl.h" -#include "skl-sst-dsp.h" -#include "skl-sst-ipc.h" - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) -#include "../../../soc/codecs/hdac_hda.h" -#endif -static int skl_pci_binding; -module_param_named(pci_binding, skl_pci_binding, int, 0444); -MODULE_PARM_DESC(pci_binding, "PCI binding (0=auto, 1=only legacy, 2=only asoc"); - -/* - * initialize the PCI registers - */ -static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, - unsigned char mask, unsigned char val) -{ - unsigned char data; - - pci_read_config_byte(pci, reg, &data); - data &= ~mask; - data |= (val & mask); - pci_write_config_byte(pci, reg, data); -} - -static void skl_init_pci(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - - /* - * Clear bits 0-2 of PCI register TCSEL (at offset 0x44) - * TCSEL == Traffic Class Select Register, which sets PCI express QOS - * Ensuring these bits are 0 clears playback static on some HD Audio - * codecs. - * The PCI register TCSEL is defined in the Intel manuals. - */ - dev_dbg(bus->dev, "Clearing TCSEL\n"); - skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); -} - -static void update_pci_dword(struct pci_dev *pci, - unsigned int reg, u32 mask, u32 val) -{ - u32 data = 0; - - pci_read_config_dword(pci, reg, &data); - data &= ~mask; - data |= (val & mask); - pci_write_config_dword(pci, reg, data); -} - -/* - * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits - * - * @dev: device pointer - * @enable: enable/disable flag - */ -static void skl_enable_miscbdcge(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - u32 val; - - val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; - - update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); -} - -/** - * skl_clock_power_gating: Enable/Disable clock and power gating - * - * @dev: Device pointer - * @enable: Enable/Disable flag - */ -static void skl_clock_power_gating(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - u32 val; - - /* Update PDCGE bit of CGCTL register */ - val = enable ? AZX_CGCTL_ADSPDCGE : 0; - update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_ADSPDCGE, val); - - /* Update L1SEN bit of EM2 register */ - val = enable ? AZX_REG_VS_EM2_L1SEN : 0; - snd_hdac_chip_updatel(bus, VS_EM2, AZX_REG_VS_EM2_L1SEN, val); - - /* Update ADSPPGD bit of PGCTL register */ - val = enable ? 0 : AZX_PGCTL_ADSPPGD; - update_pci_dword(pci, AZX_PCIREG_PGCTL, AZX_PGCTL_ADSPPGD, val); -} - -/* - * While performing reset, controller may not come back properly causing - * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset - * (init chip) and then again set CGCTL.MISCBDCGE to 1 - */ -static int skl_init_chip(struct hdac_bus *bus, bool full_reset) -{ - struct hdac_ext_link *hlink; - int ret; - - snd_hdac_set_codec_wakeup(bus, true); - skl_enable_miscbdcge(bus->dev, false); - ret = snd_hdac_bus_init_chip(bus, full_reset); - - /* Reset stream-to-link mapping */ - list_for_each_entry(hlink, &bus->hlink_list, list) - writel(0, hlink->ml_addr + AZX_REG_ML_LOSIDV); - - skl_enable_miscbdcge(bus->dev, true); - snd_hdac_set_codec_wakeup(bus, false); - - return ret; -} - -void skl_update_d0i3c(struct device *dev, bool enable) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - u8 reg; - int timeout = 50; - - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - /* Do not write to D0I3C until command in progress bit is cleared */ - while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { - udelay(10); - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - } - - /* Highly unlikely. But if it happens, flag error explicitly */ - if (!timeout) { - dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); - return; - } - - if (enable) - reg = reg | AZX_REG_VS_D0I3C_I3; - else - reg = reg & (~AZX_REG_VS_D0I3C_I3); - - snd_hdac_chip_writeb(bus, VS_D0I3C, reg); - - timeout = 50; - /* Wait for cmd in progress to be cleared before exiting the function */ - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { - udelay(10); - reg = snd_hdac_chip_readb(bus, VS_D0I3C); - } - - /* Highly unlikely. But if it happens, flag error explicitly */ - if (!timeout) { - dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); - return; - } - - dev_dbg(bus->dev, "D0I3C register = 0x%x\n", - snd_hdac_chip_readb(bus, VS_D0I3C)); -} - -/** - * skl_dum_set - set DUM bit in EM2 register - * @bus: HD-audio core bus - * - * Addresses incorrect position reporting for capture streams. - * Used on device power up. - */ -static void skl_dum_set(struct hdac_bus *bus) -{ - /* For the DUM bit to be set, CRST needs to be out of reset state */ - if (!(snd_hdac_chip_readb(bus, GCTL) & AZX_GCTL_RESET)) { - skl_enable_miscbdcge(bus->dev, false); - snd_hdac_bus_exit_link_reset(bus); - skl_enable_miscbdcge(bus->dev, true); - } - - snd_hdac_chip_updatel(bus, VS_EM2, AZX_VS_EM2_DUM, AZX_VS_EM2_DUM); -} - -/* called from IRQ */ -static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) -{ - snd_pcm_period_elapsed(hstr->substream); -} - -static irqreturn_t skl_interrupt(int irq, void *dev_id) -{ - struct hdac_bus *bus = dev_id; - u32 status; - - if (!pm_runtime_active(bus->dev)) - return IRQ_NONE; - - spin_lock(&bus->reg_lock); - - status = snd_hdac_chip_readl(bus, INTSTS); - if (status == 0 || status == 0xffffffff) { - spin_unlock(&bus->reg_lock); - return IRQ_NONE; - } - - /* clear rirb int */ - status = snd_hdac_chip_readb(bus, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) - snd_hdac_bus_update_rirb(bus); - snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); - } - - spin_unlock(&bus->reg_lock); - - return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; -} - -static irqreturn_t skl_threaded_handler(int irq, void *dev_id) -{ - struct hdac_bus *bus = dev_id; - u32 status; - - status = snd_hdac_chip_readl(bus, INTSTS); - - snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update); - - return IRQ_HANDLED; -} - -static int skl_acquire_irq(struct hdac_bus *bus, int do_disconnect) -{ - struct skl_dev *skl = bus_to_skl(bus); - int ret; - - ret = request_threaded_irq(skl->pci->irq, skl_interrupt, - skl_threaded_handler, - IRQF_SHARED, - KBUILD_MODNAME, bus); - if (ret) { - dev_err(bus->dev, - "unable to grab IRQ %d, disabling device\n", - skl->pci->irq); - return ret; - } - - bus->irq = skl->pci->irq; - pci_intx(skl->pci, 1); - - return 0; -} - -static int skl_suspend_late(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - - return skl_suspend_late_dsp(skl); -} - -#ifdef CONFIG_PM -static int _skl_suspend(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct pci_dev *pci = to_pci_dev(bus->dev); - int ret; - - snd_hdac_ext_bus_link_power_down_all(bus); - - ret = skl_suspend_dsp(skl); - if (ret < 0) - return ret; - - snd_hdac_bus_stop_chip(bus); - update_pci_dword(pci, AZX_PCIREG_PGCTL, - AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK); - skl_enable_miscbdcge(bus->dev, false); - snd_hdac_bus_enter_link_reset(bus); - skl_enable_miscbdcge(bus->dev, true); - skl_cleanup_resources(skl); - - return 0; -} - -static int _skl_resume(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - - skl_init_pci(skl); - skl_dum_set(bus); - skl_init_chip(bus, true); - - return skl_resume_dsp(skl); -} -#endif - -#ifdef CONFIG_PM_SLEEP -/* - * power management - */ -static int skl_suspend(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - int ret; - - /* - * Do not suspend if streams which are marked ignore suspend are - * running, we need to save the state for these and continue - */ - if (skl->supend_active) { - /* turn off the links and stop the CORB/RIRB DMA if it is On */ - snd_hdac_ext_bus_link_power_down_all(bus); - - if (bus->cmd_dma_state) - snd_hdac_bus_stop_cmd_io(bus); - - enable_irq_wake(bus->irq); - pci_save_state(pci); - } else { - ret = _skl_suspend(bus); - if (ret < 0) - return ret; - skl->fw_loaded = false; - } - - return 0; -} - -static int skl_resume(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - struct hdac_ext_link *hlink; - int ret; - - /* - * resume only when we are not in suspend active, otherwise need to - * restore the device - */ - if (skl->supend_active) { - pci_restore_state(pci); - snd_hdac_ext_bus_link_power_up_all(bus); - disable_irq_wake(bus->irq); - /* - * turn On the links which are On before active suspend - * and start the CORB/RIRB DMA if On before - * active suspend. - */ - list_for_each_entry(hlink, &bus->hlink_list, list) { - if (hlink->ref_count) - snd_hdac_ext_bus_link_power_up(hlink); - } - - ret = 0; - if (bus->cmd_dma_state) - snd_hdac_bus_init_cmd_io(bus); - } else { - ret = _skl_resume(bus); - } - - return ret; -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM -static int skl_runtime_suspend(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - - dev_dbg(bus->dev, "in %s\n", __func__); - - return _skl_suspend(bus); -} - -static int skl_runtime_resume(struct device *dev) -{ - struct pci_dev *pci = to_pci_dev(dev); - struct hdac_bus *bus = pci_get_drvdata(pci); - - dev_dbg(bus->dev, "in %s\n", __func__); - - return _skl_resume(bus); -} -#endif /* CONFIG_PM */ - -static const struct dev_pm_ops skl_pm = { - SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) - SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) - .suspend_late = skl_suspend_late, -}; - -/* - * destructor - */ -static int skl_free(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - - skl->init_done = 0; /* to be sure */ - - snd_hdac_stop_streams_and_chip(bus); - - if (bus->irq >= 0) - free_irq(bus->irq, (void *)bus); - snd_hdac_bus_free_stream_pages(bus); - snd_hdac_ext_stream_free_all(bus); - snd_hdac_ext_link_free_all(bus); - - if (bus->remap_addr) - iounmap(bus->remap_addr); - - pci_release_regions(skl->pci); - pci_disable_device(skl->pci); - - snd_hdac_ext_bus_exit(bus); - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - snd_hdac_i915_exit(bus); - } - - return 0; -} - -/* - * For each ssp there are 3 clocks (mclk/sclk/sclkfs). - * e.g. for ssp0, clocks will be named as - * "ssp0_mclk", "ssp0_sclk", "ssp0_sclkfs" - * So for skl+, there are 6 ssps, so 18 clocks will be created. - */ -static struct skl_ssp_clk skl_ssp_clks[] = { - {.name = "ssp0_mclk"}, {.name = "ssp1_mclk"}, {.name = "ssp2_mclk"}, - {.name = "ssp3_mclk"}, {.name = "ssp4_mclk"}, {.name = "ssp5_mclk"}, - {.name = "ssp0_sclk"}, {.name = "ssp1_sclk"}, {.name = "ssp2_sclk"}, - {.name = "ssp3_sclk"}, {.name = "ssp4_sclk"}, {.name = "ssp5_sclk"}, - {.name = "ssp0_sclkfs"}, {.name = "ssp1_sclkfs"}, - {.name = "ssp2_sclkfs"}, - {.name = "ssp3_sclkfs"}, {.name = "ssp4_sclkfs"}, - {.name = "ssp5_sclkfs"}, -}; - -static struct snd_soc_acpi_mach *skl_find_hda_machine(struct skl_dev *skl, - struct snd_soc_acpi_mach *machines) -{ - struct snd_soc_acpi_mach *mach; - - /* point to common table */ - mach = snd_soc_acpi_intel_hda_machines; - - /* all entries in the machine table use the same firmware */ - mach->fw_filename = machines->fw_filename; - - return mach; -} - -static int skl_find_machine(struct skl_dev *skl, void *driver_data) -{ - struct hdac_bus *bus = skl_to_bus(skl); - struct snd_soc_acpi_mach *mach = driver_data; - struct skl_machine_pdata *pdata; - - mach = snd_soc_acpi_find_machine(mach); - if (!mach) { - dev_dbg(bus->dev, "No matching I2S machine driver found\n"); - mach = skl_find_hda_machine(skl, driver_data); - if (!mach) { - dev_err(bus->dev, "No matching machine driver found\n"); - return -ENODEV; - } - } - - skl->mach = mach; - skl->fw_name = mach->fw_filename; - pdata = mach->pdata; - - if (pdata) { - skl->use_tplg_pcm = pdata->use_tplg_pcm; - mach->mach_params.dmic_num = - intel_nhlt_get_dmic_geo(&skl->pci->dev, - skl->nhlt); - } - - return 0; -} - -static int skl_machine_device_register(struct skl_dev *skl) -{ - struct snd_soc_acpi_mach *mach = skl->mach; - struct hdac_bus *bus = skl_to_bus(skl); - struct platform_device *pdev; - int ret; - - pdev = platform_device_alloc(mach->drv_name, -1); - if (pdev == NULL) { - dev_err(bus->dev, "platform device alloc failed\n"); - return -EIO; - } - - mach->mach_params.platform = dev_name(bus->dev); - mach->mach_params.codec_mask = bus->codec_mask; - - ret = platform_device_add_data(pdev, (const void *)mach, sizeof(*mach)); - if (ret) { - dev_err(bus->dev, "failed to add machine device platform data\n"); - platform_device_put(pdev); - return ret; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(bus->dev, "failed to add machine device\n"); - platform_device_put(pdev); - return -EIO; - } - - - skl->i2s_dev = pdev; - - return 0; -} - -static void skl_machine_device_unregister(struct skl_dev *skl) -{ - if (skl->i2s_dev) - platform_device_unregister(skl->i2s_dev); -} - -static int skl_dmic_device_register(struct skl_dev *skl) -{ - struct hdac_bus *bus = skl_to_bus(skl); - struct platform_device *pdev; - int ret; - - /* SKL has one dmic port, so allocate dmic device for this */ - pdev = platform_device_alloc("dmic-codec", -1); - if (!pdev) { - dev_err(bus->dev, "failed to allocate dmic device\n"); - return -ENOMEM; - } - - ret = platform_device_add(pdev); - if (ret) { - dev_err(bus->dev, "failed to add dmic device: %d\n", ret); - platform_device_put(pdev); - return ret; - } - skl->dmic_dev = pdev; - - return 0; -} - -static void skl_dmic_device_unregister(struct skl_dev *skl) -{ - if (skl->dmic_dev) - platform_device_unregister(skl->dmic_dev); -} - -static struct skl_clk_parent_src skl_clk_src[] = { - { .clk_id = SKL_XTAL, .name = "xtal" }, - { .clk_id = SKL_CARDINAL, .name = "cardinal", .rate = 24576000 }, - { .clk_id = SKL_PLL, .name = "pll", .rate = 96000000 }, -}; - -struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(skl_clk_src); i++) { - if (skl_clk_src[i].clk_id == clk_id) - return &skl_clk_src[i]; - } - - return NULL; -} - -static void init_skl_xtal_rate(int pci_id) -{ - switch (pci_id) { - case PCI_DEVICE_ID_INTEL_HDA_SKL_LP: - case PCI_DEVICE_ID_INTEL_HDA_KBL_LP: - skl_clk_src[0].rate = 24000000; - return; - - default: - skl_clk_src[0].rate = 19200000; - return; - } -} - -static int skl_clock_device_register(struct skl_dev *skl) -{ - struct platform_device_info pdevinfo = {NULL}; - struct skl_clk_pdata *clk_pdata; - - if (!skl->nhlt) - return 0; - - clk_pdata = devm_kzalloc(&skl->pci->dev, sizeof(*clk_pdata), - GFP_KERNEL); - if (!clk_pdata) - return -ENOMEM; - - init_skl_xtal_rate(skl->pci->device); - - clk_pdata->parent_clks = skl_clk_src; - clk_pdata->ssp_clks = skl_ssp_clks; - clk_pdata->num_clks = ARRAY_SIZE(skl_ssp_clks); - - /* Query NHLT to fill the rates and parent */ - skl_get_clks(skl, clk_pdata->ssp_clks); - clk_pdata->pvt_data = skl; - - /* Register Platform device */ - pdevinfo.parent = &skl->pci->dev; - pdevinfo.id = -1; - pdevinfo.name = "skl-ssp-clk"; - pdevinfo.data = clk_pdata; - pdevinfo.size_data = sizeof(*clk_pdata); - skl->clk_dev = platform_device_register_full(&pdevinfo); - return PTR_ERR_OR_ZERO(skl->clk_dev); -} - -static void skl_clock_device_unregister(struct skl_dev *skl) -{ - if (skl->clk_dev) - platform_device_unregister(skl->clk_dev); -} - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - -#define IDISP_INTEL_VENDOR_ID 0x80860000 - -/* - * load the legacy codec driver - */ -static void load_codec_module(struct hda_codec *codec) -{ -#ifdef MODULE - char modalias[MODULE_NAME_LEN]; - const char *mod = NULL; - - snd_hdac_codec_modalias(&codec->core, modalias, sizeof(modalias)); - mod = modalias; - dev_dbg(&codec->core.dev, "loading %s codec module\n", mod); - request_module(mod); -#endif -} - -#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ - -static struct hda_codec *skl_codec_device_init(struct hdac_bus *bus, int addr) -{ - struct hda_codec *codec; - int ret; - - codec = snd_hda_codec_device_init(to_hda_bus(bus), addr, "ehdaudio%dD%d", bus->idx, addr); - if (IS_ERR(codec)) { - dev_err(bus->dev, "device init failed for hdac device\n"); - return codec; - } - - codec->core.type = HDA_DEV_ASOC; - - ret = snd_hdac_device_register(&codec->core); - if (ret) { - dev_err(bus->dev, "failed to register hdac device\n"); - put_device(&codec->core.dev); - return ERR_PTR(ret); - } - - return codec; -} - -/* - * Probe the given codec address - */ -static int probe_codec(struct hdac_bus *bus, int addr) -{ - unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | - (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res = -1; -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - struct skl_dev *skl = bus_to_skl(bus); - struct hdac_hda_priv *hda_codec; -#endif - struct hda_codec *codec; - - mutex_lock(&bus->cmd_mutex); - snd_hdac_bus_send_cmd(bus, cmd); - snd_hdac_bus_get_response(bus, addr, &res); - mutex_unlock(&bus->cmd_mutex); - if (res == -1) - return -EIO; - dev_dbg(bus->dev, "codec #%d probed OK: %x\n", addr, res); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - hda_codec = devm_kzalloc(&skl->pci->dev, sizeof(*hda_codec), - GFP_KERNEL); - if (!hda_codec) - return -ENOMEM; - - codec = skl_codec_device_init(bus, addr); - if (IS_ERR(codec)) - return PTR_ERR(codec); - - hda_codec->codec = codec; - hda_codec->dev_index = addr; - dev_set_drvdata(&codec->core.dev, hda_codec); - - /* use legacy bus only for HDA codecs, idisp uses ext bus */ - if ((res & 0xFFFF0000) != IDISP_INTEL_VENDOR_ID) { - codec->core.type = HDA_DEV_LEGACY; - load_codec_module(hda_codec->codec); - } - return 0; -#else - codec = skl_codec_device_init(bus, addr); - return PTR_ERR_OR_ZERO(codec); -#endif /* CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC */ -} - -/* Codec initialization */ -static void skl_codec_create(struct hdac_bus *bus) -{ - int c, max_slots; - - max_slots = HDA_MAX_CODECS; - - /* First try to probe all given codec slots */ - for (c = 0; c < max_slots; c++) { - if ((bus->codec_mask & (1 << c))) { - if (probe_codec(bus, c) < 0) { - /* - * Some BIOSen give you wrong codec addresses - * that don't exist - */ - dev_warn(bus->dev, - "Codec #%d probe error; disabling it...\n", c); - bus->codec_mask &= ~(1 << c); - /* - * More badly, accessing to a non-existing - * codec often screws up the controller bus, - * and disturbs the further communications. - * Thus if an error occurs during probing, - * better to reset the controller bus to get - * back to the sanity state. - */ - snd_hdac_bus_stop_chip(bus); - skl_init_chip(bus, true); - } - } - } -} - -static void skl_probe_work(struct work_struct *work) -{ - struct skl_dev *skl = container_of(work, struct skl_dev, probe_work); - struct hdac_bus *bus = skl_to_bus(skl); - struct hdac_ext_link *hlink; - int err; - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); - - skl_init_pci(skl); - skl_dum_set(bus); - - err = skl_init_chip(bus, true); - if (err < 0) { - dev_err(bus->dev, "Init chip failed with err: %d\n", err); - goto out_err; - } - - /* codec detection */ - if (!bus->codec_mask) - dev_info(bus->dev, "no hda codecs found!\n"); - - /* create codec instances */ - skl_codec_create(bus); - - /* register platform dai and controls */ - err = skl_platform_register(bus->dev); - if (err < 0) { - dev_err(bus->dev, "platform register failed: %d\n", err); - goto out_err; - } - - err = skl_machine_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "machine register failed: %d\n", err); - goto out_err; - } - - /* - * we are done probing so decrement link counts - */ - list_for_each_entry(hlink, &bus->hlink_list, list) - snd_hdac_ext_bus_link_put(bus, hlink); - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); - - /* configure PM */ - pm_runtime_put_noidle(bus->dev); - pm_runtime_allow(bus->dev); - skl->init_done = 1; - - return; - -out_err: - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) - snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, false); -} - -/* - * constructor - */ -static int skl_create(struct pci_dev *pci, - struct skl_dev **rskl) -{ - struct hdac_ext_bus_ops *ext_ops = NULL; - struct skl_dev *skl; - struct hdac_bus *bus; - struct hda_bus *hbus; - int err; - - *rskl = NULL; - - err = pci_enable_device(pci); - if (err < 0) - return err; - - skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL); - if (!skl) { - pci_disable_device(pci); - return -ENOMEM; - } - - hbus = skl_to_hbus(skl); - bus = skl_to_bus(skl); - - INIT_LIST_HEAD(&skl->ppl_list); - INIT_LIST_HEAD(&skl->bind_list); - -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - ext_ops = snd_soc_hdac_hda_get_ops(); -#endif - snd_hdac_ext_bus_init(bus, &pci->dev, NULL, ext_ops); - bus->use_posbuf = 1; - skl->pci = pci; - INIT_WORK(&skl->probe_work, skl_probe_work); - bus->bdl_pos_adj = 0; - - mutex_init(&hbus->prepare_mutex); - hbus->pci = pci; - hbus->mixer_assigned = -1; - hbus->modelname = "sklbus"; - - *rskl = skl; - - return 0; -} - -static int skl_first_init(struct hdac_bus *bus) -{ - struct skl_dev *skl = bus_to_skl(bus); - struct pci_dev *pci = skl->pci; - int err; - unsigned short gcap; - int cp_streams, pb_streams, start_idx; - - err = pci_request_regions(pci, "Skylake HD audio"); - if (err < 0) - return err; - - bus->addr = pci_resource_start(pci, 0); - bus->remap_addr = pci_ioremap_bar(pci, 0); - if (bus->remap_addr == NULL) { - dev_err(bus->dev, "ioremap error\n"); - return -ENXIO; - } - - snd_hdac_bus_parse_capabilities(bus); - - /* check if PPCAP exists */ - if (!bus->ppcap) { - dev_err(bus->dev, "bus ppcap not set, HDAudio or DSP not present?\n"); - return -ENODEV; - } - - if (skl_acquire_irq(bus, 0) < 0) - return -EBUSY; - - pci_set_master(pci); - synchronize_irq(bus->irq); - - gcap = snd_hdac_chip_readw(bus, GCAP); - dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); - - /* read number of streams from GCAP register */ - cp_streams = (gcap >> 8) & 0x0f; - pb_streams = (gcap >> 12) & 0x0f; - - if (!pb_streams && !cp_streams) { - dev_err(bus->dev, "no streams found in GCAP definitions?\n"); - return -EIO; - } - - bus->num_streams = cp_streams + pb_streams; - - /* allow 64bit DMA address if supported by H/W */ - if (dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(64))) - dma_set_mask_and_coherent(bus->dev, DMA_BIT_MASK(32)); - dma_set_max_seg_size(bus->dev, UINT_MAX); - - /* initialize streams */ - snd_hdac_ext_stream_init_all - (bus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); - start_idx = cp_streams; - snd_hdac_ext_stream_init_all - (bus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); - - err = snd_hdac_bus_alloc_stream_pages(bus); - if (err < 0) - return err; - - return 0; -} - -static int skl_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) -{ - struct skl_dev *skl; - struct hdac_bus *bus = NULL; - int err; - - switch (skl_pci_binding) { - case SND_SKL_PCI_BIND_AUTO: - err = snd_intel_dsp_driver_probe(pci); - if (err != SND_INTEL_DSP_DRIVER_ANY && - err != SND_INTEL_DSP_DRIVER_SST) - return -ENODEV; - break; - case SND_SKL_PCI_BIND_LEGACY: - dev_info(&pci->dev, "Module parameter forced binding with HDAudio legacy, aborting probe\n"); - return -ENODEV; - case SND_SKL_PCI_BIND_ASOC: - dev_info(&pci->dev, "Module parameter forced binding with SKL driver, bypassed detection logic\n"); - break; - default: - dev_err(&pci->dev, "invalid value for skl_pci_binding module parameter, ignored\n"); - break; - } - - /* we use ext core ops, so provide NULL for ops here */ - err = skl_create(pci, &skl); - if (err < 0) - return err; - - bus = skl_to_bus(skl); - - err = skl_first_init(bus); - if (err < 0) { - dev_err(bus->dev, "skl_first_init failed with err: %d\n", err); - goto out_free; - } - - skl->pci_id = pci->device; - - device_disable_async_suspend(bus->dev); - - skl->nhlt = intel_nhlt_init(bus->dev); - - if (skl->nhlt == NULL) { -#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_SKYLAKE_HDAUDIO_CODEC) - dev_err(bus->dev, "no nhlt info found\n"); - err = -ENODEV; - goto out_free; -#else - dev_warn(bus->dev, "no nhlt info found, continuing to try to enable HDAudio codec\n"); -#endif - } else { - - err = skl_nhlt_create_sysfs(skl); - if (err < 0) { - dev_err(bus->dev, "skl_nhlt_create_sysfs failed with err: %d\n", err); - goto out_nhlt_free; - } - - skl_nhlt_update_topology_bin(skl); - - /* create device for dsp clk */ - err = skl_clock_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "skl_clock_device_register failed with err: %d\n", err); - goto out_clk_free; - } - } - - pci_set_drvdata(skl->pci, bus); - - - err = skl_find_machine(skl, (void *)pci_id->driver_data); - if (err < 0) { - dev_err(bus->dev, "skl_find_machine failed with err: %d\n", err); - goto out_nhlt_free; - } - - err = skl_init_dsp(skl); - if (err < 0) { - dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_nhlt_free; - } - skl->enable_miscbdcge = skl_enable_miscbdcge; - skl->clock_power_gating = skl_clock_power_gating; - - if (bus->mlcap) - snd_hdac_ext_bus_get_ml_capabilities(bus); - - /* create device for soc dmic */ - err = skl_dmic_device_register(skl); - if (err < 0) { - dev_err(bus->dev, "skl_dmic_device_register failed with err: %d\n", err); - goto out_dsp_free; - } - - if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { - err = snd_hdac_i915_init(bus); - if (err < 0) - goto out_dmic_unregister; - } - schedule_work(&skl->probe_work); - - return 0; - -out_dmic_unregister: - skl_dmic_device_unregister(skl); -out_dsp_free: - skl_free_dsp(skl); -out_clk_free: - skl_clock_device_unregister(skl); -out_nhlt_free: - if (skl->nhlt) - intel_nhlt_free(skl->nhlt); -out_free: - skl_free(bus); - - return err; -} - -static void skl_shutdown(struct pci_dev *pci) -{ - struct hdac_bus *bus = pci_get_drvdata(pci); - struct hdac_stream *s; - struct hdac_ext_stream *stream; - struct skl_dev *skl; - - if (!bus) - return; - - skl = bus_to_skl(bus); - - if (!skl->init_done) - return; - - snd_hdac_stop_streams(bus); - snd_hdac_ext_bus_link_power_down_all(bus); - skl_dsp_sleep(skl->dsp); - - list_for_each_entry(s, &bus->stream_list, list) { - stream = stream_to_hdac_ext_stream(s); - snd_hdac_ext_stream_decouple(bus, stream, false); - } - - snd_hdac_bus_stop_chip(bus); -} - -static void skl_remove(struct pci_dev *pci) -{ - struct hdac_bus *bus = pci_get_drvdata(pci); - struct skl_dev *skl = bus_to_skl(bus); - - cancel_work_sync(&skl->probe_work); - - pm_runtime_get_noresume(&pci->dev); - - /* codec removal, invoke bus_device_remove */ - snd_hdac_ext_bus_device_remove(bus); - - skl_platform_unregister(&pci->dev); - skl_free_dsp(skl); - skl_machine_device_unregister(skl); - skl_dmic_device_unregister(skl); - skl_clock_device_unregister(skl); - skl_nhlt_remove_sysfs(skl); - if (skl->nhlt) - intel_nhlt_free(skl->nhlt); - skl_free(bus); -} - -/* PCI IDs */ -static const struct pci_device_id skl_ids[] = { -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_SKL) - { PCI_DEVICE_DATA(INTEL, HDA_SKL_LP, &snd_soc_acpi_intel_skl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_APL) - { PCI_DEVICE_DATA(INTEL, HDA_APL, &snd_soc_acpi_intel_bxt_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_KBL) - { PCI_DEVICE_DATA(INTEL, HDA_KBL_LP, &snd_soc_acpi_intel_kbl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_GLK) - { PCI_DEVICE_DATA(INTEL, HDA_GML, &snd_soc_acpi_intel_glk_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CNL) - { PCI_DEVICE_DATA(INTEL, HDA_CNL_LP, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CFL) - { PCI_DEVICE_DATA(INTEL, HDA_CNL_H, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_LP) - { PCI_DEVICE_DATA(INTEL, HDA_CML_LP, &snd_soc_acpi_intel_cnl_machines) }, -#endif -#if IS_ENABLED(CONFIG_SND_SOC_INTEL_CML_H) - { PCI_DEVICE_DATA(INTEL, HDA_CML_H, &snd_soc_acpi_intel_cnl_machines) }, -#endif - { 0, } -}; -MODULE_DEVICE_TABLE(pci, skl_ids); - -/* pci_driver definition */ -static struct pci_driver skl_driver = { - .name = KBUILD_MODNAME, - .id_table = skl_ids, - .probe = skl_probe, - .remove = skl_remove, - .shutdown = skl_shutdown, - .driver = { - .pm = &skl_pm, - }, -}; -module_pci_driver(skl_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver"); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h deleted file mode 100644 index f55f8b3dbdc3..000000000000 --- a/sound/soc/intel/skylake/skl.h +++ /dev/null @@ -1,207 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * skl.h - HD Audio skylake definitions. - * - * Copyright (C) 2015 Intel Corp - * Author: Jeeja KP <jeeja.kp@intel.com> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __SOUND_SOC_SKL_H -#define __SOUND_SOC_SKL_H - -#include <sound/hda_register.h> -#include <sound/hdaudio_ext.h> -#include <sound/hda_codec.h> -#include <sound/soc.h> -#include "skl-ssp-clk.h" -#include "skl-sst-ipc.h" - -#define SKL_SUSPEND_DELAY 2000 - -#define SKL_MAX_ASTATE_CFG 3 - -#define AZX_PCIREG_PGCTL 0x44 -#define AZX_PGCTL_LSRMD_MASK (1 << 4) -#define AZX_PGCTL_ADSPPGD BIT(2) -#define AZX_PCIREG_CGCTL 0x48 -#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) -#define AZX_CGCTL_ADSPDCGE BIT(1) -/* D0I3C Register fields */ -#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ -#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ -#define SKL_MAX_DMACTRL_CFG 18 -#define DMA_CLK_CONTROLS 1 -#define DMA_TRANSMITION_START 2 -#define DMA_TRANSMITION_STOP 3 - -#define AZX_VS_EM2_DUM BIT(23) -#define AZX_REG_VS_EM2_L1SEN BIT(13) - -struct skl_debug; - -struct skl_astate_param { - u32 kcps; - u32 clk_src; -}; - -struct skl_astate_config { - u32 count; - struct skl_astate_param astate_table[]; -}; - -struct skl_fw_config { - struct skl_astate_config *astate_cfg; -}; - -struct skl_dev { - struct hda_bus hbus; - struct pci_dev *pci; - - unsigned int init_done:1; /* delayed init status */ - struct platform_device *dmic_dev; - struct platform_device *i2s_dev; - struct platform_device *clk_dev; - struct snd_soc_component *component; - struct snd_soc_dai_driver *dais; - - struct nhlt_acpi_table *nhlt; /* nhlt ptr */ - - struct list_head ppl_list; - struct list_head bind_list; - - const char *fw_name; - char tplg_name[64]; - unsigned short pci_id; - - int supend_active; - - struct work_struct probe_work; - - struct skl_debug *debugfs; - u8 nr_modules; - struct skl_module **modules; - bool use_tplg_pcm; - struct skl_fw_config cfg; - struct snd_soc_acpi_mach *mach; - - struct device *dev; - struct sst_dsp *dsp; - - /* boot */ - wait_queue_head_t boot_wait; - bool boot_complete; - - /* module load */ - wait_queue_head_t mod_load_wait; - bool mod_load_complete; - bool mod_load_status; - - /* IPC messaging */ - struct sst_generic_ipc ipc; - - /* callback for miscbdge */ - void (*enable_miscbdcge)(struct device *dev, bool enable); - /* Is CGCTL.MISCBDCGE disabled */ - bool miscbdcg_disabled; - - /* Populate module information */ - struct list_head uuid_list; - - /* Is firmware loaded */ - bool fw_loaded; - - /* first boot ? */ - bool is_first_boot; - - /* multi-core */ - struct skl_dsp_cores cores; - - /* library info */ - struct skl_lib_info lib_info[SKL_MAX_LIB]; - int lib_count; - - /* Callback to update D0i3C register */ - void (*update_d0i3c)(struct device *dev, bool enable); - - struct skl_d0i3_data d0i3; - - const struct skl_dsp_ops *dsp_ops; - - /* Callback to update dynamic clock and power gating registers */ - void (*clock_power_gating)(struct device *dev, bool enable); -}; - -#define skl_to_bus(s) (&(s)->hbus.core) -#define bus_to_skl(bus) container_of(bus, struct skl_dev, hbus.core) - -#define skl_to_hbus(s) (&(s)->hbus) -#define hbus_to_skl(hbus) container_of((hbus), struct skl_dev, (hbus)) - -/* to pass dai dma data */ -struct skl_dma_params { - u32 format; - u8 stream_tag; -}; - -struct skl_machine_pdata { - bool use_tplg_pcm; /* use dais and dai links from topology */ -}; - -struct skl_dsp_ops { - int id; - unsigned int num_cores; - struct skl_dsp_loader_ops (*loader_ops)(void); - int (*init)(struct device *dev, void __iomem *mmio_base, - int irq, const char *fw_name, - struct skl_dsp_loader_ops loader_ops, - struct skl_dev **skl_sst); - int (*init_fw)(struct device *dev, struct skl_dev *skl); - void (*cleanup)(struct device *dev, struct skl_dev *skl); -}; - -int skl_platform_unregister(struct device *dev); -int skl_platform_register(struct device *dev); - -int skl_nhlt_update_topology_bin(struct skl_dev *skl); -int skl_init_dsp(struct skl_dev *skl); -int skl_free_dsp(struct skl_dev *skl); -int skl_suspend_late_dsp(struct skl_dev *skl); -int skl_suspend_dsp(struct skl_dev *skl); -int skl_resume_dsp(struct skl_dev *skl); -void skl_cleanup_resources(struct skl_dev *skl); -const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); -void skl_update_d0i3c(struct device *dev, bool enable); -int skl_nhlt_create_sysfs(struct skl_dev *skl); -void skl_nhlt_remove_sysfs(struct skl_dev *skl); -void skl_get_clks(struct skl_dev *skl, struct skl_ssp_clk *ssp_clks); -struct skl_clk_parent_src *skl_get_parent_clk(u8 clk_id); -int skl_dsp_set_dma_control(struct skl_dev *skl, u32 *caps, - u32 caps_size, u32 node_id); - -struct skl_module_cfg; - -#ifdef CONFIG_DEBUG_FS -struct skl_debug *skl_debugfs_init(struct skl_dev *skl); -void skl_debugfs_exit(struct skl_dev *skl); -void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig); -#else -static inline struct skl_debug *skl_debugfs_init(struct skl_dev *skl) -{ - return NULL; -} - -static inline void skl_debugfs_exit(struct skl_dev *skl) -{} - -static inline void skl_debug_init_module(struct skl_debug *d, - struct snd_soc_dapm_widget *w, - struct skl_module_cfg *mconfig) -{} -#endif - -#endif /* __SOUND_SOC_SKL_H */ |