diff --git a/include/sound/sof/dai.h b/include/sound/sof/dai.h index 36809f7127236..60a0603a39b30 100644 --- a/include/sound/sof/dai.h +++ b/include/sound/sof/dai.h @@ -90,8 +90,30 @@ enum sof_ipc_dai_type { SOF_DAI_AMD_HS_VIRTUAL, /**< AMD ACP HS VIRTUAL */ SOF_DAI_IMX_MICFIL, /** < i.MX MICFIL PDM */ SOF_DAI_AMD_SDW, /**< AMD ACP SDW */ + SOF_DAI_VIRTUAL, /**< Virtual DAI for testing/debugging */ }; +/* VIRTUAL DAI Configuration Request - SOF_IPC_DAI_VIRTUAL_CONFIG */ +struct sof_ipc_dai_virtual_params { + struct sof_ipc_hdr hdr; + + /* MCLK */ + uint16_t reserved1; + uint16_t mclk_id; + uint32_t mclk_direction; + + uint32_t mclk_rate; /* MCLK frequency in Hz */ + uint32_t fsync_rate; /* FSYNC frequency in Hz */ + uint32_t bclk_rate; /* BCLK frequency in Hz */ + + /* TDM */ + uint32_t tdm_slots; + uint32_t rx_slots; + uint32_t tx_slots; + uint16_t tdm_slot_width; + uint16_t reserved2; /* alignment */ +} __packed; + /* general purpose DAI configuration */ struct sof_ipc_dai_config { struct sof_ipc_cmd_hdr hdr; @@ -121,6 +143,7 @@ struct sof_ipc_dai_config { struct sof_ipc_dai_mtk_afe_params afe; struct sof_ipc_dai_micfil_params micfil; struct sof_ipc_dai_acp_sdw_params acp_sdw; + struct sof_ipc_dai_virtual_params virtual_dai; }; } __packed; diff --git a/include/uapi/sound/sof/tokens.h b/include/uapi/sound/sof/tokens.h index 0a246bc218d32..4aa5ae606cad9 100644 --- a/include/uapi/sound/sof/tokens.h +++ b/include/uapi/sound/sof/tokens.h @@ -222,4 +222,7 @@ #define SOF_TKN_AMD_ACP_SDW_RATE 2100 #define SOF_TKN_AMD_ACP_SDW_CH 2101 +/* VIRTUAL DAI */ +#define SOF_TKN_DAI_VIRTUAL_MCLK_ID 2102 + #endif diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c index f4fed8c2189fd..248de4ac0489f 100644 --- a/sound/soc/sof/imx/imx8m.c +++ b/sound/soc/sof/imx/imx8m.c @@ -283,6 +283,13 @@ static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type) } static struct snd_soc_dai_driver imx8m_dai[] = { +{ + .name = "virtual_dai", + .playback = { + .channels_min = 1, + .channels_max = 32, + }, +}, { .name = "sai1", .playback = { diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 1c1b8f5953674..2da3f30eacbc6 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -420,6 +420,16 @@ static int sof_ipc3_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, dev_dbg(component->dev, "AMD_SDW channels_min: %d channels_max: %d\n", channels->min, channels->max); break; + case SOF_DAI_VIRTUAL: + rate->min = private->dai_config->virtual_dai.fsync_rate; + rate->max = private->dai_config->virtual_dai.fsync_rate; + channels->min = private->dai_config->virtual_dai.tdm_slots; + channels->max = private->dai_config->virtual_dai.tdm_slots; + + dev_dbg(component->dev, "rate_min: %d rate_max: %d\n", rate->min, rate->max); + dev_dbg(component->dev, "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 e98b53b67d12b..d931a1e1ec73c 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -230,6 +230,12 @@ static const struct sof_topology_token sai_tokens[] = { offsetof(struct sof_ipc_dai_sai_params, mclk_id)}, }; +/* DAI VIRTUAL */ +static const struct sof_topology_token dai_virtual_tokens[] = { + {SOF_TKN_DAI_VIRTUAL_MCLK_ID, SND_SOC_TPLG_TUPLE_TYPE_SHORT, get_token_u16, + offsetof(struct sof_ipc_dai_virtual_params, mclk_id)}, +}; + /* * DMIC PDM Tokens * SOF_TKN_INTEL_DMIC_PDM_CTRL_ID should be the first token @@ -348,6 +354,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = { [SOF_MICFIL_TOKENS] = {"MICFIL PDM tokens", micfil_pdm_tokens, ARRAY_SIZE(micfil_pdm_tokens)}, [SOF_ACP_SDW_TOKENS] = {"ACP_SDW tokens", acp_sdw_tokens, ARRAY_SIZE(acp_sdw_tokens)}, + [SOF_DAI_VIRTUAL_TOKENS] = {"DAI VIRTUAL tokens", dai_virtual_tokens, ARRAY_SIZE(dai_virtual_tokens)}, }; /** @@ -1164,6 +1171,39 @@ static int sof_link_esai_load(struct snd_soc_component *scomp, struct snd_sof_da return 0; } +static int sof_link_virtual_dai_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; + + /* init IPC */ + memset(&config->virtual_dai, 0, sizeof(config->virtual_dai)); + config->hdr.size = size; + + /* set format */ + sof_dai_set_format(hw_config, config); + + ret = sof_update_ipc_object(scomp, &config->virtual_dai, SOF_DAI_VIRTUAL_TOKENS, + slink->tuples, slink->num_tuples, size, 1); + if (ret < 0) + return ret; + + dev_info(scomp->dev, + "tplg: config VIRTUAL_DAI%d fmt 0x%x\n", + config->dai_index, config->format); + + 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_micfil_load(struct snd_soc_component *scomp, struct snd_sof_dai_link *slink, struct sof_ipc_dai_config *config, struct snd_sof_dai *dai) { @@ -1661,6 +1701,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_VIRTUAL: + ret = sof_link_virtual_dai_load(scomp, slink, config, dai); + break; case SOF_DAI_IMX_MICFIL: ret = sof_link_micfil_load(scomp, slink, config, dai); break; diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 01b819dd84984..986418b093047 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -287,6 +287,7 @@ enum sof_tokens { SOF_ACPI2S_TOKENS, SOF_MICFIL_TOKENS, SOF_ACP_SDW_TOKENS, + SOF_DAI_VIRTUAL_TOKENS, /* this should be the last */ SOF_TOKEN_COUNT, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index b3fca5fd87d68..c587afa326628 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -298,6 +298,7 @@ static const struct sof_dai_types sof_dais[] = { {"ACPHS_VIRTUAL", SOF_DAI_AMD_HS_VIRTUAL}, {"MICFIL", SOF_DAI_IMX_MICFIL}, {"ACP_SDW", SOF_DAI_AMD_SDW}, + {"DAI_VIRTUAL", SOF_DAI_VIRTUAL}, }; @@ -1948,6 +1949,10 @@ static int sof_link_load(struct snd_soc_component *scomp, int index, struct snd_ token_id = SOF_ESAI_TOKENS; num_tuples += token_list[SOF_ESAI_TOKENS].count; break; + case SOF_DAI_VIRTUAL: + token_id = SOF_DAI_VIRTUAL_TOKENS; + num_tuples += token_list[SOF_DAI_VIRTUAL_TOKENS].count; + break; case SOF_DAI_MEDIATEK_AFE: token_id = SOF_AFE_TOKENS; num_tuples += token_list[SOF_AFE_TOKENS].count;