ASoC: SOF: Intel: updates and cleanups
Merge series from Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>: Set of updates for IPC3, IPC4, MTL support and cleanups for the topology filename override which was broken for HDaudio platforms.
This commit is contained in:
commit
16824dffcf
@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
|
||||
const char *ssp_str)
|
||||
{
|
||||
const char *tplg_filename = NULL;
|
||||
char *filename;
|
||||
char *split_ext;
|
||||
const char *split_ext;
|
||||
char *filename, *tmp;
|
||||
|
||||
filename = devm_kstrdup(sdev->dev, sof_tplg_filename, GFP_KERNEL);
|
||||
filename = kstrdup(sof_tplg_filename, GFP_KERNEL);
|
||||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
/* this assumes a .tplg extension */
|
||||
split_ext = strsep(&filename, ".");
|
||||
if (split_ext) {
|
||||
tmp = filename;
|
||||
split_ext = strsep(&tmp, ".");
|
||||
if (split_ext)
|
||||
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
|
||||
"%s-%s.tplg",
|
||||
split_ext, ssp_str);
|
||||
if (!tplg_filename)
|
||||
return NULL;
|
||||
}
|
||||
kfree(filename);
|
||||
|
||||
return tplg_filename;
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,9 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
|
||||
return cstream->runtime->private_data;
|
||||
}
|
||||
|
||||
static int hda_probes_compr_assign(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id)
|
||||
static int hda_probes_compr_startup(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id)
|
||||
{
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
struct hdac_ext_stream *hext_stream;
|
||||
@ -45,9 +45,9 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hda_probes_compr_free(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
|
||||
struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct hdac_ext_stream *hext_stream = hda_compr_get_stream(cstream);
|
||||
struct snd_sof_dev *sdev = sof_client_dev_to_sof_dev(cdev);
|
||||
@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
|
||||
|
||||
/* SOF client implementation */
|
||||
static const struct sof_probes_host_ops hda_probes_ops = {
|
||||
.assign = hda_probes_compr_assign,
|
||||
.free = hda_probes_compr_free,
|
||||
.startup = hda_probes_compr_startup,
|
||||
.shutdown = hda_probes_compr_shutdown,
|
||||
.set_params = hda_probes_compr_set_params,
|
||||
.trigger = hda_probes_compr_trigger,
|
||||
.pointer = hda_probes_compr_pointer,
|
||||
|
@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (!dmab) {
|
||||
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (hstream->posbuf)
|
||||
*hstream->posbuf = 0;
|
||||
|
||||
@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* decouple host and link DMA */
|
||||
mask = 0x1 << hstream->index;
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
mask, mask);
|
||||
|
||||
if (!dmab) {
|
||||
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* decouple host and link DMA */
|
||||
mask = 0x1 << hstream->index;
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_PP_BAR, SOF_HDA_REG_PP_PPCTL,
|
||||
mask, mask);
|
||||
|
||||
/* clear stream status */
|
||||
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
|
||||
SOF_HDA_CL_DMA_SD_INT_MASK |
|
||||
|
@ -776,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
|
||||
return tplg_filename;
|
||||
}
|
||||
|
||||
static int dmic_topology_fixup(struct snd_sof_dev *sdev,
|
||||
const char **tplg_filename,
|
||||
const char *idisp_str,
|
||||
int *dmic_found)
|
||||
static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
|
||||
const char **tplg_filename,
|
||||
const char *idisp_str,
|
||||
int *dmic_found,
|
||||
bool tplg_fixup)
|
||||
{
|
||||
const char *default_tplg_filename = *tplg_filename;
|
||||
const char *fixed_tplg_filename;
|
||||
const char *dmic_str;
|
||||
int dmic_num;
|
||||
|
||||
@ -808,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
|
||||
break;
|
||||
}
|
||||
|
||||
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
|
||||
idisp_str, dmic_str);
|
||||
if (!fixed_tplg_filename)
|
||||
return -ENOMEM;
|
||||
if (tplg_fixup) {
|
||||
const char *default_tplg_filename = *tplg_filename;
|
||||
const char *fixed_tplg_filename;
|
||||
|
||||
fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
|
||||
idisp_str, dmic_str);
|
||||
if (!fixed_tplg_filename)
|
||||
return -ENOMEM;
|
||||
*tplg_filename = fixed_tplg_filename;
|
||||
}
|
||||
|
||||
dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
|
||||
*dmic_found = dmic_num;
|
||||
*tplg_filename = fixed_tplg_filename;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1221,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
|
||||
* - one external HDAudio codec
|
||||
*/
|
||||
if (!*mach && codec_num <= 2) {
|
||||
bool tplg_fixup;
|
||||
|
||||
hda_mach = snd_soc_acpi_intel_hda_machines;
|
||||
|
||||
dev_info(bus->dev, "using HDA machine driver %s now\n",
|
||||
@ -1232,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
|
||||
idisp_str = "";
|
||||
|
||||
/* topology: use the info from hda_machines */
|
||||
tplg_filename = hda_mach->sof_tplg_filename;
|
||||
ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num);
|
||||
if (pdata->tplg_filename) {
|
||||
tplg_fixup = false;
|
||||
tplg_filename = pdata->tplg_filename;
|
||||
} else {
|
||||
tplg_fixup = true;
|
||||
tplg_filename = hda_mach->sof_tplg_filename;
|
||||
}
|
||||
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
|
||||
tplg_fixup);
|
||||
if (ret < 0)
|
||||
return;
|
||||
|
||||
@ -1397,12 +1410,19 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
}
|
||||
if (mach && mach->link_mask) {
|
||||
int dmic_num = 0;
|
||||
bool tplg_fixup;
|
||||
const char *tplg_filename;
|
||||
|
||||
mach->mach_params.links = mach->links;
|
||||
mach->mach_params.link_mask = mach->link_mask;
|
||||
mach->mach_params.platform = dev_name(sdev->dev);
|
||||
pdata->fw_filename = pdata->desc->default_fw_filename[pdata->ipc_type];
|
||||
pdata->tplg_filename = mach->sof_tplg_filename;
|
||||
|
||||
if (pdata->tplg_filename) {
|
||||
tplg_fixup = false;
|
||||
} else {
|
||||
tplg_fixup = true;
|
||||
tplg_filename = mach->sof_tplg_filename;
|
||||
}
|
||||
|
||||
/*
|
||||
* DMICs use up to 4 pins and are typically pin-muxed with SoundWire
|
||||
@ -1412,15 +1432,15 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
|
||||
* b) the NHLT table reports the presence of microphones
|
||||
*/
|
||||
if (hweight_long(mach->link_mask) <= 2) {
|
||||
const char *tplg_filename = mach->sof_tplg_filename;
|
||||
int ret;
|
||||
|
||||
ret = dmic_topology_fixup(sdev, &tplg_filename, "", &dmic_num);
|
||||
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, "",
|
||||
&dmic_num, tplg_fixup);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
|
||||
pdata->tplg_filename = tplg_filename;
|
||||
}
|
||||
if (tplg_fixup)
|
||||
pdata->tplg_filename = tplg_filename;
|
||||
mach->mach_params.dmic_num = dmic_num;
|
||||
|
||||
dev_dbg(sdev->dev,
|
||||
@ -1466,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
|
||||
mach = snd_soc_acpi_find_machine(desc->machines);
|
||||
if (mach) {
|
||||
bool add_extension = false;
|
||||
bool tplg_fixup = false;
|
||||
|
||||
/*
|
||||
* If tplg file name is overridden, use it instead of
|
||||
* the one set in mach table
|
||||
*/
|
||||
if (!sof_pdata->tplg_filename)
|
||||
if (!sof_pdata->tplg_filename) {
|
||||
sof_pdata->tplg_filename = mach->sof_tplg_filename;
|
||||
tplg_fixup = true;
|
||||
}
|
||||
|
||||
/* report to machine driver if any DMICs are found */
|
||||
mach->mach_params.dmic_num = check_dmic_num(sdev);
|
||||
|
||||
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
|
||||
if (tplg_fixup &&
|
||||
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_DMIC_NUMBER &&
|
||||
mach->mach_params.dmic_num) {
|
||||
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
|
||||
"%s%s%d%s",
|
||||
@ -1500,7 +1524,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
|
||||
/* report SSP link mask to machine driver */
|
||||
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev);
|
||||
|
||||
if (mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
|
||||
if (tplg_fixup &&
|
||||
mach->tplg_quirk_mask & SND_SOC_ACPI_TPLG_INTEL_SSP_NUMBER &&
|
||||
mach->mach_params.i2s_link_mask) {
|
||||
int ssp_num;
|
||||
|
||||
@ -1523,7 +1548,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
|
||||
add_extension = true;
|
||||
}
|
||||
|
||||
if (add_extension) {
|
||||
if (tplg_fixup && add_extension) {
|
||||
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
|
||||
"%s%s",
|
||||
sof_pdata->tplg_filename,
|
||||
|
@ -372,20 +372,9 @@ static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core)
|
||||
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE, dspcxctl,
|
||||
(dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
|
||||
HDA_DSP_RESET_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
if (ret < 0)
|
||||
dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
|
||||
__func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* did core power up ? */
|
||||
dspcxctl = snd_sof_dsp_read(sdev, HDA_DSP_BAR, MTL_DSP2CXCTL_PRIMARY_CORE);
|
||||
if ((dspcxctl & MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK)
|
||||
!= MTL_DSP2CXCTL_PRIMARY_CORE_CPA_MASK) {
|
||||
dev_err(sdev->dev, "power up core failed core %d adspcs %#x\n",
|
||||
core, dspcxctl);
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
|
||||
static ssize_t ipc3_fw_ext_man_size(struct snd_sof_dev *sdev, const struct firmware *fw)
|
||||
{
|
||||
const struct sof_ext_man_header *head;
|
||||
|
||||
@ -131,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
|
||||
return head->full_size;
|
||||
|
||||
/* otherwise given fw don't have an extended manifest */
|
||||
dev_dbg(sdev->dev, "Unexpected extended manifest magic number: %#x\n",
|
||||
head->magic);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -147,7 +149,7 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev)
|
||||
|
||||
head = (struct sof_ext_man_header *)fw->data;
|
||||
remaining = head->full_size - head->header_size;
|
||||
ext_man_size = ipc3_fw_ext_man_size(fw);
|
||||
ext_man_size = ipc3_fw_ext_man_size(sdev, fw);
|
||||
|
||||
/* Assert firmware starts with extended manifest */
|
||||
if (ext_man_size <= 0)
|
||||
|
@ -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
|
||||
|
@ -111,6 +111,12 @@ 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)},
|
||||
};
|
||||
|
||||
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 +140,7 @@ 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)},
|
||||
};
|
||||
|
||||
static void sof_ipc4_dbg_audio_format(struct device *dev,
|
||||
@ -307,6 +314,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);
|
||||
@ -323,6 +331,9 @@ 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 & SOF_IPC4_MODULE_DP ? 1 : 0;
|
||||
msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -740,6 +751,58 @@ err:
|
||||
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 by SRC */
|
||||
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 SRC tokens failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
dev_dbg(scomp->dev, "SRC sink rate %d\n", src->sink_rate);
|
||||
|
||||
ret = sof_ipc4_widget_setup_msg(swidget, &src->msg);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
sof_ipc4_free_audio_fmt(&src->available_fmt);
|
||||
kfree(src);
|
||||
swidget->private = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sof_ipc4_widget_free_comp_src(struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct sof_ipc4_src *src = swidget->private;
|
||||
|
||||
if (!src)
|
||||
return;
|
||||
|
||||
sof_ipc4_free_audio_fmt(&src->available_fmt);
|
||||
kfree(swidget->private);
|
||||
swidget->private = NULL;
|
||||
}
|
||||
|
||||
static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct sof_ipc4_mixer *mixer = swidget->private;
|
||||
@ -891,7 +954,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev,
|
||||
|
||||
static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
|
||||
struct sof_ipc4_copier *ipc4_copier = NULL;
|
||||
struct snd_sof_widget *pipe_widget;
|
||||
struct sof_ipc4_pipeline *pipeline;
|
||||
@ -925,8 +987,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget)
|
||||
ipc4_copier->ipc_config_data = NULL;
|
||||
ipc4_copier->ipc_config_size = 0;
|
||||
}
|
||||
|
||||
ida_free(&fw_module->m_ida, swidget->instance_id);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_ACPI) && IS_ENABLED(CONFIG_SND_INTEL_NHLT)
|
||||
@ -1254,15 +1314,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
|
||||
/* update pipeline memory usage */
|
||||
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
|
||||
|
||||
/* assign instance ID */
|
||||
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
|
||||
}
|
||||
|
||||
static void sof_ipc4_unprepare_generic_module(struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
|
||||
|
||||
ida_free(&fw_module->m_ida, swidget->instance_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
|
||||
@ -1287,8 +1339,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
|
||||
/* update pipeline memory usage */
|
||||
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
|
||||
|
||||
/* assign instance ID */
|
||||
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
|
||||
@ -1314,8 +1365,38 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
|
||||
/* update pipeline memory usage */
|
||||
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
|
||||
|
||||
/* assign instance ID */
|
||||
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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->min;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol)
|
||||
@ -1373,9 +1454,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
|
||||
u32 ipc_size = 0;
|
||||
int ret;
|
||||
|
||||
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);
|
||||
|
||||
switch (swidget->id) {
|
||||
case snd_soc_dapm_scheduler:
|
||||
pipeline = swidget->private;
|
||||
@ -1430,21 +1508,37 @@ 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;
|
||||
}
|
||||
|
||||
if (swidget->id != snd_soc_dapm_scheduler) {
|
||||
ret = sof_ipc4_widget_assign_instance_id(sdev, swidget);
|
||||
if (ret < 0) {
|
||||
dev_err(sdev->dev, "failed to assign instance id for %s\n",
|
||||
swidget->widget->name);
|
||||
return ret;
|
||||
}
|
||||
pipeline = pipe_widget->private;
|
||||
msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
|
||||
msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
|
||||
|
||||
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);
|
||||
}
|
||||
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;
|
||||
@ -1458,6 +1552,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
|
||||
|
||||
static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
|
||||
{
|
||||
struct sof_ipc4_fw_module *fw_module = swidget->module_info;
|
||||
int ret = 0;
|
||||
|
||||
/* freeing a pipeline frees all the widgets associated with it */
|
||||
@ -1480,6 +1575,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
|
||||
|
||||
pipeline->mem_usage = 0;
|
||||
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
|
||||
} else {
|
||||
ida_free(&fw_module->m_ida, swidget->instance_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -1766,6 +1863,15 @@ 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,
|
||||
};
|
||||
|
||||
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,
|
||||
@ -1789,11 +1895,15 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TY
|
||||
[snd_soc_dapm_pga] = {sof_ipc4_widget_setup_comp_pga, sof_ipc4_widget_free_comp_pga,
|
||||
pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
|
||||
sof_ipc4_prepare_gain_module,
|
||||
sof_ipc4_unprepare_generic_module},
|
||||
NULL},
|
||||
[snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
|
||||
mixer_token_list, ARRAY_SIZE(mixer_token_list),
|
||||
NULL, sof_ipc4_prepare_mixer_module,
|
||||
sof_ipc4_unprepare_generic_module},
|
||||
NULL},
|
||||
[snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src,
|
||||
src_token_list, ARRAY_SIZE(src_token_list),
|
||||
NULL, sof_ipc4_prepare_src_module,
|
||||
NULL},
|
||||
};
|
||||
|
||||
const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
|
||||
|
@ -15,7 +15,18 @@
|
||||
#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12)
|
||||
#define SOF_IPC4_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
|
||||
|
||||
#define SOF_IPC4_MODULE_LL BIT(5)
|
||||
#define SOF_IPC4_MODULE_LOAD_TYPE GENMASK(3, 0)
|
||||
#define SOF_IPC4_MODULE_AUTO_START BIT(4)
|
||||
/*
|
||||
* Two module schedule domains in fw :
|
||||
* LL domain - Low latency domain
|
||||
* DP domain - Data processing domain
|
||||
* The LL setting should be equal to !DP setting
|
||||
*/
|
||||
#define SOF_IPC4_MODULE_LL BIT(5)
|
||||
#define SOF_IPC4_MODULE_DP BIT(6)
|
||||
#define SOF_IPC4_MODULE_LIB_CODE BIT(7)
|
||||
|
||||
#define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12
|
||||
#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
|
||||
#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
|
||||
@ -242,4 +253,18 @@ struct sof_ipc4_mixer {
|
||||
struct sof_ipc4_msg msg;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sof_ipc4_src SRC config data
|
||||
* @base_config: IPC base config data
|
||||
* @sink_rate: Output rate for sink module
|
||||
* @available_fmt: Available audio format
|
||||
* @msg: IPC4 message struct containing header and data info
|
||||
*/
|
||||
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
|
||||
|
@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ops->assign(cdev, cstream, dai, &priv->extractor_stream_tag);
|
||||
ret = ops->startup(cdev, cstream, dai, &priv->extractor_stream_tag);
|
||||
if (ret) {
|
||||
dev_err(dai->dev, "Failed to assign probe stream: %d\n", ret);
|
||||
dev_err(dai->dev, "Failed to startup probe stream: %d\n", ret);
|
||||
priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
|
||||
sof_client_core_module_put(cdev);
|
||||
}
|
||||
@ -310,7 +310,7 @@ exit:
|
||||
priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
|
||||
snd_compr_free_pages(cstream);
|
||||
|
||||
ret = ops->free(cdev, cstream, dai);
|
||||
ret = ops->shutdown(cdev, cstream, dai);
|
||||
|
||||
sof_client_core_module_put(cdev);
|
||||
|
||||
@ -709,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
|
||||
|
||||
ops = dev->platform_data;
|
||||
|
||||
if (!ops->assign || !ops->free || !ops->set_params || !ops->trigger ||
|
||||
if (!ops->startup || !ops->shutdown || !ops->set_params || !ops->trigger ||
|
||||
!ops->pointer) {
|
||||
dev_err(dev, "missing platform callback(s)\n");
|
||||
return -ENODEV;
|
||||
|
@ -14,10 +14,10 @@ struct snd_soc_dai;
|
||||
* DSP and host, like HDA.
|
||||
*/
|
||||
struct sof_probes_host_ops {
|
||||
int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id);
|
||||
int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai);
|
||||
int (*startup)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai, u32 *stream_id);
|
||||
int (*shutdown)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_soc_dai *dai);
|
||||
int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
|
||||
struct snd_compr_params *params,
|
||||
struct snd_soc_dai *dai);
|
||||
|
Loading…
x
Reference in New Issue
Block a user