diff --git a/include/sound/sof/ext_manifest4.h b/include/sound/sof/ext_manifest4.h index ec97edcbbfc394..cd1cef9d78e2ea 100644 --- a/include/sound/sof/ext_manifest4.h +++ b/include/sound/sof/ext_manifest4.h @@ -90,6 +90,21 @@ struct sof_man4_segment_desc { uint32_t file_offset; } __packed; +/* + * bit definition for type in sof_man4_module + * uint32_t load_type : 4; MT_BUILTIN, MT_LOADABLE + * uint32_t auto_start : 1; 0 - manually created, 1 - single instance created by Module Manager + * uint32_t domain_ll : 1; support LL domain + * uint32_t domain_dp : 1; support DP domain + * uint32_t lib_code : 1; determines if module is place holder for common library code + * uint32_t _rsvd : 24; + */ +#define SOF_IPC4_MODULE_LOAD_TYPE(x) ((x) & 0xf) +#define SOF_IPC4_MODULE_AUTO_START(x) (((x) >> 4) & 0x1) +#define SOF_IPC4_MODULE_DOMAIN_LL(x) (((x) >> 5) & 0x1) +#define SOF_IPC4_MODULE_DOMAIN_DP(x) (((x) >> 6) & 0x1) +#define SOF_IPC4_MODULE_LIB_CODE(x) (((x) >> 7) & 0x1) + struct sof_man4_module { uint32_t id; uint8_t name[MAX_MODULE_NAME_LEN]; diff --git a/sound/soc/sof/intel/tgl.c b/sound/soc/sof/intel/tgl.c index 0173e5b255daa0..af6a8ba5abf0f0 100644 --- a/sound/soc/sof/intel/tgl.c +++ b/sound/soc/sof/intel/tgl.c @@ -9,6 +9,7 @@ * Hardware interface for audio DSP on Tigerlake. */ +#include #include #include "../ipc4-priv.h" #include "../ops.h" @@ -50,6 +51,40 @@ static int tgl_dsp_core_put(struct snd_sof_dev *sdev, int core) return 0; } +static int tgl_dsp_ipc4_core_get(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc4_msg msg; + struct sof_ipc4_dx_info dx_info; + + dx_info.core_mask = BIT(core); + dx_info.dx_mask = BIT(core); + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.data_ptr = &dx_info; + msg.data_size = sizeof(dx_info); + + /* now send the iPC */ + return sof_ipc_tx_message(sdev->ipc, &msg, sizeof(dx_info), NULL, 0); +} + +static int tgl_dsp_ipc4_core_put(struct snd_sof_dev *sdev, int core) +{ + struct sof_ipc4_msg msg; + struct sof_ipc4_dx_info dx_info; + + dx_info.core_mask = BIT(core); + dx_info.dx_mask = ~BIT(core); + msg.primary = SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_MOD_SET_DX); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.data_ptr = &dx_info; + msg.data_size = sizeof(dx_info); + + /* now send the iPC */ + return sof_ipc_tx_message(sdev->ipc, &msg, sizeof(dx_info), NULL, 0); +} + /* Tigerlake ops */ struct snd_sof_dsp_ops sof_tgl_ops; EXPORT_SYMBOL_NS(sof_tgl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); @@ -68,6 +103,10 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_tgl_ops.send_msg = cnl_ipc_send_msg; + + /* dsp core get/put */ + sof_tgl_ops.core_get = tgl_dsp_core_get; + sof_tgl_ops.core_put = tgl_dsp_core_put; } if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) { @@ -85,6 +124,10 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* ipc */ sof_tgl_ops.send_msg = cnl_ipc4_send_msg; + + /* dsp core get/put */ + sof_tgl_ops.core_get = tgl_dsp_ipc4_core_get; + sof_tgl_ops.core_put = tgl_dsp_ipc4_core_put; } /* set DAI driver ops */ @@ -101,10 +144,6 @@ int sof_tgl_ops_init(struct snd_sof_dev *sdev) /* firmware run */ sof_tgl_ops.run = hda_dsp_cl_boot_firmware_iccmax; - /* dsp core get/put */ - sof_tgl_ops.core_get = tgl_dsp_core_get; - sof_tgl_ops.core_put = tgl_dsp_core_put; - return 0; }; EXPORT_SYMBOL_NS(sof_tgl_ops_init, SND_SOC_SOF_INTEL_HDA_COMMON); diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 6a702f9dc065bd..732872395980ae 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -179,6 +179,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); + struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct sof_ipc4_copier *ipc4_copier; @@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, snd_mask_none(fmt); snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); + rate->min = ipc4_copier->available_fmt.base_config->audio_fmt.sampling_frequency; + rate->max = rate->min; + /* * Set trigger order for capture to SND_SOC_DPCM_TRIGGER_PRE. This is required * to ensure that the BE DAI pipeline gets stopped/suspended before the FE DAI diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index 9492fe1796c2f1..c28e0f57b16cdd 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -48,4 +48,14 @@ extern const struct sof_ipc_pcm_ops ipc4_pcm_ops; int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state); +/** + * struct sof_ipc4_dx_info: ipc4 core/Dx mask data + * @core_mask: core mask + * @dx_mask: Dx mask + */ +struct sof_ipc4_dx_info { + u32 core_mask; + u32 dx_mask; +}; + #endif diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 34f805431f2eb3..16fa9b35c7ce13 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -111,6 +111,17 @@ static const struct sof_topology_token gain_tokens[] = { get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, }; +/* SRC */ +static const struct sof_topology_token src_tokens[] = { + {SOF_TKN_SRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, + offsetof(struct sof_ipc4_src, sink_rate)}, +}; + +/* Core tokens */ +static const struct sof_topology_token ipc4_core_tokens[] = { + {SOF_TKN_COMP_CORE_ID, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32, 0}, +}; + static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, [SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_tokens)}, @@ -134,6 +145,8 @@ static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = { [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens", ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_tokens)}, [SOF_GAIN_TOKENS] = {"Gain tokens", gain_tokens, ARRAY_SIZE(gain_tokens)}, + [SOF_SRC_TOKENS] = {"SRC tokens", src_tokens, ARRAY_SIZE(src_tokens)}, + [SOF_CORE_TOKENS] = {"Core tokens", ipc4_core_tokens, ARRAY_SIZE(ipc4_core_tokens)}, }; static void sof_ipc4_dbg_audio_format(struct device *dev, @@ -297,6 +310,7 @@ static int sof_ipc4_widget_set_module_info(struct snd_sof_widget *swidget) static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg) { struct sof_ipc4_fw_module *fw_module; + uint32_t type; int ret; ret = sof_ipc4_widget_set_module_info(swidget); @@ -312,6 +326,8 @@ static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ msg->extension = SOF_IPC4_MOD_EXT_PPL_ID(swidget->pipeline_id); msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); + type = fw_module->man4_module_entry.type; + msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(SOF_IPC4_MODULE_DOMAIN_DP(type)); return 0; } @@ -701,6 +717,44 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) return ret; } +static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct sof_ipc4_src *src; + int ret; + + dev_dbg(scomp->dev, "Updating IPC structure for %s\n", swidget->widget->name); + + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + swidget->private = src; + + /* The out_audio_fmt in topology is ignored as it is not required to be sent to the FW */ + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &src->available_fmt, false); + if (ret) + goto err; + + ret = sof_update_ipc_object(scomp, src, SOF_SRC_TOKENS, swidget->tuples, + swidget->num_tuples, sizeof(src), 1); + if (ret) { + dev_err(scomp->dev, "Parsing gain tokens failed\n"); + goto err; + } + + dev_dbg(scomp->dev, "Src output rate %d\n", src->sink_rate); + + ret = sof_ipc4_widget_setup_msg(swidget, &src->msg); + if (ret) + goto err; + + return 0; +err: + kfree(src); + return ret; +} + static void sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, struct sof_ipc4_base_module_cfg *base_config) @@ -802,10 +856,15 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, rate = fmt->sampling_frequency; channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); - if (params_rate(params) == rate && params_channels(params) == channels && - sample_valid_bits == valid_bits) { - dev_dbg(sdev->dev, "matching audio format index for %uHz, %ubit, %u channels: %d\n", - rate, valid_bits, channels, i); + + /* + * use SNDRV_PCM_RATE_8000_192000 to avoid + * dozens of format setting in tplg for SRC case + */ + if ((params_rate(params) == rate || rate == SNDRV_PCM_RATE_8000_192000) && + params_channels(params) == channels && sample_valid_bits == valid_bits) { + dev_dbg(sdev->dev, "%s: matching audio format index for %uHz, %ubit, %u channels: %d\n", + __func__, rate, valid_bits, channels, i); /* copy ibs/obs and input format */ memcpy(base_config, &available_fmt->base_config[i], @@ -815,6 +874,26 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, if (out_format) memcpy(out_format, &available_fmt->out_audio_fmt[i], sizeof(struct sof_ipc4_audio_format)); + + /* calculate ibs & obs in driver for range of rate support */ + if (rate == SNDRV_PCM_RATE_8000_192000) { + base_config->audio_fmt.sampling_frequency = params_rate(params); + /* + * add 999 to get correct buffer size for some rates + * like 11.025khz, 22.05khz, 44.1khz + */ + base_config->ibs = ((params_rate(params) + 999) / 1000) * channels * + (base_config->audio_fmt.bit_depth >> 2); + + if (out_format) { + out_format->sampling_frequency = params_rate(params); + base_config->obs = ((params_rate(params) + 999) / 1000) * + channels * (out_format->bit_depth >> 2); + } else { + base_config->obs = base_config->ibs; + } + } + break; } } @@ -1177,7 +1256,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, } /* set the gateway dma_buffer_size using the matched ID returned above */ - copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; + if (available_fmt->base_config[ret].audio_fmt.sampling_frequency == + SNDRV_PCM_RATE_8000_192000) + copier_data->gtw_cfg.dma_buffer_size = copier_data->base_config.obs; + else + copier_data->gtw_cfg.dma_buffer_size = available_fmt->dma_buffer_size[ret]; data = &ipc4_copier->copier_config; ipc_config_size = &ipc4_copier->ipc_config_size; @@ -1267,6 +1350,41 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, return sof_ipc4_widget_assign_instance_id(sdev, swidget); } +static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, + struct snd_pcm_hw_params *fe_params, + struct snd_sof_platform_stream_params *platform_params, + struct snd_pcm_hw_params *pipeline_params, int dir) +{ + struct snd_soc_component *scomp = swidget->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + struct sof_ipc4_src *src = swidget->private; + struct snd_interval *rate; + int ret; + + src->available_fmt.ref_audio_fmt = &src->available_fmt.base_config->audio_fmt; + + /* output format is not required to be sent to the FW for src */ + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &src->base_config, + NULL, pipeline_params, &src->available_fmt, + sizeof(src->base_config)); + if (ret < 0) + return ret; + + /* update pipeline memory usage */ + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &src->base_config); + + /* update pipeline_params for sink widgets */ + rate = hw_param_interval(pipeline_params, SNDRV_PCM_HW_PARAM_RATE); + rate->min = src->sink_rate; + rate->max = rate->max; + /* src needs extra 4 sample size */ + src->base_config.obs = ((src->sink_rate + 999) / 1000 + 4) * params_channels(fe_params) * + (src->base_config.audio_fmt.bit_depth >> 2); + + /* assign instance ID */ + return sof_ipc4_widget_assign_instance_id(sdev, swidget); +} + static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) { struct sof_ipc4_control_data *control_data; @@ -1379,6 +1497,16 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg = &mixer->msg; break; } + case snd_soc_dapm_src: + { + struct sof_ipc4_src *src = swidget->private; + + ipc_size = sizeof(struct sof_ipc4_base_module_cfg) + sizeof(src->sink_rate); + ipc_data = src; + + msg = &src->msg; + break; + } default: dev_err(sdev->dev, "widget type %d not supported", swidget->id); return -EINVAL; @@ -1391,8 +1519,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; msg->extension |= ipc_size >> 2; - msg->extension &= ~SOF_IPC4_MOD_EXT_DOMAIN_MASK; - msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(pipeline->lp_mode); } msg->data_size = ipc_size; @@ -1679,6 +1805,7 @@ static enum sof_tokens host_token_list[] = { SOF_COPIER_GATEWAY_CFG_TOKENS, SOF_COPIER_TOKENS, SOF_COMP_EXT_TOKENS, + SOF_CORE_TOKENS, }; static enum sof_tokens pipeline_token_list[] = { @@ -1696,6 +1823,7 @@ static enum sof_tokens dai_token_list[] = { SOF_COPIER_TOKENS, SOF_DAI_TOKENS, SOF_COMP_EXT_TOKENS, + SOF_CORE_TOKENS, }; static enum sof_tokens pga_token_list[] = { @@ -1705,6 +1833,7 @@ static enum sof_tokens pga_token_list[] = { SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, SOF_IN_AUDIO_FORMAT_TOKENS, SOF_COMP_EXT_TOKENS, + SOF_CORE_TOKENS, }; static enum sof_tokens mixer_token_list[] = { @@ -1715,6 +1844,16 @@ static enum sof_tokens mixer_token_list[] = { SOF_COMP_EXT_TOKENS, }; +static enum sof_tokens src_token_list[] = { + SOF_COMP_TOKENS, + SOF_SRC_TOKENS, + SOF_AUDIO_FMT_NUM_TOKENS, + SOF_IN_AUDIO_FORMAT_TOKENS, + SOF_AUDIO_FORMAT_BUFFER_SIZE_TOKENS, + SOF_COMP_EXT_TOKENS, + SOF_CORE_TOKENS, +}; + static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, host_token_list, ARRAY_SIZE(host_token_list), NULL, @@ -1743,6 +1882,10 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY mixer_token_list, ARRAY_SIZE(mixer_token_list), NULL, sof_ipc4_prepare_mixer_module, sof_ipc4_unprepare_generic_module}, + [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp, + src_token_list, ARRAY_SIZE(src_token_list), NULL, + sof_ipc4_prepare_src_module, + sof_ipc4_unprepare_generic_module}, }; const struct sof_ipc_tplg_ops ipc4_tplg_ops = { diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index 3bc2fe38c7333a..bbc835cdf64c3d 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -242,4 +242,10 @@ struct sof_ipc4_mixer { struct sof_ipc4_msg msg; }; +struct sof_ipc4_src { + struct sof_ipc4_base_module_cfg base_config; + uint32_t sink_rate; + struct sof_ipc4_available_audio_format available_fmt; + struct sof_ipc4_msg msg; +}; #endif