aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/soc/sof
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2024-01-08 08:18:02 +0100
committerTakashi Iwai <tiwai@suse.de>2024-01-08 08:18:02 +0100
commit0205f3753dbe15fe8b5c08302f44b69a80a83167 (patch)
tree0278890aa13930127bcda2366a741091aff77f47 /sound/soc/sof
parentMerge branch 'for-next' into for-linus (diff)
parentASoC: pxa: sspa: Don't select SND_ARM (diff)
downloadwireguard-linux-0205f3753dbe15fe8b5c08302f44b69a80a83167.tar.xz
wireguard-linux-0205f3753dbe15fe8b5c08302f44b69a80a83167.zip
Merge tag 'asoc-v6.8' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Updates for v6.8 This is a relatively quiet release, there's a lot of driver specific changes and the usual high level of activity in the SOF core but the one big core change was Mormioto-san's work to support more N:M CPU:CODEC mapping cases. Highlights include: - Enhanced support for N:M CPU:CODEC mappings in the core and in audio-graph-card2. - Support for falling back to older SOF IPC versions where firmware for new versions is not available. - Support for notification of control changes generated by SOF firmware with IPC4. - Device tree support for describing parts of the card which can be active over suspend (for very low power playback or wake word use cases). - ACPI parsing support for the ES83xx driver, reducing the number of quirks neede for x86 systems. - Support for more AMD and Intel systems, NXP i.MX8m MICFIL, Qualcomm SM8250, SM8550, SM8650 and X1E80100. - Removal of Freescale MPC8610 support, the SoC is no longer supported by Linux.
Diffstat (limited to 'sound/soc/sof')
-rw-r--r--sound/soc/sof/Kconfig11
-rw-r--r--sound/soc/sof/Makefile3
-rw-r--r--sound/soc/sof/amd/acp-common.c1
-rw-r--r--sound/soc/sof/amd/acp-ipc.c4
-rw-r--r--sound/soc/sof/amd/acp.c14
-rw-r--r--sound/soc/sof/amd/acp.h5
-rw-r--r--sound/soc/sof/core.c311
-rw-r--r--sound/soc/sof/fw-file-profile.c322
-rw-r--r--sound/soc/sof/imx/imx8.c1
-rw-r--r--sound/soc/sof/imx/imx8m.c8
-rw-r--r--sound/soc/sof/imx/imx8ulp.c1
-rw-r--r--sound/soc/sof/intel/apl.c2
-rw-r--r--sound/soc/sof/intel/cnl.c2
-rw-r--r--sound/soc/sof/intel/hda-dai.c3
-rw-r--r--sound/soc/sof/intel/hda-loader.c10
-rw-r--r--sound/soc/sof/intel/hda.c6
-rw-r--r--sound/soc/sof/intel/icl.c2
-rw-r--r--sound/soc/sof/intel/lnl.c8
-rw-r--r--sound/soc/sof/intel/mtl.c23
-rw-r--r--sound/soc/sof/intel/mtl.h3
-rw-r--r--sound/soc/sof/intel/skl.c2
-rw-r--r--sound/soc/sof/intel/tgl.c4
-rw-r--r--sound/soc/sof/ipc3-dtrace.c3
-rw-r--r--sound/soc/sof/ipc3-pcm.c11
-rw-r--r--sound/soc/sof/ipc3-topology.c59
-rw-r--r--sound/soc/sof/ipc4-control.c179
-rw-r--r--sound/soc/sof/ipc4-loader.c3
-rw-r--r--sound/soc/sof/ipc4-priv.h4
-rw-r--r--sound/soc/sof/ipc4-topology.c32
-rw-r--r--sound/soc/sof/ipc4.c117
-rw-r--r--sound/soc/sof/mediatek/adsp_helper.h4
-rw-r--r--sound/soc/sof/mediatek/mt8186/mt8186.c49
-rw-r--r--sound/soc/sof/mediatek/mt8195/mt8195.c49
-rw-r--r--sound/soc/sof/sof-acpi-dev.c16
-rw-r--r--sound/soc/sof/sof-audio.c120
-rw-r--r--sound/soc/sof/sof-audio.h1
-rw-r--r--sound/soc/sof/sof-client-probes.c4
-rw-r--r--sound/soc/sof/sof-of-dev.c13
-rw-r--r--sound/soc/sof/sof-pci-dev.c102
-rw-r--r--sound/soc/sof/sof-priv.h9
-rw-r--r--sound/soc/sof/topology.c10
41 files changed, 1095 insertions, 436 deletions
diff --git a/sound/soc/sof/Kconfig b/sound/soc/sof/Kconfig
index a741ed96e789..32ffd345e07f 100644
--- a/sound/soc/sof/Kconfig
+++ b/sound/soc/sof/Kconfig
@@ -126,6 +126,17 @@ config SND_SOC_SOF_STRICT_ABI_CHECKS
If you are not involved in SOF releases and CI development,
select "N".
+config SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION
+ bool "SOF allow fallback to newer IPC version"
+ help
+ This option will allow the kernel to try to 'fallback' to a newer IPC
+ version if there are missing firmware files to satisfy the default IPC
+ version.
+ IPC version fallback to older versions is not affected by this option,
+ it is always available.
+ Say Y if you are involved in SOF development and need this option.
+ If not, select N.
+
config SND_SOC_SOF_DEBUG
bool "SOF debugging features"
help
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile
index ef6fd43d0b72..3624124575af 100644
--- a/sound/soc/sof/Makefile
+++ b/sound/soc/sof/Makefile
@@ -1,7 +1,8 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\
- control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o
+ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\
+ fw-file-profile.o
# IPC implementations
ifneq ($(CONFIG_SND_SOC_SOF_IPC3),)
diff --git a/sound/soc/sof/amd/acp-common.c b/sound/soc/sof/amd/acp-common.c
index 3a0c7688dcfe..2d72c6d55dc8 100644
--- a/sound/soc/sof/amd/acp-common.c
+++ b/sound/soc/sof/amd/acp-common.c
@@ -13,7 +13,6 @@
#include "../sof-priv.h"
#include "../sof-audio.h"
#include "../ops.h"
-#include "../sof-audio.h"
#include "acp.h"
#include "acp-dsp-offset.h"
#include <sound/sof/xtensa.h>
diff --git a/sound/soc/sof/amd/acp-ipc.c b/sound/soc/sof/amd/acp-ipc.c
index fcb54f545fea..2743f07a5e08 100644
--- a/sound/soc/sof/amd/acp-ipc.c
+++ b/sound/soc/sof/amd/acp-ipc.c
@@ -3,7 +3,7 @@
// 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) 2021 Advanced Micro Devices, Inc.
+// Copyright(c) 2021, 2023 Advanced Micro Devices, Inc.
//
// Authors: Balakishore Pati <Balakishore.pati@amd.com>
// Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
@@ -188,13 +188,11 @@ irqreturn_t acp_sof_ipc_irq_thread(int irq, void *context)
dsp_ack = snd_sof_dsp_read(sdev, ACP_DSP_BAR, ACP_SCRATCH_REG_0 + dsp_ack_write);
if (dsp_ack) {
- spin_lock_irq(&sdev->ipc_lock);
/* handle immediate reply from DSP core */
acp_dsp_ipc_get_reply(sdev);
snd_sof_ipc_reply(sdev, 0);
/* set the done bit */
acp_dsp_ipc_dsp_done(sdev);
- spin_unlock_irq(&sdev->ipc_lock);
ipc_irq = true;
}
diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c
index 603ea5fc0d0d..32a741fcb84f 100644
--- a/sound/soc/sof/amd/acp.c
+++ b/sound/soc/sof/amd/acp.c
@@ -278,6 +278,17 @@ int configure_and_run_sha_dma(struct acp_dev_data *adata, void *image_addr,
return ret;
}
+ /* psp_send_cmd only required for vangogh platform (rev - 5) */
+ if (desc->rev == 5) {
+ /* Modify IRAM and DRAM size */
+ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | IRAM_DRAM_FENCE_2);
+ if (ret)
+ return ret;
+ ret = psp_send_cmd(adata, MBOX_ACP_IRAM_DRAM_FENCE_COMMAND | MBOX_ISREADY_FLAG);
+ if (ret)
+ return ret;
+ }
+
ret = snd_sof_dsp_read_poll_timeout(sdev, ACP_DSP_BAR, ACP_SHA_DSP_FW_QUALIFIER,
fw_qualifier, fw_qualifier & DSP_FW_RUN_ENABLE,
ACP_REG_POLL_INTERVAL, ACP_DMA_COMPLETE_TIMEOUT_US);
@@ -343,11 +354,13 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
const struct sof_amd_acp_desc *desc = get_chip_info(sdev->pdata);
unsigned int count = ACP_HW_SEM_RETRY_COUNT;
+ spin_lock_irq(&sdev->ipc_lock);
while (snd_sof_dsp_read(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset)) {
/* Wait until acquired HW Semaphore lock or timeout */
count--;
if (!count) {
dev_err(sdev->dev, "%s: Failed to acquire HW lock\n", __func__);
+ spin_unlock_irq(&sdev->ipc_lock);
return IRQ_NONE;
}
}
@@ -356,6 +369,7 @@ static irqreturn_t acp_irq_thread(int irq, void *context)
/* Unlock or Release HW Semaphore */
snd_sof_dsp_write(sdev, ACP_DSP_BAR, desc->hw_semaphore_offset, 0x0);
+ spin_unlock_irq(&sdev->ipc_lock);
return IRQ_HANDLED;
};
diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h
index c536cfde0e44..c645aee216fd 100644
--- a/sound/soc/sof/amd/acp.h
+++ b/sound/soc/sof/amd/acp.h
@@ -74,9 +74,14 @@
#define MP0_C2PMSG_114_REG 0x3810AC8
#define MP0_C2PMSG_73_REG 0x3810A24
#define MBOX_ACP_SHA_DMA_COMMAND 0x70000
+#define MBOX_ACP_IRAM_DRAM_FENCE_COMMAND 0x80000
#define MBOX_DELAY_US 1000
#define MBOX_READY_MASK 0x80000000
#define MBOX_STATUS_MASK 0xFFFF
+#define MBOX_ISREADY_FLAG 0x40000000
+#define IRAM_DRAM_FENCE_0 0X0
+#define IRAM_DRAM_FENCE_1 0X01
+#define IRAM_DRAM_FENCE_2 0X02
#define BOX_SIZE_512 0x200
#define BOX_SIZE_1024 0x400
diff --git a/sound/soc/sof/core.c b/sound/soc/sof/core.c
index d7b090224f1b..425b023b03b4 100644
--- a/sound/soc/sof/core.c
+++ b/sound/soc/sof/core.c
@@ -13,6 +13,7 @@
#include <sound/soc.h>
#include <sound/sof.h>
#include "sof-priv.h"
+#include "sof-of-dev.h"
#include "ops.h"
#define CREATE_TRACE_POINTS
@@ -143,6 +144,233 @@ void sof_set_fw_state(struct snd_sof_dev *sdev, enum sof_fw_state new_state)
}
EXPORT_SYMBOL(sof_set_fw_state);
+static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_sof_of_mach *mach = desc->of_machines;
+
+ if (!mach)
+ return NULL;
+
+ for (; mach->compatible; mach++) {
+ if (of_machine_is_compatible(mach->compatible)) {
+ sof_pdata->tplg_filename = mach->sof_tplg_filename;
+ if (mach->fw_filename)
+ sof_pdata->fw_filename = mach->fw_filename;
+
+ return mach;
+ }
+ }
+
+ return NULL;
+}
+
+/* SOF Driver enumeration */
+static int sof_machine_check(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *sof_pdata = sdev->pdata;
+ const struct sof_dev_desc *desc = sof_pdata->desc;
+ struct snd_soc_acpi_mach *mach;
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
+ const struct snd_sof_of_mach *of_mach;
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
+ sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
+ goto nocodec;
+
+ /* find machine */
+ mach = snd_sof_machine_select(sdev);
+ if (mach) {
+ sof_pdata->machine = mach;
+
+ if (sof_pdata->subsystem_id_set) {
+ mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor;
+ mach->mach_params.subsystem_device = sof_pdata->subsystem_device;
+ mach->mach_params.subsystem_id_set = true;
+ }
+
+ snd_sof_set_mach_params(mach, sdev);
+ return 0;
+ }
+
+ of_mach = sof_of_machine_select(sdev);
+ if (of_mach) {
+ sof_pdata->of_machine = of_mach;
+ return 0;
+ }
+
+ if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
+ dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
+ return -ENODEV;
+ }
+ } else {
+ dev_warn(sdev->dev, "Force to use nocodec mode\n");
+ }
+
+nocodec:
+ /* select nocodec mode */
+ dev_warn(sdev->dev, "Using nocodec machine driver\n");
+ mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
+ if (!mach)
+ return -ENOMEM;
+
+ mach->drv_name = "sof-nocodec";
+ if (!sof_pdata->tplg_filename)
+ sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
+
+ sof_pdata->machine = mach;
+ snd_sof_set_mach_params(mach, sdev);
+
+ return 0;
+}
+
+static int sof_select_ipc_and_paths(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+ struct sof_loadable_file_profile out_profile;
+ struct device *dev = sdev->dev;
+ int ret;
+
+ if (base_profile->ipc_type != plat_data->desc->ipc_default)
+ dev_info(dev,
+ "Module parameter used, overriding default IPC %d to %d\n",
+ plat_data->desc->ipc_default, base_profile->ipc_type);
+
+ if (base_profile->fw_path)
+ dev_dbg(dev, "Module parameter used, changed fw path to %s\n",
+ base_profile->fw_path);
+ else if (base_profile->fw_path_postfix)
+ dev_dbg(dev, "Path postfix appended to default fw path: %s\n",
+ base_profile->fw_path_postfix);
+
+ if (base_profile->fw_lib_path)
+ dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
+ base_profile->fw_lib_path);
+ else if (base_profile->fw_lib_path_postfix)
+ dev_dbg(dev, "Path postfix appended to default fw_lib path: %s\n",
+ base_profile->fw_lib_path_postfix);
+
+ if (base_profile->fw_name)
+ dev_dbg(dev, "Module parameter used, changed fw filename to %s\n",
+ base_profile->fw_name);
+
+ if (base_profile->tplg_path)
+ dev_dbg(dev, "Module parameter used, changed tplg path to %s\n",
+ base_profile->tplg_path);
+
+ if (base_profile->tplg_name)
+ dev_dbg(dev, "Module parameter used, changed tplg name to %s\n",
+ base_profile->tplg_name);
+
+ ret = sof_create_ipc_file_profile(sdev, base_profile, &out_profile);
+ if (ret)
+ return ret;
+
+ plat_data->ipc_type = out_profile.ipc_type;
+ plat_data->fw_filename = out_profile.fw_name;
+ plat_data->fw_filename_prefix = out_profile.fw_path;
+ plat_data->fw_lib_prefix = out_profile.fw_lib_path;
+ plat_data->tplg_filename_prefix = out_profile.tplg_path;
+
+ return 0;
+}
+
+static int validate_sof_ops(struct snd_sof_dev *sdev)
+{
+ int ret;
+
+ /* init ops, if necessary */
+ ret = sof_ops_init(sdev);
+ if (ret < 0)
+ return ret;
+
+ /* check all mandatory ops */
+ if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
+ dev_err(sdev->dev, "missing mandatory ops\n");
+ sof_ops_free(sdev);
+ return -EINVAL;
+ }
+
+ if (!sdev->dspless_mode_selected &&
+ (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
+ !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
+ !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
+ dev_err(sdev->dev, "missing mandatory DSP ops\n");
+ sof_ops_free(sdev);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sof_init_sof_ops(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+
+ /* check IPC support */
+ if (!(BIT(base_profile->ipc_type) & plat_data->desc->ipc_supported_mask)) {
+ dev_err(sdev->dev,
+ "ipc_type %d is not supported on this platform, mask is %#x\n",
+ base_profile->ipc_type, plat_data->desc->ipc_supported_mask);
+ return -EINVAL;
+ }
+
+ /*
+ * Save the selected IPC type and a topology name override before
+ * selecting ops since platform code might need this information
+ */
+ plat_data->ipc_type = base_profile->ipc_type;
+ plat_data->tplg_filename = base_profile->tplg_name;
+
+ return validate_sof_ops(sdev);
+}
+
+static int sof_init_environment(struct snd_sof_dev *sdev)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ struct sof_loadable_file_profile *base_profile = &plat_data->ipc_file_profile_base;
+ int ret;
+
+ /* probe the DSP hardware */
+ ret = snd_sof_probe(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to probe DSP %d\n", ret);
+ sof_ops_free(sdev);
+ return ret;
+ }
+
+ /* check machine info */
+ ret = sof_machine_check(sdev);
+ if (ret < 0) {
+ dev_err(sdev->dev, "failed to get machine info %d\n", ret);
+ goto err_machine_check;
+ }
+
+ ret = sof_select_ipc_and_paths(sdev);
+ if (!ret && plat_data->ipc_type != base_profile->ipc_type) {
+ /* IPC type changed, re-initialize the ops */
+ sof_ops_free(sdev);
+
+ ret = validate_sof_ops(sdev);
+ if (ret < 0) {
+ snd_sof_remove(sdev);
+ return ret;
+ }
+ }
+
+err_machine_check:
+ if (ret) {
+ snd_sof_remove(sdev);
+ sof_ops_free(sdev);
+ }
+
+ return ret;
+}
+
/*
* FW Boot State Transition Diagram
*
@@ -188,23 +416,13 @@ static int sof_probe_continue(struct snd_sof_dev *sdev)
struct snd_sof_pdata *plat_data = sdev->pdata;
int ret;
- /* probe the DSP hardware */
- ret = snd_sof_probe(sdev);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to probe DSP %d\n", ret);
- goto probe_err;
- }
+ /* Initialize loadable file paths and check the environment validity */
+ ret = sof_init_environment(sdev);
+ if (ret)
+ return ret;
sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
- /* check machine info */
- ret = sof_machine_check(sdev);
- if (ret < 0) {
- dev_err(sdev->dev, "error: failed to get machine info %d\n",
- ret);
- goto dsp_err;
- }
-
/* set up platform component driver */
snd_sof_new_platform_drv(sdev);
@@ -324,9 +542,7 @@ fw_load_err:
ipc_err:
dbg_err:
snd_sof_free_debug(sdev);
-dsp_err:
snd_sof_remove(sdev);
-probe_err:
snd_sof_remove_late(sdev);
sof_ops_free(sdev);
@@ -381,34 +597,11 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
}
}
- /* check IPC support */
- if (!(BIT(plat_data->ipc_type) & plat_data->desc->ipc_supported_mask)) {
- dev_err(dev, "ipc_type %d is not supported on this platform, mask is %#x\n",
- plat_data->ipc_type, plat_data->desc->ipc_supported_mask);
- return -EINVAL;
- }
-
- /* init ops, if necessary */
- ret = sof_ops_init(sdev);
- if (ret < 0)
+ /* Initialize sof_ops based on the initial selected IPC version */
+ ret = sof_init_sof_ops(sdev);
+ if (ret)
return ret;
- /* check all mandatory ops */
- if (!sof_ops(sdev) || !sof_ops(sdev)->probe) {
- sof_ops_free(sdev);
- dev_err(dev, "missing mandatory ops\n");
- return -EINVAL;
- }
-
- if (!sdev->dspless_mode_selected &&
- (!sof_ops(sdev)->run || !sof_ops(sdev)->block_read ||
- !sof_ops(sdev)->block_write || !sof_ops(sdev)->send_msg ||
- !sof_ops(sdev)->load_firmware || !sof_ops(sdev)->ipc_msg_data)) {
- sof_ops_free(sdev);
- dev_err(dev, "missing mandatory DSP ops\n");
- return -EINVAL;
- }
-
INIT_LIST_HEAD(&sdev->pcm_list);
INIT_LIST_HEAD(&sdev->kcontrol_list);
INIT_LIST_HEAD(&sdev->widget_list);
@@ -527,6 +720,40 @@ int snd_sof_device_shutdown(struct device *dev)
}
EXPORT_SYMBOL(snd_sof_device_shutdown);
+/* Machine driver registering and unregistering */
+int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = pdata;
+ const char *drv_name;
+ const void *mach;
+ int size;
+
+ drv_name = plat_data->machine->drv_name;
+ mach = plat_data->machine;
+ size = sizeof(*plat_data->machine);
+
+ /* register machine driver, pass machine info as pdata */
+ plat_data->pdev_mach =
+ platform_device_register_data(sdev->dev, drv_name,
+ PLATFORM_DEVID_NONE, mach, size);
+ if (IS_ERR(plat_data->pdev_mach))
+ return PTR_ERR(plat_data->pdev_mach);
+
+ dev_dbg(sdev->dev, "created machine %s\n",
+ dev_name(&plat_data->pdev_mach->dev));
+
+ return 0;
+}
+EXPORT_SYMBOL(sof_machine_register);
+
+void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
+{
+ struct snd_sof_pdata *plat_data = pdata;
+
+ platform_device_unregister(plat_data->pdev_mach);
+}
+EXPORT_SYMBOL(sof_machine_unregister);
+
MODULE_AUTHOR("Liam Girdwood");
MODULE_DESCRIPTION("Sound Open Firmware (SOF) Core");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/sound/soc/sof/fw-file-profile.c b/sound/soc/sof/fw-file-profile.c
new file mode 100644
index 000000000000..138a1ca2c4a8
--- /dev/null
+++ b/sound/soc/sof/fw-file-profile.c
@@ -0,0 +1,322 @@
+// 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) 2023 Intel Corporation. All rights reserved.
+//
+
+#include <linux/firmware.h>
+#include <sound/sof.h>
+#include <sound/sof/ext_manifest4.h>
+#include "sof-priv.h"
+
+static int sof_test_firmware_file(struct device *dev,
+ struct sof_loadable_file_profile *profile,
+ enum sof_ipc_type *ipc_type_to_adjust)
+{
+ enum sof_ipc_type fw_ipc_type;
+ const struct firmware *fw;
+ const char *fw_filename;
+ const u32 *magic;
+ int ret;
+
+ fw_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->fw_path,
+ profile->fw_name);
+ if (!fw_filename)
+ return -ENOMEM;
+
+ ret = firmware_request_nowarn(&fw, fw_filename, dev);
+ if (ret < 0) {
+ dev_dbg(dev, "Failed to open firmware file: %s\n", fw_filename);
+ kfree(fw_filename);
+ return ret;
+ }
+
+ /* firmware file exists, check the magic number */
+ magic = (const u32 *)fw->data;
+ switch (*magic) {
+ case SOF_EXT_MAN_MAGIC_NUMBER:
+ fw_ipc_type = SOF_IPC_TYPE_3;
+ break;
+ case SOF_EXT_MAN4_MAGIC_NUMBER:
+ fw_ipc_type = SOF_IPC_TYPE_4;
+ break;
+ default:
+ dev_err(dev, "Invalid firmware magic: %#x\n", *magic);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (ipc_type_to_adjust) {
+ *ipc_type_to_adjust = fw_ipc_type;
+ } else if (fw_ipc_type != profile->ipc_type) {
+ dev_err(dev,
+ "ipc type mismatch between %s and expected: %d vs %d\n",
+ fw_filename, fw_ipc_type, profile->ipc_type);
+ ret = -EINVAL;
+ }
+out:
+ release_firmware(fw);
+ kfree(fw_filename);
+
+ return ret;
+}
+
+static int sof_test_topology_file(struct device *dev,
+ struct sof_loadable_file_profile *profile)
+{
+ const struct firmware *fw;
+ const char *tplg_filename;
+ int ret;
+
+ if (!profile->tplg_path || !profile->tplg_name)
+ return 0;
+
+ tplg_filename = kasprintf(GFP_KERNEL, "%s/%s", profile->tplg_path,
+ profile->tplg_name);
+ if (!tplg_filename)
+ return -ENOMEM;
+
+ ret = firmware_request_nowarn(&fw, tplg_filename, dev);
+ if (!ret)
+ release_firmware(fw);
+ else
+ dev_dbg(dev, "Failed to open topology file: %s\n", tplg_filename);
+
+ kfree(tplg_filename);
+
+ return ret;
+}
+
+static int
+sof_file_profile_for_ipc_type(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ const struct sof_dev_desc *desc,
+ struct sof_loadable_file_profile *base_profile,
+ struct sof_loadable_file_profile *out_profile)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ bool fw_lib_path_allocated = false;
+ struct device *dev = sdev->dev;
+ bool fw_path_allocated = false;
+ int ret = 0;
+
+ /* firmware path */
+ if (base_profile->fw_path) {
+ out_profile->fw_path = base_profile->fw_path;
+ } else if (base_profile->fw_path_postfix) {
+ out_profile->fw_path = devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
+ desc->default_fw_path[ipc_type],
+ base_profile->fw_path_postfix);
+ if (!out_profile->fw_path)
+ return -ENOMEM;
+
+ fw_path_allocated = true;
+ } else {
+ out_profile->fw_path = desc->default_fw_path[ipc_type];
+ }
+
+ /* firmware filename */
+ if (base_profile->fw_name)
+ out_profile->fw_name = base_profile->fw_name;
+ else
+ out_profile->fw_name = desc->default_fw_filename[ipc_type];
+
+ /*
+ * Check the custom firmware path/filename and adjust the ipc_type to
+ * match with the existing file for the remaining path configuration.
+ *
+ * For default path and firmware name do a verification before
+ * continuing further.
+ */
+ if (base_profile->fw_path || base_profile->fw_name) {
+ ret = sof_test_firmware_file(dev, out_profile, &ipc_type);
+ if (ret)
+ return ret;
+
+ if (!(desc->ipc_supported_mask & BIT(ipc_type))) {
+ dev_err(dev, "Unsupported IPC type %d needed by %s/%s\n",
+ ipc_type, out_profile->fw_path,
+ out_profile->fw_name);
+ return -EINVAL;
+ }
+ }
+
+ /* firmware library path */
+ if (base_profile->fw_lib_path) {
+ out_profile->fw_lib_path = base_profile->fw_lib_path;
+ } else if (desc->default_lib_path[ipc_type]) {
+ if (base_profile->fw_lib_path_postfix) {
+ out_profile->fw_lib_path = devm_kasprintf(dev,
+ GFP_KERNEL, "%s/%s",
+ desc->default_lib_path[ipc_type],
+ base_profile->fw_lib_path_postfix);
+ if (!out_profile->fw_lib_path) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ fw_lib_path_allocated = true;
+ } else {
+ out_profile->fw_lib_path = desc->default_lib_path[ipc_type];
+ }
+ }
+
+ if (base_profile->fw_path_postfix)
+ out_profile->fw_path_postfix = base_profile->fw_path_postfix;
+
+ if (base_profile->fw_lib_path_postfix)
+ out_profile->fw_lib_path_postfix = base_profile->fw_lib_path_postfix;
+
+ /* topology path */
+ if (base_profile->tplg_path)
+ out_profile->tplg_path = base_profile->tplg_path;
+ else
+ out_profile->tplg_path = desc->default_tplg_path[ipc_type];
+
+ /* topology name */
+ out_profile->tplg_name = plat_data->tplg_filename;
+
+ out_profile->ipc_type = ipc_type;
+
+ /* Test only default firmware file */
+ if (!base_profile->fw_path && !base_profile->fw_name)
+ ret = sof_test_firmware_file(dev, out_profile, NULL);
+
+ if (!ret)
+ ret = sof_test_topology_file(dev, out_profile);
+
+out:
+ if (ret) {
+ /* Free up path strings created with devm_kasprintf */
+ if (fw_path_allocated)
+ devm_kfree(dev, out_profile->fw_path);
+ if (fw_lib_path_allocated)
+ devm_kfree(dev, out_profile->fw_lib_path);
+
+ memset(out_profile, 0, sizeof(*out_profile));
+ }
+
+ return ret;
+}
+
+static void
+sof_print_missing_firmware_info(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ struct sof_loadable_file_profile *base_profile)
+{
+ struct snd_sof_pdata *plat_data = sdev->pdata;
+ const struct sof_dev_desc *desc = plat_data->desc;
+ struct device *dev = sdev->dev;
+ int ipc_type_count, i;
+ char *marker;
+
+ dev_err(dev, "SOF firmware and/or topology file not found.\n");
+ dev_info(dev, "Supported default profiles\n");
+
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
+ ipc_type_count = SOF_IPC_TYPE_COUNT - 1;
+ else
+ ipc_type_count = base_profile->ipc_type;
+
+ for (i = 0; i <= ipc_type_count; i++) {
+ if (!(desc->ipc_supported_mask & BIT(i)))
+ continue;
+
+ if (i == ipc_type)
+ marker = "Requested";
+ else
+ marker = "Fallback";
+
+ dev_info(dev, "- ipc type %d (%s):\n", i, marker);
+ if (base_profile->fw_path_postfix)
+ dev_info(dev, " Firmware file: %s/%s/%s\n",
+ desc->default_fw_path[i],
+ base_profile->fw_path_postfix,
+ desc->default_fw_filename[i]);
+ else
+ dev_info(dev, " Firmware file: %s/%s\n",
+ desc->default_fw_path[i],
+ desc->default_fw_filename[i]);
+
+ dev_info(dev, " Topology file: %s/%s\n",
+ desc->default_tplg_path[i],
+ plat_data->tplg_filename);
+ }
+
+ if (base_profile->fw_path || base_profile->fw_name ||
+ base_profile->tplg_path || base_profile->tplg_name)
+ dev_info(dev, "Verify the path/name override module parameters.\n");
+
+ dev_info(dev, "Check if you have 'sof-firmware' package installed.\n");
+ dev_info(dev, "Optionally it can be manually downloaded from:\n");
+ dev_info(dev, " https://github.com/thesofproject/sof-bin/\n");
+}
+
+static void sof_print_profile_info(struct snd_sof_dev *sdev,
+ enum sof_ipc_type ipc_type,
+ struct sof_loadable_file_profile *profile)
+{
+ struct device *dev = sdev->dev;
+
+ if (ipc_type != profile->ipc_type)
+ dev_info(dev,
+ "Using fallback IPC type %d (requested type was %d)\n",
+ profile->ipc_type, ipc_type);
+
+ dev_info(dev, "Firmware paths/files for ipc type %d:\n", profile->ipc_type);
+
+ dev_info(dev, " Firmware file: %s/%s\n", profile->fw_path, profile->fw_name);
+ if (profile->fw_lib_path)
+ dev_info(dev, " Firmware lib path: %s\n", profile->fw_lib_path);
+ dev_info(dev, " Topology file: %s/%s\n", profile->tplg_path, profile->tplg_name);
+}
+
+int sof_create_ipc_file_profile(struct snd_sof_dev *sdev,
+ struct sof_loadable_file_profile *base_profile,
+ struct sof_loadable_file_profile *out_profile)
+{
+ const struct sof_dev_desc *desc = sdev->pdata->desc;
+ int ipc_fallback_start, ret, i;
+
+ memset(out_profile, 0, sizeof(*out_profile));
+
+ ret = sof_file_profile_for_ipc_type(sdev, base_profile->ipc_type, desc,
+ base_profile, out_profile);
+ if (!ret)
+ goto out;
+
+ /*
+ * No firmware file was found for the requested IPC type, as fallback
+ * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is selected, check
+ * all IPC versions in a backwards direction (from newer to older)
+ * if SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION is not selected,
+ * check only older IPC versions than the selected/default version
+ */
+ if (IS_ENABLED(CONFIG_SND_SOC_SOF_ALLOW_FALLBACK_TO_NEWER_IPC_VERSION))
+ ipc_fallback_start = SOF_IPC_TYPE_COUNT - 1;
+ else
+ ipc_fallback_start = (int)base_profile->ipc_type - 1;
+
+ for (i = ipc_fallback_start; i >= 0 ; i--) {
+ if (i == base_profile->ipc_type ||
+ !(desc->ipc_supported_mask & BIT(i)))
+ continue;
+
+ ret = sof_file_profile_for_ipc_type(sdev, i, desc, base_profile,
+ out_profile);
+ if (!ret)
+ break;
+ }
+
+out:
+ if (ret)
+ sof_print_missing_firmware_info(sdev, base_profile->ipc_type,
+ base_profile);
+ else
+ sof_print_profile_info(sdev, base_profile->ipc_type, out_profile);
+
+ return ret;
+}
+EXPORT_SYMBOL(sof_create_ipc_file_profile);
diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c
index 170740bce839..d777e70250ef 100644
--- a/sound/soc/sof/imx/imx8.c
+++ b/sound/soc/sof/imx/imx8.c
@@ -603,6 +603,7 @@ static struct snd_sof_dsp_ops sof_imx8x_ops = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP
};
diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c
index 2680f061ba42..1b976fa500aa 100644
--- a/sound/soc/sof/imx/imx8m.c
+++ b/sound/soc/sof/imx/imx8m.c
@@ -313,6 +313,13 @@ static struct snd_soc_dai_driver imx8m_dai[] = {
.channels_max = 32,
},
},
+{
+ .name = "micfil",
+ .capture = {
+ .channels_min = 1,
+ .channels_max = 8,
+ },
+},
};
static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev,
@@ -465,6 +472,7 @@ static struct snd_sof_dsp_ops sof_imx8m_ops = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
};
diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c
index ca6edb85ff71..2badca75782b 100644
--- a/sound/soc/sof/imx/imx8ulp.c
+++ b/sound/soc/sof/imx/imx8ulp.c
@@ -463,6 +463,7 @@ static struct snd_sof_dsp_ops sof_imx8ulp_ops = {
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_BATCH |
SNDRV_PCM_INFO_NO_PERIOD_WAKEUP,
/* PM */
diff --git a/sound/soc/sof/intel/apl.c b/sound/soc/sof/intel/apl.c
index 776b66389c34..dee6c7f73e80 100644
--- a/sound/soc/sof/intel/apl.c
+++ b/sound/soc/sof/intel/apl.c
@@ -55,7 +55,7 @@ int sof_apl_ops_init(struct snd_sof_dev *sdev)
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
diff --git a/sound/soc/sof/intel/cnl.c b/sound/soc/sof/intel/cnl.c
index 598cf50abadb..85e1e4760d0e 100644
--- a/sound/soc/sof/intel/cnl.c
+++ b/sound/soc/sof/intel/cnl.c
@@ -402,7 +402,7 @@ int sof_cnl_ops_init(struct snd_sof_dev *sdev)
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c
index a20deaf3b428..f4cbc0ad5de3 100644
--- a/sound/soc/sof/intel/hda-dai.c
+++ b/sound/soc/sof/intel/hda-dai.c
@@ -621,6 +621,9 @@ void hda_ops_free(struct snd_sof_dev *sdev)
if (!hda_use_tplg_nhlt)
intel_nhlt_free(ipc4_data->nhlt);
+
+ kfree(sdev->private);
+ sdev->private = NULL;
}
}
EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
diff --git a/sound/soc/sof/intel/hda-loader.c b/sound/soc/sof/intel/hda-loader.c
index 46fb2d1425e9..b81f231abee3 100644
--- a/sound/soc/sof/intel/hda-loader.c
+++ b/sound/soc/sof/intel/hda-loader.c
@@ -510,9 +510,8 @@ cleanup:
return chip_info->init_core_mask;
/* disable DSP */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR,
- SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_GPROCEN, 0);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
+
return ret;
}
@@ -520,14 +519,15 @@ int hda_dsp_ipc4_load_library(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload)
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
+ struct sof_ipc4_fw_data *ipc4_data = sdev->private;
struct hdac_ext_stream *hext_stream;
struct firmware stripped_firmware;
struct sof_ipc4_msg msg = {};
struct snd_dma_buffer dmab;
int ret, ret1;
- /* IMR booting will restore the libraries as well, skip the loading */
- if (reload && hda->booted_from_imr)
+ /* if IMR booting is enabled and fw context is saved for D3 state, skip the loading */
+ if (reload && hda->booted_from_imr && ipc4_data->fw_context_save)
return 0;
/* the fw_lib has been verified during loading, we can trust the validity here */
diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c
index 744c0dd5766d..fe4ae349dad5 100644
--- a/sound/soc/sof/intel/hda.c
+++ b/sound/soc/sof/intel/hda.c
@@ -1350,8 +1350,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
if (!sdev->dspless_mode_selected) {
/* disable DSP IRQ */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_PIE, 0);
+ hda_dsp_ctrl_ppcap_int_enable(sdev, false);
}
/* disable CIE and GIE interrupts */
@@ -1366,8 +1365,7 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
chip->power_down_dsp(sdev);
/* disable DSP */
- snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
- SOF_HDA_PPCTL_GPROCEN, 0);
+ hda_dsp_ctrl_ppcap_enable(sdev, false);
skip_disable_dsp:
free_irq(sdev->ipc_irq, sdev);
diff --git a/sound/soc/sof/intel/icl.c b/sound/soc/sof/intel/icl.c
index 8e29d6bb6fe8..040698591992 100644
--- a/sound/soc/sof/intel/icl.c
+++ b/sound/soc/sof/intel/icl.c
@@ -123,7 +123,7 @@ int sof_icl_ops_init(struct snd_sof_dev *sdev)
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c
index db94b45e53af..30712ea05a7a 100644
--- a/sound/soc/sof/intel/lnl.c
+++ b/sound/soc/sof/intel/lnl.c
@@ -120,7 +120,11 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+ /* dsp core get/put */
+ sof_lnl_ops.core_get = mtl_dsp_core_get;
+ sof_lnl_ops.core_put = mtl_dsp_core_put;
+
+ sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -129,6 +133,8 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ ipc4_data->fw_context_save = true;
+
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c
index 7946110e7adf..df05dc77b8d5 100644
--- a/sound/soc/sof/intel/mtl.c
+++ b/sound/soc/sof/intel/mtl.c
@@ -440,7 +440,8 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int status;
- u32 ipc_hdr;
+ u32 ipc_hdr, flags;
+ char *dump_msg;
int ret;
/* step 1: purge FW request */
@@ -493,8 +494,18 @@ int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot)
return 0;
err:
- snd_sof_dsp_dbg_dump(sdev, "MTL DSP init fail", 0);
+ flags = SOF_DBG_DUMP_PCI | SOF_DBG_DUMP_MBOX | SOF_DBG_DUMP_OPTIONAL;
+
+ /* after max boot attempts make sure that the dump is printed */
+ if (hda->boot_iteration == HDA_FW_BOOT_ATTEMPTS)
+ flags &= ~SOF_DBG_DUMP_OPTIONAL;
+
+ dump_msg = kasprintf(GFP_KERNEL, "Boot iteration failed: %d/%d",
+ hda->boot_iteration, HDA_FW_BOOT_ATTEMPTS);
+ snd_sof_dsp_dbg_dump(sdev, dump_msg, flags);
mtl_dsp_core_power_down(sdev, SOF_DSP_PRIMARY_CORE);
+
+ kfree(dump_msg);
return ret;
}
@@ -627,7 +638,7 @@ u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
return ((u64)llp_u << 32) | llp_l;
}
-static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
+int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
@@ -640,7 +651,7 @@ static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
return 0;
}
-static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
+int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core)
{
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
int ret;
@@ -698,7 +709,7 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -707,6 +718,8 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ ipc4_data->fw_context_save = true;
+
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h
index 95696b3d7c4c..cc5a1f46fd09 100644
--- a/sound/soc/sof/intel/mtl.h
+++ b/sound/soc/sof/intel/mtl.h
@@ -106,3 +106,6 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev);
u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream);
+
+int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core);
+int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core);
diff --git a/sound/soc/sof/intel/skl.c b/sound/soc/sof/intel/skl.c
index d24e64e71b58..93824e6ce573 100644
--- a/sound/soc/sof/intel/skl.c
+++ b/sound/soc/sof/intel/skl.c
@@ -62,7 +62,7 @@ int sof_skl_ops_init(struct snd_sof_dev *sdev)
/* probe/remove/shutdown */
sof_skl_ops.shutdown = hda_dsp_shutdown;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c
index f7de1f5ba06d..c2bb04c89b9d 100644
--- a/sound/soc/sof/intel/tgl.c
+++ b/sound/soc/sof/intel/tgl.c
@@ -82,7 +82,7 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
if (sdev->pdata->ipc_type == SOF_IPC_TYPE_4) {
struct sof_ipc4_fw_data *ipc4_data;
- sdev->private = devm_kzalloc(sdev->dev, sizeof(*ipc4_data), GFP_KERNEL);
+ sdev->private = kzalloc(sizeof(*ipc4_data), GFP_KERNEL);
if (!sdev->private)
return -ENOMEM;
@@ -91,6 +91,8 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev)
ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2;
+ ipc4_data->fw_context_save = true;
+
/* External library loading support */
ipc4_data->load_library = hda_dsp_ipc4_load_library;
diff --git a/sound/soc/sof/ipc3-dtrace.c b/sound/soc/sof/ipc3-dtrace.c
index 0dca139322f3..93b189c2d2ee 100644
--- a/sound/soc/sof/ipc3-dtrace.c
+++ b/sound/soc/sof/ipc3-dtrace.c
@@ -137,6 +137,7 @@ static int trace_filter_parse(struct snd_sof_dev *sdev, char *string,
dev_err(sdev->dev,
"Parsing filter entry '%s' failed with %d\n",
entry, entry_len);
+ kfree(*out);
return -EINVAL;
}
}
@@ -208,13 +209,13 @@ static ssize_t dfsentry_trace_filter_write(struct file *file, const char __user
ret = ipc3_trace_update_filter(sdev, num_elems, elems);
if (ret < 0) {
dev_err(sdev->dev, "Filter update failed: %d\n", ret);
+ kfree(elems);
goto error;
}
}
ret = count;
error:
kfree(string);
- kfree(elems);
return ret;
}
diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c
index 2d0addcbc819..330f04bcd75d 100644
--- a/sound/soc/sof/ipc3-pcm.c
+++ b/sound/soc/sof/ipc3-pcm.c
@@ -384,6 +384,17 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
dev_dbg(component->dev, "AMD_DMIC channels_min: %d channels_max: %d\n",
channels->min, channels->max);
break;
+ case SOF_DAI_IMX_MICFIL:
+ rate->min = private->dai_config->micfil.pdm_rate;
+ rate->max = private->dai_config->micfil.pdm_rate;
+ channels->min = private->dai_config->micfil.pdm_ch;
+ channels->max = private->dai_config->micfil.pdm_ch;
+
+ dev_dbg(component->dev,
+ "MICFIL PDM rate_min: %d rate_max: %d\n", rate->min, rate->max);
+ dev_dbg(component->dev, "MICFIL PDM channels_min: %d channels_max: %d\n",
+ channels->min, channels->max);
+ break;
default:
dev_err(component->dev, "Invalid DAI type %d\n", private->dai_config->type);
break;
diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 2c7a5e7a364c..a8832a1c1a24 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -72,6 +72,8 @@ static const struct sof_topology_token buffer_tokens[] = {
offsetof(struct sof_ipc_buffer, size)},
{SOF_TKN_BUF_CAPS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
offsetof(struct sof_ipc_buffer, caps)},
+ {SOF_TKN_BUF_FLAGS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_buffer, flags)},
};
/* DAI */
@@ -286,6 +288,16 @@ static const struct sof_topology_token acpi2s_tokens[] = {
offsetof(struct sof_ipc_dai_acp_params, tdm_mode)},
};
+/* MICFIL PDM */
+static const struct sof_topology_token micfil_pdm_tokens[] = {
+ {SOF_TKN_IMX_MICFIL_RATE,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_micfil_params, pdm_rate)},
+ {SOF_TKN_IMX_MICFIL_CH,
+ SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+ offsetof(struct sof_ipc_dai_micfil_params, pdm_ch)},
+};
+
/* Core tokens */
static const struct sof_topology_token core_tokens[] = {
{SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -322,6 +334,8 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
[SOF_AFE_TOKENS] = {"AFE tokens", afe_tokens, ARRAY_SIZE(afe_tokens)},
[SOF_ACPDMIC_TOKENS] = {"ACPDMIC tokens", acpdmic_tokens, ARRAY_SIZE(acpdmic_tokens)},
[SOF_ACPI2S_TOKENS] = {"ACPI2S tokens", acpi2s_tokens, ARRAY_SIZE(acpi2s_tokens)},
+ [SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens",
+ micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)},
};
/**
@@ -1138,6 +1152,37 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_da
return 0;
}
+static int sof_link_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
+ struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
+{
+ struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
+ struct sof_dai_private_data *private = dai->private;
+ u32 size = sizeof(*config);
+ int ret;
+
+ /* handle master/slave and inverted clocks */
+ sof_dai_set_format(hw_config, config);
+
+ config->hdr.size = size;
+
+ /* parse the required set of MICFIL PDM tokens based on num_hw_cfgs */
+ ret = sof_update_ipc_object(scomp, &config->micfil, SOF_MICFIL_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
+
+ dev_info(scomp->dev, "MICFIL PDM config dai_index %d channel %d rate %d\n",
+ config->dai_index, config->micfil.pdm_ch, config->micfil.pdm_rate);
+
+ dai->number_configs = 1;
+ dai->current_config = 0;
+ private->dai_config = kmemdup(config, size, GFP_KERNEL);
+ if (!private->dai_config)
+ return -ENOMEM;
+
+ return 0;
+}
+
static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink,
struct sof_ipc_dai_config *config, struct snd_sof_dai *dai)
{
@@ -1176,6 +1221,7 @@ static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_
struct snd_soc_tplg_hw_config *hw_config = slink->hw_configs;
struct sof_dai_private_data *private = dai->private;
u32 size = sizeof(*config);
+ int ret;
/* handle master/slave and inverted clocks */
sof_dai_set_format(hw_config, config);
@@ -1184,12 +1230,14 @@ static int sof_link_acp_bt_load(struct snd_soc_component *scomp, struct snd_sof_
memset(&config->acpbt, 0, sizeof(config->acpbt));
config->hdr.size = size;
- config->acpbt.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
- config->acpbt.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+ ret = sof_update_ipc_object(scomp, &config->acpbt, SOF_ACPI2S_TOKENS, slink->tuples,
+ slink->num_tuples, size, slink->num_hw_configs);
+ if (ret < 0)
+ return ret;
- dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
+ dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d tdm_mode %d\n",
config->dai_index, config->acpbt.tdm_slots,
- config->acpbt.fsync_rate);
+ config->acpbt.fsync_rate, config->acpbt.tdm_mode);
dai->number_configs = 1;
dai->current_config = 0;
@@ -1561,6 +1609,9 @@ static int sof_ipc3_widget_setup_comp_dai(struct snd_sof_widget *swidget)
case SOF_DAI_IMX_ESAI:
ret = sof_link_esai_load(scomp, slink, config, dai);
break;
+ case SOF_DAI_IMX_MICFIL:
+ ret = sof_link_micfil_load(scomp, slink, config, dai);
+ break;
case SOF_DAI_AMD_BT:
ret = sof_link_acp_bt_load(scomp, slink, config, dai);
break;
diff --git a/sound/soc/sof/ipc4-control.c b/sound/soc/sof/ipc4-control.c
index b4cdcec33e12..1be9519de909 100644
--- a/sound/soc/sof/ipc4-control.c
+++ b/sound/soc/sof/ipc4-control.c
@@ -240,6 +240,50 @@ sof_ipc4_set_generic_control_data(struct snd_sof_dev *sdev,
return ret;
}
+static void sof_ipc4_refresh_generic_control(struct snd_sof_control *scontrol)
+{
+ struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
+ struct snd_soc_component *scomp = scontrol->scomp;
+ struct sof_ipc4_control_msg_payload *data;
+ struct sof_ipc4_msg *msg = &cdata->msg;
+ size_t data_size;
+ unsigned int i;
+ int ret;
+
+ if (!scontrol->comp_data_dirty)
+ return;
+
+ if (!pm_runtime_active(scomp->dev))
+ return;
+
+ data_size = struct_size(data, chanv, scontrol->num_channels);
+ data = kmalloc(data_size, GFP_KERNEL);
+ if (!data)
+ return;
+
+ data->id = cdata->index;
+ data->num_elems = scontrol->num_channels;
+ msg->data_ptr = data;
+ msg->data_size = data_size;
+
+ scontrol->comp_data_dirty = false;
+ ret = sof_ipc4_set_get_kcontrol_data(scontrol, false, true);
+ msg->data_ptr = NULL;
+ msg->data_size = 0;
+ if (!ret) {
+ for (i = 0; i < scontrol->num_channels; i++) {
+ cdata->chanv[i].channel = data->chanv[i].channel;
+ cdata->chanv[i].value = data->chanv[i].value;
+ }
+ } else {
+ dev_err(scomp->dev, "Failed to read control data for %s\n",
+ scontrol->name);
+ scontrol->comp_data_dirty = true;
+ }
+
+ kfree(data);
+}
+
static bool sof_ipc4_switch_put(struct snd_sof_control *scontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -290,6 +334,8 @@ static int sof_ipc4_switch_get(struct snd_sof_control *scontrol,
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
unsigned int i;
+ sof_ipc4_refresh_generic_control(scontrol);
+
/* read back each channel */
for (i = 0; i < scontrol->num_channels; i++)
ucontrol->value.integer.value[i] = cdata->chanv[i].value;
@@ -347,6 +393,8 @@ static int sof_ipc4_enum_get(struct snd_sof_control *scontrol,
struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data;
unsigned int i;
+ sof_ipc4_refresh_generic_control(scontrol);
+
/* read back each channel */
for (i = 0; i < scontrol->num_channels; i++)
ucontrol->value.enumerated.item[i] = cdata->chanv[i].value;
@@ -601,6 +649,136 @@ sof_ipc4_volsw_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget,
return sof_ipc4_set_volume_data(sdev, swidget, scontrol, false);
}
+#define PARAM_ID_FROM_EXTENSION(_ext) (((_ext) & SOF_IPC4_MOD_EXT_MSG_PARAM_ID_MASK) \
+ >> SOF_IPC4_MOD_EXT_MSG_PARAM_ID_SHIFT)
+
+static void sof_ipc4_control_update(struct snd_sof_dev *sdev, void *ipc_message)
+{
+ struct sof_ipc4_msg *ipc4_msg = ipc_message;
+ struct sof_ipc4_notify_module_data *ndata = ipc4_msg->data_ptr;
+ struct sof_ipc4_control_msg_payload *msg_data;
+ struct sof_ipc4_control_data *cdata;
+ struct snd_soc_dapm_widget *widget;
+ struct snd_sof_control *scontrol;
+ struct snd_sof_widget *swidget;
+ struct snd_kcontrol *kc = NULL;
+ bool scontrol_found = false;
+ u32 event_param_id;
+ int i, type;
+
+ if (ndata->event_data_size < sizeof(*msg_data)) {
+ dev_err(sdev->dev,
+ "%s: Invalid event data size for module %u.%u: %u\n",
+ __func__, ndata->module_id, ndata->instance_id,
+ ndata->event_data_size);
+ return;
+ }
+
+ event_param_id = ndata->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_PARAMID_MASK;
+ switch (event_param_id) {
+ case SOF_IPC4_SWITCH_CONTROL_PARAM_ID:
+ type = SND_SOC_TPLG_TYPE_MIXER;
+ break;
+ case SOF_IPC4_ENUM_CONTROL_PARAM_ID:
+ type = SND_SOC_TPLG_TYPE_ENUM;
+ break;
+ default:
+ dev_err(sdev->dev,
+ "%s: Invalid control type for module %u.%u: %u\n",
+ __func__, ndata->module_id, ndata->instance_id,
+ event_param_id);
+ return;
+ }
+
+ /* Find the swidget based on ndata->module_id and ndata->instance_id */
+ swidget = sof_ipc4_find_swidget_by_ids(sdev, ndata->module_id,
+ ndata->instance_id);
+ if (!swidget) {
+ dev_err(sdev->dev, "%s: Failed to find widget for module %u.%u\n",
+ __func__, ndata->module_id, ndata->instance_id);
+ return;
+ }
+
+ /* Find the scontrol which is the source of the notification */
+ msg_data = (struct sof_ipc4_control_msg_payload *)ndata->event_data;
+ list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+ if (scontrol->comp_id == swidget->comp_id) {
+ u32 local_param_id;
+
+ cdata = scontrol->ipc_control_data;
+ /*
+ * The scontrol's param_id is stored in the IPC message
+ * template's extension
+ */
+ local_param_id = PARAM_ID_FROM_EXTENSION(cdata->msg.extension);
+ if (local_param_id == event_param_id &&
+ msg_data->id == cdata->index) {
+ scontrol_found = true;
+ break;
+ }
+ }
+ }
+
+ if (!scontrol_found) {
+ dev_err(sdev->dev,
+ "%s: Failed to find control on widget %s: %u:%u\n",
+ __func__, swidget->widget->name, ndata->event_id & 0xffff,
+ msg_data->id);
+ return;
+ }
+
+ if (msg_data->num_elems) {
+ /*
+ * The message includes the updated value/data, update the
+ * control's local cache using the received notification
+ */
+ for (i = 0; i < msg_data->num_elems; i++) {
+ u32 channel = msg_data->chanv[i].channel;
+
+ if (channel >= scontrol->num_channels) {
+ dev_warn(sdev->dev,
+ "Invalid channel index for %s: %u\n",
+ scontrol->name, i);
+
+ /*
+ * Mark the scontrol as dirty to force a refresh
+ * on next read
+ */
+ scontrol->comp_data_dirty = true;
+ break;
+ }
+
+ cdata->chanv[channel].value = msg_data->chanv[i].value;
+ }
+ } else {
+ /*
+ * Mark the scontrol as dirty because the value/data is changed
+ * in firmware, forcing a refresh on next read access
+ */
+ scontrol->comp_data_dirty = true;
+ }
+
+ /*
+ * Look up the ALSA kcontrol of the scontrol to be able to send a
+ * notification to user space
+ */
+ widget = swidget->widget;
+ for (i = 0; i < widget->num_kcontrols; i++) {
+ /* skip non matching types or non matching indexes within type */
+ if (widget->dobj.widget.kcontrol_type[i] == type &&
+ widget->kcontrol_news[i].index == cdata->index) {
+ kc = widget->kcontrols[i];
+ break;
+ }
+ }
+
+ if (!kc)
+ return;
+
+ snd_ctl_notify_one(swidget->scomp->card->snd_card,
+ SNDRV_CTL_EVENT_MASK_VALUE, kc, 0);
+}
+
/* set up all controls for the widget */
static int sof_ipc4_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
{
@@ -674,6 +852,7 @@ const struct sof_ipc_tplg_control_ops tplg_ipc4_control_ops = {
.bytes_ext_put = sof_ipc4_bytes_ext_put,
.bytes_ext_get = sof_ipc4_bytes_ext_get,
.bytes_ext_volatile_get = sof_ipc4_bytes_ext_volatile_get,
+ .update = sof_ipc4_control_update,
.widget_kcontrol_setup = sof_ipc4_widget_kcontrol_setup,
.set_up_volume_table = sof_ipc4_set_up_volume_table,
};
diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c
index eaa04762eb11..3539b0a66e1b 100644
--- a/sound/soc/sof/ipc4-loader.c
+++ b/sound/soc/sof/ipc4-loader.c
@@ -391,6 +391,9 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev)
goto out;
}
break;
+ case SOF_IPC4_FW_CONTEXT_SAVE:
+ ipc4_data->fw_context_save = *tuple->value;
+ break;
default:
break;
}
diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h
index 9e69b7c29117..1d39836d5efa 100644
--- a/sound/soc/sof/ipc4-priv.h
+++ b/sound/soc/sof/ipc4-priv.h
@@ -81,6 +81,7 @@ struct sof_ipc4_fw_data {
u32 mtrace_log_bytes;
int max_num_pipelines;
u32 max_libs_count;
+ bool fw_context_save;
int (*load_library)(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_library *fw_lib, bool reload);
@@ -115,6 +116,9 @@ int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev);
struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev,
const guid_t *uuid);
+struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
+ u32 module_id, int instance_id);
+
struct sof_ipc4_base_module_cfg;
void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev,
struct sof_ipc4_fw_module *fw_module,
diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c
index e012b6e166ac..f779156fe0e6 100644
--- a/sound/soc/sof/ipc4-topology.c
+++ b/sound/soc/sof/ipc4-topology.c
@@ -167,6 +167,26 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)},
};
+struct snd_sof_widget *sof_ipc4_find_swidget_by_ids(struct snd_sof_dev *sdev,
+ u32 module_id, int instance_id)
+{
+ struct snd_sof_widget *swidget;
+
+ list_for_each_entry(swidget, &sdev->widget_list, list) {
+ struct sof_ipc4_fw_module *fw_module = swidget->module_info;
+
+ /* Only active module instances have valid instance_id */
+ if (!swidget->use_count)
+ continue;
+
+ if (fw_module && fw_module->man4_module_entry.id == module_id &&
+ swidget->instance_id == instance_id)
+ return swidget;
+ }
+
+ return NULL;
+}
+
static void sof_ipc4_dbg_audio_format(struct device *dev, struct sof_ipc4_pin_format *pin_fmt,
int num_formats)
{
@@ -2372,6 +2392,8 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
}
if (swidget->id != snd_soc_dapm_scheduler) {
+ int module_id = msg->primary & SOF_IPC4_MOD_ID_MASK;
+
ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
if (ret < 0) {
dev_err(sdev->dev, "failed to assign instance id for %s\n",
@@ -2387,9 +2409,15 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg->extension &= ~SOF_IPC4_MOD_EXT_PPL_ID_MASK;
msg->extension |= SOF_IPC4_MOD_EXT_PPL_ID(pipe_widget->instance_id);
+
+ dev_dbg(sdev->dev, "Create widget %s (pipe %d) - ID %d, instance %d, core %d\n",
+ swidget->widget->name, swidget->pipeline_id, module_id,
+ swidget->instance_id, swidget->core);
+ } else {
+ dev_dbg(sdev->dev, "Create pipeline %s (pipe %d) - instance %d, core %d\n",
+ swidget->widget->name, swidget->pipeline_id,
+ swidget->instance_id, swidget->core);
}
- dev_dbg(sdev->dev, "Create widget %s instance %d - pipe %d - core %d\n",
- swidget->widget->name, swidget->instance_id, swidget->pipeline_id, swidget->core);
msg->data_size = ipc_size;
msg->data_ptr = ipc_data;
diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c
index 8441f4ae4065..ac5c6bc66d2a 100644
--- a/sound/soc/sof/ipc4.c
+++ b/sound/soc/sof/ipc4.c
@@ -78,6 +78,9 @@ static const struct sof_ipc4_fw_status {
{165, "Reserved (ADSP_IPC_PIPELINE_ALREADY_EXISTS removed)"},
};
+typedef void (*ipc4_notification_handler)(struct snd_sof_dev *sdev,
+ struct sof_ipc4_msg *msg);
+
static int sof_ipc4_check_reply_status(struct snd_sof_dev *sdev, u32 status)
{
int i, ret;
@@ -573,46 +576,64 @@ EXPORT_SYMBOL(sof_ipc4_find_debug_slot_offset_by_type);
static int ipc4_fw_ready(struct snd_sof_dev *sdev, struct sof_ipc4_msg *ipc4_msg)
{
- int inbox_offset, inbox_size, outbox_offset, outbox_size;
-
/* no need to re-check version/ABI for subsequent boots */
if (!sdev->first_boot)
return 0;
- /* Set up the windows for IPC communication */
- inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev);
- if (inbox_offset < 0) {
- dev_err(sdev->dev, "%s: No mailbox offset\n", __func__);
- return inbox_offset;
- }
- inbox_size = SOF_IPC4_MSG_MAX_SIZE;
- outbox_offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_OUTBOX_WINDOW_IDX);
- outbox_size = SOF_IPC4_MSG_MAX_SIZE;
+ sof_ipc4_create_exception_debugfs_node(sdev);
- sdev->fw_info_box.offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_INBOX_WINDOW_IDX);
- sdev->fw_info_box.size = sizeof(struct sof_ipc4_fw_registers);
- sdev->dsp_box.offset = inbox_offset;
- sdev->dsp_box.size = inbox_size;
- sdev->host_box.offset = outbox_offset;
- sdev->host_box.size = outbox_size;
+ return sof_ipc4_init_msg_memory(sdev);
+}
- sdev->debug_box.offset = snd_sof_dsp_get_window_offset(sdev,
- SOF_IPC4_DEBUG_WINDOW_IDX);
+static void sof_ipc4_module_notification_handler(struct snd_sof_dev *sdev,
+ struct sof_ipc4_msg *ipc4_msg)
+{
+ struct sof_ipc4_notify_module_data *data = ipc4_msg->data_ptr;
+
+ /*
+ * If the notification includes additional, module specific data, then
+ * we need to re-allocate the buffer and re-read the whole payload,
+ * including the event_data
+ */
+ if (data->event_data_size) {
+ void *new;
+ int ret;
+
+ ipc4_msg->data_size += data->event_data_size;
+
+ new = krealloc(ipc4_msg->data_ptr, ipc4_msg->data_size, GFP_KERNEL);
+ if (!new) {
+ ipc4_msg->data_size -= data->event_data_size;
+ return;
+ }
- sof_ipc4_create_exception_debugfs_node(sdev);
+ /* re-read the whole payload */
+ ipc4_msg->data_ptr = new;
+ ret = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr,
+ ipc4_msg->data_size);
+ if (ret < 0) {
+ dev_err(sdev->dev,
+ "Failed to read the full module notification: %d\n",
+ ret);
+ return;
+ }
+ data = ipc4_msg->data_ptr;
+ }
- dev_dbg(sdev->dev, "mailbox upstream 0x%x - size 0x%x\n",
- inbox_offset, inbox_size);
- dev_dbg(sdev->dev, "mailbox downstream 0x%x - size 0x%x\n",
- outbox_offset, outbox_size);
- dev_dbg(sdev->dev, "debug box 0x%x\n", sdev->debug_box.offset);
+ /* Handle ALSA kcontrol notification */
+ if ((data->event_id & SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_MASK) ==
+ SOF_IPC4_NOTIFY_MODULE_EVENTID_ALSA_MAGIC_VAL) {
+ const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
- return sof_ipc4_init_msg_memory(sdev);
+ if (tplg_ops->control->update)
+ tplg_ops->control->update(sdev, ipc4_msg);
+ }
}
static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
{
struct sof_ipc4_msg *ipc4_msg = sdev->ipc->msg.rx_data;
+ ipc4_notification_handler handler_func = NULL;
size_t data_size = 0;
int err;
@@ -648,6 +669,10 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
case SOF_IPC4_NOTIFY_EXCEPTION_CAUGHT:
snd_sof_dsp_panic(sdev, 0, true);
break;
+ case SOF_IPC4_NOTIFY_MODULE_NOTIFICATION:
+ data_size = sizeof(struct sof_ipc4_notify_module_data);
+ handler_func = sof_ipc4_module_notification_handler;
+ break;
default:
dev_dbg(sdev->dev, "Unhandled DSP message: %#x|%#x\n",
ipc4_msg->primary, ipc4_msg->extension);
@@ -660,9 +685,20 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
return;
ipc4_msg->data_size = data_size;
- snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size);
+ err = snd_sof_ipc_msg_data(sdev, NULL, ipc4_msg->data_ptr, ipc4_msg->data_size);
+ if (err < 0) {
+ dev_err(sdev->dev, "failed to read IPC notification data: %d\n", err);
+ kfree(ipc4_msg->data_ptr);
+ ipc4_msg->data_ptr = NULL;
+ ipc4_msg->data_size = 0;
+ return;
+ }
}
+ /* Handle notifications with payload */
+ if (handler_func)
+ handler_func(sdev, ipc4_msg);
+
sof_ipc4_log_header(sdev->dev, "ipc rx done ", ipc4_msg, true);
if (data_size) {
@@ -732,11 +768,38 @@ static const struct sof_ipc_pm_ops ipc4_pm_ops = {
static int sof_ipc4_init(struct snd_sof_dev *sdev)
{
struct sof_ipc4_fw_data *ipc4_data = sdev->private;
+ int inbox_offset;
mutex_init(&ipc4_data->pipeline_state_mutex);
xa_init_flags(&ipc4_data->fw_lib_xa, XA_FLAGS_ALLOC);
+ /* Set up the windows for IPC communication */
+ inbox_offset = snd_sof_dsp_get_mailbox_offset(sdev);
+ if (inbox_offset < 0) {
+ dev_err(sdev->dev, "%s: No mailbox offset\n", __func__);
+ return inbox_offset;
+ }
+
+ sdev->dsp_box.offset = inbox_offset;
+ sdev->dsp_box.size = SOF_IPC4_MSG_MAX_SIZE;
+ sdev->host_box.offset = snd_sof_dsp_get_window_offset(sdev,
+ SOF_IPC4_OUTBOX_WINDOW_IDX);
+ sdev->host_box.size = SOF_IPC4_MSG_MAX_SIZE;
+
+ sdev->debug_box.offset = snd_sof_dsp_get_window_offset(sdev,
+ SOF_IPC4_DEBUG_WINDOW_IDX);
+
+ sdev->fw_info_box.offset = snd_sof_dsp_get_window_offset(sdev,
+ SOF_IPC4_INBOX_WINDOW_IDX);
+ sdev->fw_info_box.size = sizeof(struct sof_ipc4_fw_registers);
+
+ dev_dbg(sdev->dev, "mailbox upstream %#x - size %#x\n",
+ sdev->dsp_box.offset, SOF_IPC4_MSG_MAX_SIZE);
+ dev_dbg(sdev->dev, "mailbox downstream %#x - size %#x\n",
+ sdev->host_box.offset, SOF_IPC4_MSG_MAX_SIZE);
+ dev_dbg(sdev->dev, "debug box %#x\n", sdev->debug_box.offset);
+
return 0;
}
diff --git a/sound/soc/sof/mediatek/adsp_helper.h b/sound/soc/sof/mediatek/adsp_helper.h
index d41e904e6614..35527567962e 100644
--- a/sound/soc/sof/mediatek/adsp_helper.h
+++ b/sound/soc/sof/mediatek/adsp_helper.h
@@ -15,17 +15,13 @@
struct mtk_adsp_chip_info {
phys_addr_t pa_sram;
phys_addr_t pa_dram; /* adsp dram physical base */
- phys_addr_t pa_shared_dram; /* adsp dram physical base */
phys_addr_t pa_cfgreg;
u32 sramsize;
u32 dramsize;
u32 cfgregsize;
- u32 shared_size;
void __iomem *va_sram; /* corresponding to pa_sram */
void __iomem *va_dram; /* corresponding to pa_dram */
void __iomem *va_cfgreg;
- void __iomem *shared_sram; /* part of va_sram */
- void __iomem *shared_dram; /* part of va_dram */
phys_addr_t adsp_bootup_addr;
int dram_offset; /*dram offset between system and dsp view*/
diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c
index b69fa788b16f..0d2d7d697de0 100644
--- a/sound/soc/sof/mediatek/mt8186/mt8186.c
+++ b/sound/soc/sof/mediatek/mt8186/mt8186.c
@@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
struct mtk_adsp_chip_info *adsp = data;
int ret;
- mem_region = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (!mem_region) {
- dev_err(dev, "no dma memory-region phandle\n");
- return -ENODEV;
- }
-
- ret = of_address_to_resource(mem_region, 0, &res);
- of_node_put(mem_region);
- if (ret) {
- dev_err(dev, "of_address_to_resource dma failed\n");
- return ret;
- }
-
- dev_dbg(dev, "DMA %pR\n", &res);
-
- adsp->pa_shared_dram = (phys_addr_t)res.start;
- adsp->shared_size = resource_size(&res);
- if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
- dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
- (u32)adsp->pa_shared_dram);
- return -EINVAL;
- }
-
ret = of_reserved_mem_device_init(dev);
if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -248,26 +225,6 @@ static int adsp_memory_remap_init(struct snd_sof_dev *sdev, struct mtk_adsp_chip
return 0;
}
-static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
-{
- struct device *dev = &pdev->dev;
- struct mtk_adsp_chip_info *adsp = data;
-
- /* remap shared-dram base to be non-cachable */
- adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
- adsp->shared_size);
- if (!adsp->shared_dram) {
- dev_err(dev, "failed to ioremap base %pa size %#x\n",
- adsp->shared_dram, adsp->shared_size);
- return -ENOMEM;
- }
-
- dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
- adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
-
- return 0;
-}
-
static int mt8186_run(struct snd_sof_dev *sdev)
{
u32 adsp_bootup_addr;
@@ -324,12 +281,6 @@ static int mt8186_dsp_probe(struct snd_sof_dev *sdev)
priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM];
- ret = adsp_shared_base_ioremap(pdev, priv->adsp);
- if (ret) {
- dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n");
- return ret;
- }
-
sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg;
sdev->bar[DSP_SECREG_BAR] = priv->adsp->va_secreg;
sdev->bar[DSP_BUSREG_BAR] = priv->adsp->va_busreg;
diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c
index cac0a085f60a..8ee7ee246344 100644
--- a/sound/soc/sof/mediatek/mt8195/mt8195.c
+++ b/sound/soc/sof/mediatek/mt8195/mt8195.c
@@ -96,29 +96,6 @@ static int platform_parse_resource(struct platform_device *pdev, void *data)
struct mtk_adsp_chip_info *adsp = data;
int ret;
- mem_region = of_parse_phandle(dev->of_node, "memory-region", 0);
- if (!mem_region) {
- dev_err(dev, "no dma memory-region phandle\n");
- return -ENODEV;
- }
-
- ret = of_address_to_resource(mem_region, 0, &res);
- of_node_put(mem_region);
- if (ret) {
- dev_err(dev, "of_address_to_resource dma failed\n");
- return ret;
- }
-
- dev_dbg(dev, "DMA %pR\n", &res);
-
- adsp->pa_shared_dram = (phys_addr_t)res.start;
- adsp->shared_size = resource_size(&res);
- if (adsp->pa_shared_dram & DRAM_REMAP_MASK) {
- dev_err(dev, "adsp shared dma memory(%#x) is not 4K-aligned\n",
- (u32)adsp->pa_shared_dram);
- return -EINVAL;
- }
-
ret = of_reserved_mem_device_init(dev);
if (ret) {
dev_err(dev, "of_reserved_mem_device_init failed\n");
@@ -238,26 +215,6 @@ static int adsp_memory_remap_init(struct device *dev, struct mtk_adsp_chip_info
return 0;
}
-static int adsp_shared_base_ioremap(struct platform_device *pdev, void *data)
-{
- struct device *dev = &pdev->dev;
- struct mtk_adsp_chip_info *adsp = data;
-
- /* remap shared-dram base to be non-cachable */
- adsp->shared_dram = devm_ioremap(dev, adsp->pa_shared_dram,
- adsp->shared_size);
- if (!adsp->shared_dram) {
- dev_err(dev, "failed to ioremap base %pa size %#x\n",
- adsp->shared_dram, adsp->shared_size);
- return -ENOMEM;
- }
-
- dev_dbg(dev, "shared-dram vbase=%p, phy addr :%pa, size=%#x\n",
- adsp->shared_dram, &adsp->pa_shared_dram, adsp->shared_size);
-
- return 0;
-}
-
static int mt8195_run(struct snd_sof_dev *sdev)
{
u32 adsp_bootup_addr;
@@ -338,12 +295,6 @@ static int mt8195_dsp_probe(struct snd_sof_dev *sdev)
}
priv->adsp->va_dram = sdev->bar[SOF_FW_BLK_TYPE_SRAM];
- ret = adsp_shared_base_ioremap(pdev, priv->adsp);
- if (ret) {
- dev_err(sdev->dev, "adsp_shared_base_ioremap fail!\n");
- goto err_adsp_sram_power_off;
- }
-
sdev->bar[DSP_REG_BAR] = priv->adsp->va_cfgreg;
sdev->mmio_bar = SOF_FW_BLK_TYPE_SRAM;
diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c
index 84a4a0a3318e..2977f0a63fba 100644
--- a/sound/soc/sof/sof-acpi-dev.c
+++ b/sound/soc/sof/sof-acpi-dev.c
@@ -74,18 +74,10 @@ int sof_acpi_probe(struct platform_device *pdev, const struct sof_dev_desc *desc
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
- sof_pdata->fw_filename = desc->default_fw_filename[SOF_IPC_TYPE_3];
-
- /* alternate fw and tplg filenames ? */
- if (fw_path)
- sof_pdata->fw_filename_prefix = fw_path;
- else
- sof_pdata->fw_filename_prefix = desc->default_fw_path[SOF_IPC_TYPE_3];
-
- if (tplg_path)
- sof_pdata->tplg_filename_prefix = tplg_path;
- else
- sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3];
+
+ sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default;
+ sof_pdata->ipc_file_profile_base.fw_path = fw_path;
+ sof_pdata->ipc_file_profile_base.tplg_path = tplg_path;
/* set callback to be called on successful device probe to enable runtime_pm */
sof_pdata->sof_probe_complete = sof_acpi_probe_complete;
diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c
index 77cc64ac7113..9163975c9c3f 100644
--- a/sound/soc/sof/sof-audio.c
+++ b/sound/soc/sof/sof-audio.c
@@ -11,7 +11,6 @@
#include <linux/bitfield.h>
#include <trace/events/sof.h>
#include "sof-audio.h"
-#include "sof-of-dev.h"
#include "ops.h"
static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
@@ -1006,122 +1005,3 @@ int sof_dai_get_bclk(struct snd_soc_pcm_runtime *rtd)
return sof_dai_get_clk(rtd, SOF_DAI_CLK_INTEL_SSP_BCLK);
}
EXPORT_SYMBOL(sof_dai_get_bclk);
-
-static struct snd_sof_of_mach *sof_of_machine_select(struct snd_sof_dev *sdev)
-{
- struct snd_sof_pdata *sof_pdata = sdev->pdata;
- const struct sof_dev_desc *desc = sof_pdata->desc;
- struct snd_sof_of_mach *mach = desc->of_machines;
-
- if (!mach)
- return NULL;
-
- for (; mach->compatible; mach++) {
- if (of_machine_is_compatible(mach->compatible)) {
- sof_pdata->tplg_filename = mach->sof_tplg_filename;
- if (mach->fw_filename)
- sof_pdata->fw_filename = mach->fw_filename;
-
- return mach;
- }
- }
-
- return NULL;
-}
-
-/*
- * SOF Driver enumeration.
- */
-int sof_machine_check(struct snd_sof_dev *sdev)
-{
- struct snd_sof_pdata *sof_pdata = sdev->pdata;
- const struct sof_dev_desc *desc = sof_pdata->desc;
- struct snd_soc_acpi_mach *mach;
-
- if (!IS_ENABLED(CONFIG_SND_SOC_SOF_FORCE_NOCODEC_MODE)) {
- const struct snd_sof_of_mach *of_mach;
-
- if (IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC_DEBUG_SUPPORT) &&
- sof_debug_check_flag(SOF_DBG_FORCE_NOCODEC))
- goto nocodec;
-
- /* find machine */
- mach = snd_sof_machine_select(sdev);
- if (mach) {
- sof_pdata->machine = mach;
-
- if (sof_pdata->subsystem_id_set) {
- mach->mach_params.subsystem_vendor = sof_pdata->subsystem_vendor;
- mach->mach_params.subsystem_device = sof_pdata->subsystem_device;
- mach->mach_params.subsystem_id_set = true;
- }
-
- snd_sof_set_mach_params(mach, sdev);
- return 0;
- }
-
- of_mach = sof_of_machine_select(sdev);
- if (of_mach) {
- sof_pdata->of_machine = of_mach;
- return 0;
- }
-
- if (!IS_ENABLED(CONFIG_SND_SOC_SOF_NOCODEC)) {
- dev_err(sdev->dev, "error: no matching ASoC machine driver found - aborting probe\n");
- return -ENODEV;
- }
- } else {
- dev_warn(sdev->dev, "Force to use nocodec mode\n");
- }
-
-nocodec:
- /* select nocodec mode */
- dev_warn(sdev->dev, "Using nocodec machine driver\n");
- mach = devm_kzalloc(sdev->dev, sizeof(*mach), GFP_KERNEL);
- if (!mach)
- return -ENOMEM;
-
- mach->drv_name = "sof-nocodec";
- if (!sof_pdata->tplg_filename)
- sof_pdata->tplg_filename = desc->nocodec_tplg_filename;
-
- sof_pdata->machine = mach;
- snd_sof_set_mach_params(mach, sdev);
-
- return 0;
-}
-EXPORT_SYMBOL(sof_machine_check);
-
-int sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
-{
- struct snd_sof_pdata *plat_data = pdata;
- const char *drv_name;
- const void *mach;
- int size;
-
- drv_name = plat_data->machine->drv_name;
- mach = plat_data->machine;
- size = sizeof(*plat_data->machine);
-
- /* register machine driver, pass machine info as pdata */
- plat_data->pdev_mach =
- platform_device_register_data(sdev->dev, drv_name,
- PLATFORM_DEVID_NONE, mach, size);
- if (IS_ERR(plat_data->pdev_mach))
- return PTR_ERR(plat_data->pdev_mach);
-
- dev_dbg(sdev->dev, "created machine %s\n",
- dev_name(&plat_data->pdev_mach->dev));
-
- return 0;
-}
-EXPORT_SYMBOL(sof_machine_register);
-
-void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata)
-{
- struct snd_sof_pdata *plat_data = pdata;
-
- if (!IS_ERR_OR_NULL(plat_data->pdev_mach))
- platform_device_unregister(plat_data->pdev_mach);
-}
-EXPORT_SYMBOL(sof_machine_unregister);
diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h
index a6d6bcd00cee..8874ee5f557f 100644
--- a/sound/soc/sof/sof-audio.h
+++ b/sound/soc/sof/sof-audio.h
@@ -275,6 +275,7 @@ enum sof_tokens {
SOF_GAIN_TOKENS,
SOF_ACPDMIC_TOKENS,
SOF_ACPI2S_TOKENS,
+ SOF_MICFIL_TOKENS,
/* this should be the last */
SOF_TOKEN_COUNT,
diff --git a/sound/soc/sof/sof-client-probes.c b/sound/soc/sof/sof-client-probes.c
index 7cc9e8f18de7..30f771ac7bbf 100644
--- a/sound/soc/sof/sof-client-probes.c
+++ b/sound/soc/sof/sof-client-probes.c
@@ -381,8 +381,6 @@ static const struct snd_soc_component_driver sof_probes_component = {
.legacy_dai_naming = 1,
};
-SND_SOC_DAILINK_DEF(dummy, DAILINK_COMP_ARRAY(COMP_DUMMY()));
-
static int sof_probes_client_probe(struct auxiliary_device *auxdev,
const struct auxiliary_device_id *id)
{
@@ -475,7 +473,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
links[0].cpus = &cpus[0];
links[0].num_cpus = 1;
links[0].cpus->dai_name = "Probe Extraction CPU DAI";
- links[0].codecs = dummy;
+ links[0].codecs = &snd_soc_dummy_dlc;
links[0].num_codecs = 1;
links[0].platforms = platform_component;
links[0].num_platforms = ARRAY_SIZE(platform_component);
diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c
index c6be8a91e74b..b9a499e92b9a 100644
--- a/sound/soc/sof/sof-of-dev.c
+++ b/sound/soc/sof/sof-of-dev.c
@@ -64,17 +64,10 @@ int sof_of_probe(struct platform_device *pdev)
sof_pdata->desc = desc;
sof_pdata->dev = &pdev->dev;
- sof_pdata->fw_filename = desc->default_fw_filename[SOF_IPC_TYPE_3];
- if (fw_path)
- sof_pdata->fw_filename_prefix = fw_path;
- else
- sof_pdata->fw_filename_prefix = desc->default_fw_path[SOF_IPC_TYPE_3];
-
- if (tplg_path)
- sof_pdata->tplg_filename_prefix = tplg_path;
- else
- sof_pdata->tplg_filename_prefix = desc->default_tplg_path[SOF_IPC_TYPE_3];
+ sof_pdata->ipc_file_profile_base.ipc_type = desc->ipc_default;
+ sof_pdata->ipc_file_profile_base.fw_path = fw_path;
+ sof_pdata->ipc_file_profile_base.tplg_path = tplg_path;
/* set callback to be called on successful device probe to enable runtime_pm */
sof_pdata->sof_probe_complete = sof_of_probe_complete;
diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c
index 64b326e3ef85..aab5c900cecf 100644
--- a/sound/soc/sof/sof-pci-dev.c
+++ b/sound/soc/sof/sof-pci-dev.c
@@ -190,6 +190,7 @@ static void sof_pci_probe_complete(struct device *dev)
int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
{
+ struct sof_loadable_file_profile *path_override;
struct device *dev = &pci->dev;
const struct sof_dev_desc *desc =
(const struct sof_dev_desc *)pci_id->driver_data;
@@ -232,106 +233,39 @@ int sof_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
sof_pdata->desc = desc;
sof_pdata->dev = dev;
- sof_pdata->ipc_type = desc->ipc_default;
+ path_override = &sof_pdata->ipc_file_profile_base;
if (sof_pci_ipc_type < 0) {
- sof_pdata->ipc_type = desc->ipc_default;
+ path_override->ipc_type = desc->ipc_default;
+ } else if (sof_pci_ipc_type < SOF_IPC_TYPE_COUNT) {
+ path_override->ipc_type = sof_pci_ipc_type;
} else {
- dev_info(dev, "overriding default IPC %d to requested %d\n",
- desc->ipc_default, sof_pci_ipc_type);
- if (sof_pci_ipc_type >= SOF_IPC_TYPE_COUNT) {
- dev_err(dev, "invalid request value %d\n", sof_pci_ipc_type);
- ret = -EINVAL;
- goto out;
- }
- if (!(BIT(sof_pci_ipc_type) & desc->ipc_supported_mask)) {
- dev_err(dev, "invalid request value %d, supported mask is %#x\n",
- sof_pci_ipc_type, desc->ipc_supported_mask);
- ret = -EINVAL;
- goto out;
- }
- sof_pdata->ipc_type = sof_pci_ipc_type;
+ dev_err(dev, "Invalid IPC type requested: %d\n", sof_pci_ipc_type);
+ ret = -EINVAL;
+ goto out;
}
- if (fw_filename) {
- sof_pdata->fw_filename = fw_filename;
+ path_override->fw_path = fw_path;
+ path_override->fw_name = fw_filename;
+ path_override->fw_lib_path = lib_path;
+ path_override->tplg_path = tplg_path;
- dev_dbg(dev, "Module parameter used, changed fw filename to %s\n",
- sof_pdata->fw_filename);
- } else {
- sof_pdata->fw_filename = desc->default_fw_filename[sof_pdata->ipc_type];
+ if (dmi_check_system(community_key_platforms) &&
+ sof_dmi_use_community_key) {
+ path_override->fw_path_postfix = "community";
+ path_override->fw_lib_path_postfix = "community";
}
/*
- * for platforms using the SOF community key, change the
- * default path automatically to pick the right files from the
- * linux-firmware tree. This can be overridden with the
- * fw_path kernel parameter, e.g. for developers.
- */
-
- /* alternate fw and tplg filenames ? */
- if (fw_path) {
- sof_pdata->fw_filename_prefix = fw_path;
-
- dev_dbg(dev,
- "Module parameter used, changed fw path to %s\n",
- sof_pdata->fw_filename_prefix);
-
- } else if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
- sof_pdata->fw_filename_prefix =
- devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
- sof_pdata->desc->default_fw_path[sof_pdata->ipc_type],
- "community");
-
- dev_dbg(dev,
- "Platform uses community key, changed fw path to %s\n",
- sof_pdata->fw_filename_prefix);
- } else {
- sof_pdata->fw_filename_prefix =
- sof_pdata->desc->default_fw_path[sof_pdata->ipc_type];
- }
-
- if (lib_path) {
- sof_pdata->fw_lib_prefix = lib_path;
-
- dev_dbg(dev, "Module parameter used, changed fw_lib path to %s\n",
- sof_pdata->fw_lib_prefix);
-
- } else if (sof_pdata->desc->default_lib_path[sof_pdata->ipc_type]) {
- if (dmi_check_system(community_key_platforms) && sof_dmi_use_community_key) {
- sof_pdata->fw_lib_prefix =
- devm_kasprintf(dev, GFP_KERNEL, "%s/%s",
- sof_pdata->desc->default_lib_path[sof_pdata->ipc_type],
- "community");
-
- dev_dbg(dev,
- "Platform uses community key, changed fw_lib path to %s\n",
- sof_pdata->fw_lib_prefix);
- } else {
- sof_pdata->fw_lib_prefix =
- sof_pdata->desc->default_lib_path[sof_pdata->ipc_type];
- }
- }
-
- if (tplg_path)
- sof_pdata->tplg_filename_prefix = tplg_path;
- else
- sof_pdata->tplg_filename_prefix =
- sof_pdata->desc->default_tplg_path[sof_pdata->ipc_type];
-
- /*
* the topology filename will be provided in the machine descriptor, unless
* it is overridden by a module parameter or DMI quirk.
*/
if (tplg_filename) {
- sof_pdata->tplg_filename = tplg_filename;
-
- dev_dbg(dev, "Module parameter used, changed tplg filename to %s\n",
- sof_pdata->tplg_filename);
+ path_override->tplg_name = tplg_filename;
} else {
dmi_check_system(sof_tplg_table);
if (sof_dmi_override_tplg_name)
- sof_pdata->tplg_filename = sof_dmi_override_tplg_name;
+ path_override->tplg_name = sof_dmi_override_tplg_name;
}
/* set callback to be called on successful device probe to enable runtime_pm */
diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h
index f4185012eb69..6d7897bf9607 100644
--- a/sound/soc/sof/sof-priv.h
+++ b/sound/soc/sof/sof-priv.h
@@ -696,6 +696,13 @@ void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
extern struct snd_compress_ops sof_compressed_ops;
/*
+ * Firmware (firmware, libraries, topologies) file location
+ */
+int sof_create_ipc_file_profile(struct snd_sof_dev *sdev,
+ struct sof_loadable_file_profile *base_profile,
+ struct sof_loadable_file_profile *out_profile);
+
+/*
* Firmware loading.
*/
int snd_sof_load_firmware_raw(struct snd_sof_dev *sdev);
@@ -814,8 +821,6 @@ int sof_stream_pcm_open(struct snd_sof_dev *sdev,
int sof_stream_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream);
-int sof_machine_check(struct snd_sof_dev *sdev);
-
/* SOF client support */
#if IS_ENABLED(CONFIG_SND_SOC_SOF_CLIENT)
int sof_client_dev_register(struct snd_sof_dev *sdev, const char *name, u32 id,
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index 37ec671a2d76..617a225fff24 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -289,13 +289,14 @@ static const struct sof_dai_types sof_dais[] = {
{"ALH", SOF_DAI_INTEL_ALH},
{"SAI", SOF_DAI_IMX_SAI},
{"ESAI", SOF_DAI_IMX_ESAI},
- {"ACP", SOF_DAI_AMD_BT},
+ {"ACPBT", SOF_DAI_AMD_BT},
{"ACPSP", SOF_DAI_AMD_SP},
{"ACPDMIC", SOF_DAI_AMD_DMIC},
{"ACPHS", SOF_DAI_AMD_HS},
{"AFE", SOF_DAI_MEDIATEK_AFE},
{"ACPSP_VIRTUAL", SOF_DAI_AMD_SP_VIRTUAL},
{"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL},
+ {"MICFIL", SOF_DAI_IMX_MICFIL},
};
@@ -1134,7 +1135,7 @@ static void sof_disconnect_dai_widget(struct snd_soc_component *scomp,
list_for_each_entry(rtd, &card->rtd_list, list) {
/* does stream match DAI link ? */
if (!rtd->dai_link->stream_name ||
- strcmp(sname, rtd->dai_link->stream_name))
+ !strstr(rtd->dai_link->stream_name, sname))
continue;
for_each_rtd_cpu_dais(rtd, i, cpu_dai)
@@ -1955,6 +1956,7 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
token_id = SOF_ACPDMIC_TOKENS;
num_tuples += token_list[SOF_ACPDMIC_TOKENS].count;
break;
+ case SOF_DAI_AMD_BT:
case SOF_DAI_AMD_SP:
case SOF_DAI_AMD_HS:
case SOF_DAI_AMD_SP_VIRTUAL:
@@ -1962,6 +1964,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_
token_id = SOF_ACPI2S_TOKENS;
num_tuples += token_list[SOF_ACPI2S_TOKENS].count;
break;
+ case SOF_DAI_IMX_MICFIL:
+ token_id = SOF_MICFIL_TOKENS;
+ num_tuples += token_list[SOF_MICFIL_TOKENS].count;
+ break;
default:
break;
}