ASoC: SOF: topology: Add support for AMD ACP DAIs
authorAjit Kumar Pandey <AjitKumar.Pandey@amd.com>
Wed, 17 Nov 2021 09:37:24 +0000 (11:37 +0200)
committerMark Brown <broonie@kernel.org>
Wed, 17 Nov 2021 17:35:54 +0000 (17:35 +0000)
Add new sof dais and config to pass topology file configuration
to SOF firmware running on ACP's DSP core. ACP firmware support
I2S_BT, I2S_SP and DMIC controller hence add three new dais to
the list of supported sof_dais

Signed-off-by: Ajit Kumar Pandey <AjitKumar.Pandey@amd.com>
Reviewed-by: Bard Liao <bard.liao@intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
Link: https://lore.kernel.org/r/20211117093734.17407-12-daniel.baluta@oss.nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sof/dai-amd.h [new file with mode: 0644]
include/sound/sof/dai.h
sound/soc/sof/pcm.c
sound/soc/sof/topology.c

diff --git a/include/sound/sof/dai-amd.h b/include/sound/sof/dai-amd.h
new file mode 100644 (file)
index 0000000..90d09db
--- /dev/null
@@ -0,0 +1,21 @@
+/* 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) 2021 Advanced Micro Devices, Inc.. All rights reserved.
+ */
+
+#ifndef __INCLUDE_SOUND_SOF_DAI_AMD_H__
+#define __INCLUDE_SOUND_SOF_DAI_AMD_H__
+
+#include <sound/sof/header.h>
+
+/* ACP Configuration Request - SOF_IPC_DAI_AMD_CONFIG */
+struct sof_ipc_dai_acp_params {
+       struct sof_ipc_hdr hdr;
+
+       uint32_t fsync_rate;    /* FSYNC frequency in Hz */
+       uint32_t tdm_slots;
+} __packed;
+#endif
index 9625f47..3782127 100644 (file)
@@ -12,6 +12,7 @@
 #include <sound/sof/header.h>
 #include <sound/sof/dai-intel.h>
 #include <sound/sof/dai-imx.h>
+#include <sound/sof/dai-amd.h>
 
 /*
  * DAI Configuration.
@@ -66,6 +67,9 @@ enum sof_ipc_dai_type {
        SOF_DAI_INTEL_ALH,              /**< Intel ALH  */
        SOF_DAI_IMX_SAI,                /**< i.MX SAI */
        SOF_DAI_IMX_ESAI,               /**< i.MX ESAI */
+       SOF_DAI_AMD_BT,                 /**< AMD ACP BT*/
+       SOF_DAI_AMD_SP,                 /**< AMD ACP SP */
+       SOF_DAI_AMD_DMIC,               /**< AMD ACP DMIC */
 };
 
 /* general purpose DAI configuration */
@@ -90,6 +94,9 @@ struct sof_ipc_dai_config {
                struct sof_ipc_dai_alh_params alh;
                struct sof_ipc_dai_esai_params esai;
                struct sof_ipc_dai_sai_params sai;
+               struct sof_ipc_dai_acp_params acpbt;
+               struct sof_ipc_dai_acp_params acpsp;
+               struct sof_ipc_dai_acp_params acpdmic;
        };
 } __packed;
 
index fa0bfcd..8d313c9 100644 (file)
@@ -826,6 +826,42 @@ int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_pa
                        "channels_min: %d channels_max: %d\n",
                        channels->min, channels->max);
                break;
+       case SOF_DAI_AMD_BT:
+               rate->min = dai->dai_config->acpbt.fsync_rate;
+               rate->max = dai->dai_config->acpbt.fsync_rate;
+               channels->min = dai->dai_config->acpbt.tdm_slots;
+               channels->max = dai->dai_config->acpbt.tdm_slots;
+
+               dev_dbg(component->dev,
+                       "AMD_BT rate_min: %d rate_max: %d\n", rate->min, rate->max);
+               dev_dbg(component->dev,
+                       "AMD_BT channels_min: %d channels_max: %d\n",
+                       channels->min, channels->max);
+               break;
+       case SOF_DAI_AMD_SP:
+               rate->min = dai->dai_config->acpsp.fsync_rate;
+               rate->max = dai->dai_config->acpsp.fsync_rate;
+               channels->min = dai->dai_config->acpsp.tdm_slots;
+               channels->max = dai->dai_config->acpsp.tdm_slots;
+
+               dev_dbg(component->dev,
+                       "AMD_SP rate_min: %d rate_max: %d\n", rate->min, rate->max);
+               dev_dbg(component->dev,
+                       "AMD_SP channels_min: %d channels_max: %d\n",
+                       channels->min, channels->max);
+               break;
+       case SOF_DAI_AMD_DMIC:
+               rate->min = dai->dai_config->acpdmic.fsync_rate;
+               rate->max = dai->dai_config->acpdmic.fsync_rate;
+               channels->min = dai->dai_config->acpdmic.tdm_slots;
+               channels->max = dai->dai_config->acpdmic.tdm_slots;
+
+               dev_dbg(component->dev,
+                       "AMD_DMIC rate_min: %d rate_max: %d\n", rate->min, rate->max);
+               dev_dbg(component->dev,
+                       "AMD_DMIC channels_min: %d channels_max: %d\n",
+                       channels->min, channels->max);
+               break;
        default:
                dev_err(component->dev, "error: invalid DAI type %d\n",
                        dai->dai_config->type);
index bb9e62b..72e671c 100644 (file)
@@ -376,6 +376,9 @@ 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},
+       {"ACPSP", SOF_DAI_AMD_SP},
+       {"ACPDMIC", SOF_DAI_AMD_DMIC},
 };
 
 static enum sof_ipc_dai_type find_dai(const char *name)
@@ -2992,6 +2995,102 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, int index,
        return ret;
 }
 
+static int sof_link_acp_dmic_load(struct snd_soc_component *scomp, int index,
+                                 struct snd_soc_dai_link *link,
+                                 struct snd_soc_tplg_link_config *cfg,
+                                 struct snd_soc_tplg_hw_config *hw_config,
+                                 struct sof_ipc_dai_config *config)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       u32 size = sizeof(*config);
+       int ret;
+
+       /* handle master/slave and inverted clocks */
+       sof_dai_set_format(hw_config, config);
+
+       /* init IPC */
+       memset(&config->acpdmic, 0, sizeof(struct sof_ipc_dai_acp_params));
+       config->hdr.size = size;
+
+       config->acpdmic.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
+       config->acpdmic.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+
+       dev_info(scomp->dev, "ACP_DMIC config ACP%d channel %d rate %d\n",
+                config->dai_index, config->acpdmic.tdm_slots,
+                config->acpdmic.fsync_rate);
+
+       /* set config for all DAI's with name matching the link name */
+       ret = sof_set_dai_config(sdev, size, link, config);
+       if (ret < 0)
+               dev_err(scomp->dev, "ACP_DMIC failed to save DAI config for ACP%d\n",
+                       config->dai_index);
+       return ret;
+}
+
+static int sof_link_acp_bt_load(struct snd_soc_component *scomp, int index,
+                               struct snd_soc_dai_link *link,
+                               struct snd_soc_tplg_link_config *cfg,
+                               struct snd_soc_tplg_hw_config *hw_config,
+                               struct sof_ipc_dai_config *config)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       u32 size = sizeof(*config);
+       int ret;
+
+       /* handle master/slave and inverted clocks */
+       sof_dai_set_format(hw_config, config);
+
+       /* init IPC */
+       memset(&config->acpbt, 0, sizeof(struct sof_ipc_dai_acp_params));
+       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);
+
+       dev_info(scomp->dev, "ACP_BT config ACP%d channel %d rate %d\n",
+                config->dai_index, config->acpbt.tdm_slots,
+                config->acpbt.fsync_rate);
+
+       /* set config for all DAI's with name matching the link name */
+       ret = sof_set_dai_config(sdev, size, link, config);
+       if (ret < 0)
+               dev_err(scomp->dev, "ACP_BT failed to save DAI config for ACP%d\n",
+                       config->dai_index);
+       return ret;
+}
+
+static int sof_link_acp_sp_load(struct snd_soc_component *scomp, int index,
+                               struct snd_soc_dai_link *link,
+                               struct snd_soc_tplg_link_config *cfg,
+                               struct snd_soc_tplg_hw_config *hw_config,
+                               struct sof_ipc_dai_config *config)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       u32 size = sizeof(*config);
+       int ret;
+
+       /* handle master/slave and inverted clocks */
+       sof_dai_set_format(hw_config, config);
+
+       /* init IPC */
+       memset(&config->acpsp, 0, sizeof(struct sof_ipc_dai_acp_params));
+       config->hdr.size = size;
+
+       config->acpsp.fsync_rate = le32_to_cpu(hw_config->fsync_rate);
+       config->acpsp.tdm_slots = le32_to_cpu(hw_config->tdm_slots);
+
+       dev_info(scomp->dev, "ACP_SP config ACP%d channel %d rate %d\n",
+                config->dai_index, config->acpsp.tdm_slots,
+                config->acpsp.fsync_rate);
+
+       /* set config for all DAI's with name matching the link name */
+       ret = sof_set_dai_config(sdev, size, link, config);
+       if (ret < 0)
+               dev_err(scomp->dev, "ACP_SP failed to save DAI config for ACP%d\n",
+                       config->dai_index);
+       return ret;
+}
+
 static int sof_link_dmic_load(struct snd_soc_component *scomp, int index,
                              struct snd_soc_dai_link *link,
                              struct snd_soc_tplg_link_config *cfg,
@@ -3277,6 +3376,16 @@ static int sof_link_load(struct snd_soc_component *scomp, int index,
        case SOF_DAI_IMX_ESAI:
                ret = sof_link_esai_load(scomp, index, link, cfg, hw_config + curr_conf, config);
                break;
+       case SOF_DAI_AMD_BT:
+               ret = sof_link_acp_bt_load(scomp, index, link, cfg, hw_config + curr_conf, config);
+               break;
+       case SOF_DAI_AMD_SP:
+               ret = sof_link_acp_sp_load(scomp, index, link, cfg, hw_config + curr_conf, config);
+               break;
+       case SOF_DAI_AMD_DMIC:
+               ret = sof_link_acp_dmic_load(scomp, index, link, cfg, hw_config + curr_conf,
+                                            config);
+               break;
        default:
                dev_err(scomp->dev, "error: invalid DAI type %d\n", common_config.type);
                ret = -EINVAL;