Commit 16824dff authored by Mark Brown's avatar Mark Brown

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.
parents 09f85289 321add80
...@@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, ...@@ -274,22 +274,22 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
const char *ssp_str) const char *ssp_str)
{ {
const char *tplg_filename = NULL; const char *tplg_filename = NULL;
char *filename; const char *split_ext;
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) if (!filename)
return NULL; return NULL;
/* this assumes a .tplg extension */ /* this assumes a .tplg extension */
split_ext = strsep(&filename, "."); tmp = filename;
if (split_ext) { split_ext = strsep(&tmp, ".");
if (split_ext)
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s-%s.tplg", "%s-%s.tplg",
split_ext, ssp_str); split_ext, ssp_str);
if (!tplg_filename) kfree(filename);
return NULL;
}
return tplg_filename; return tplg_filename;
} }
......
...@@ -25,7 +25,7 @@ hda_compr_get_stream(struct snd_compr_stream *cstream) ...@@ -25,7 +25,7 @@ hda_compr_get_stream(struct snd_compr_stream *cstream)
return cstream->runtime->private_data; return cstream->runtime->private_data;
} }
static int hda_probes_compr_assign(struct sof_client_dev *cdev, static int hda_probes_compr_startup(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id) struct snd_soc_dai *dai, u32 *stream_id)
{ {
...@@ -45,7 +45,7 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev, ...@@ -45,7 +45,7 @@ static int hda_probes_compr_assign(struct sof_client_dev *cdev,
return 0; return 0;
} }
static int hda_probes_compr_free(struct sof_client_dev *cdev, static int hda_probes_compr_shutdown(struct sof_client_dev *cdev,
struct snd_compr_stream *cstream, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
...@@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev, ...@@ -127,8 +127,8 @@ static int hda_probes_compr_pointer(struct sof_client_dev *cdev,
/* SOF client implementation */ /* SOF client implementation */
static const struct sof_probes_host_ops hda_probes_ops = { static const struct sof_probes_host_ops hda_probes_ops = {
.assign = hda_probes_compr_assign, .startup = hda_probes_compr_startup,
.free = hda_probes_compr_free, .shutdown = hda_probes_compr_shutdown,
.set_params = hda_probes_compr_set_params, .set_params = hda_probes_compr_set_params,
.trigger = hda_probes_compr_trigger, .trigger = hda_probes_compr_trigger,
.pointer = hda_probes_compr_pointer, .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 ...@@ -411,6 +411,11 @@ int hda_dsp_iccmax_stream_hw_params(struct snd_sof_dev *sdev, struct hdac_ext_st
return -ENODEV; return -ENODEV;
} }
if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV;
}
if (hstream->posbuf) if (hstream->posbuf)
*hstream->posbuf = 0; *hstream->posbuf = 0;
...@@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev, ...@@ -485,16 +490,16 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return -ENODEV; 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) { if (!dmab) {
dev_err(sdev->dev, "error: no dma buffer allocated!\n"); dev_err(sdev->dev, "error: no dma buffer allocated!\n");
return -ENODEV; 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 */ /* clear stream status */
snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset, snd_sof_dsp_update_bits(sdev, HDA_DSP_HDA_BAR, sd_offset,
SOF_HDA_CL_DMA_SD_INT_MASK | SOF_HDA_CL_DMA_SD_INT_MASK |
......
...@@ -776,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev, ...@@ -776,13 +776,12 @@ static const char *fixup_tplg_name(struct snd_sof_dev *sdev,
return tplg_filename; return tplg_filename;
} }
static int dmic_topology_fixup(struct snd_sof_dev *sdev, static int dmic_detect_topology_fixup(struct snd_sof_dev *sdev,
const char **tplg_filename, const char **tplg_filename,
const char *idisp_str, const char *idisp_str,
int *dmic_found) int *dmic_found,
bool tplg_fixup)
{ {
const char *default_tplg_filename = *tplg_filename;
const char *fixed_tplg_filename;
const char *dmic_str; const char *dmic_str;
int dmic_num; int dmic_num;
...@@ -808,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev, ...@@ -808,14 +807,19 @@ static int dmic_topology_fixup(struct snd_sof_dev *sdev,
break; break;
} }
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, fixed_tplg_filename = fixup_tplg_name(sdev, default_tplg_filename,
idisp_str, dmic_str); idisp_str, dmic_str);
if (!fixed_tplg_filename) if (!fixed_tplg_filename)
return -ENOMEM; return -ENOMEM;
*tplg_filename = fixed_tplg_filename;
}
dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num); dev_info(sdev->dev, "DMICs detected in NHLT tables: %d\n", dmic_num);
*dmic_found = dmic_num; *dmic_found = dmic_num;
*tplg_filename = fixed_tplg_filename;
return 0; return 0;
} }
...@@ -1221,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev, ...@@ -1221,6 +1225,8 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
* - one external HDAudio codec * - one external HDAudio codec
*/ */
if (!*mach && codec_num <= 2) { if (!*mach && codec_num <= 2) {
bool tplg_fixup;
hda_mach = snd_soc_acpi_intel_hda_machines; hda_mach = snd_soc_acpi_intel_hda_machines;
dev_info(bus->dev, "using HDA machine driver %s now\n", 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, ...@@ -1232,8 +1238,15 @@ static void hda_generic_machine_select(struct snd_sof_dev *sdev,
idisp_str = ""; idisp_str = "";
/* topology: use the info from hda_machines */ /* topology: use the info from hda_machines */
if (pdata->tplg_filename) {
tplg_fixup = false;
tplg_filename = pdata->tplg_filename;
} else {
tplg_fixup = true;
tplg_filename = hda_mach->sof_tplg_filename; tplg_filename = hda_mach->sof_tplg_filename;
ret = dmic_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num); }
ret = dmic_detect_topology_fixup(sdev, &tplg_filename, idisp_str, &dmic_num,
tplg_fixup);
if (ret < 0) if (ret < 0)
return; return;
...@@ -1397,12 +1410,19 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev ...@@ -1397,12 +1410,19 @@ static struct snd_soc_acpi_mach *hda_sdw_machine_select(struct snd_sof_dev *sdev
} }
if (mach && mach->link_mask) { if (mach && mach->link_mask) {
int dmic_num = 0; int dmic_num = 0;
bool tplg_fixup;
const char *tplg_filename;
mach->mach_params.links = mach->links; mach->mach_params.links = mach->links;
mach->mach_params.link_mask = mach->link_mask; mach->mach_params.link_mask = mach->link_mask;
mach->mach_params.platform = dev_name(sdev->dev); 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 * 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 ...@@ -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 * b) the NHLT table reports the presence of microphones
*/ */
if (hweight_long(mach->link_mask) <= 2) { if (hweight_long(mach->link_mask) <= 2) {
const char *tplg_filename = mach->sof_tplg_filename;
int ret; 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) if (ret < 0)
return NULL; return NULL;
pdata->tplg_filename = tplg_filename;
} }
if (tplg_fixup)
pdata->tplg_filename = tplg_filename;
mach->mach_params.dmic_num = dmic_num; mach->mach_params.dmic_num = dmic_num;
dev_dbg(sdev->dev, dev_dbg(sdev->dev,
...@@ -1466,18 +1486,22 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -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); mach = snd_soc_acpi_find_machine(desc->machines);
if (mach) { if (mach) {
bool add_extension = false; bool add_extension = false;
bool tplg_fixup = false;
/* /*
* If tplg file name is overridden, use it instead of * If tplg file name is overridden, use it instead of
* the one set in mach table * the one set in mach table
*/ */
if (!sof_pdata->tplg_filename) if (!sof_pdata->tplg_filename) {
sof_pdata->tplg_filename = mach->sof_tplg_filename; sof_pdata->tplg_filename = mach->sof_tplg_filename;
tplg_fixup = true;
}
/* report to machine driver if any DMICs are found */ /* report to machine driver if any DMICs are found */
mach->mach_params.dmic_num = check_dmic_num(sdev); 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) { mach->mach_params.dmic_num) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s%d%s", "%s%s%d%s",
...@@ -1500,7 +1524,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -1500,7 +1524,8 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
/* report SSP link mask to machine driver */ /* report SSP link mask to machine driver */
mach->mach_params.i2s_link_mask = check_nhlt_ssp_mask(sdev); 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) { mach->mach_params.i2s_link_mask) {
int ssp_num; int ssp_num;
...@@ -1523,7 +1548,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev) ...@@ -1523,7 +1548,7 @@ struct snd_soc_acpi_mach *hda_machine_select(struct snd_sof_dev *sdev)
add_extension = true; add_extension = true;
} }
if (add_extension) { if (tplg_fixup && add_extension) {
tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL, tplg_filename = devm_kasprintf(sdev->dev, GFP_KERNEL,
"%s%s", "%s%s",
sof_pdata->tplg_filename, sof_pdata->tplg_filename,
......
...@@ -372,20 +372,9 @@ static int mtl_dsp_core_power_up(struct snd_sof_dev *sdev, int core) ...@@ -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, 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, (dspcxctl & cpa) == cpa, HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_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", dev_err(sdev->dev, "%s: timeout on MTL_DSP2CXCTL_PRIMARY_CORE read\n",
__func__); __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; return ret;
} }
......
...@@ -109,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev, ...@@ -109,7 +109,7 @@ static int ipc3_fw_ext_man_get_config_data(struct snd_sof_dev *sdev,
return 0; 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; const struct sof_ext_man_header *head;
...@@ -131,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw) ...@@ -131,6 +131,8 @@ static ssize_t ipc3_fw_ext_man_size(const struct firmware *fw)
return head->full_size; return head->full_size;
/* otherwise given fw don't have an extended manifest */ /* otherwise given fw don't have an extended manifest */
dev_dbg(sdev->dev, "Unexpected extended manifest magic number: %#x\n",
head->magic);
return 0; return 0;
} }
...@@ -147,7 +149,7 @@ static size_t sof_ipc3_fw_parse_ext_man(struct snd_sof_dev *sdev) ...@@ -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; head = (struct sof_ext_man_header *)fw->data;
remaining = head->full_size - head->header_size; 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 */ /* Assert firmware starts with extended manifest */
if (ext_man_size <= 0) if (ext_man_size <= 0)
......
...@@ -179,6 +179,7 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -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_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_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_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
struct sof_ipc4_copier *ipc4_copier; struct sof_ipc4_copier *ipc4_copier;
...@@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, ...@@ -201,6 +202,9 @@ static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd,
snd_mask_none(fmt); snd_mask_none(fmt);
snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S32_LE); 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 * 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 * 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[] = { ...@@ -111,6 +111,12 @@ static const struct sof_topology_token gain_tokens[] = {
get_token_u32, offsetof(struct sof_ipc4_gain_data, init_val)}, 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] = { static const struct sof_token_info ipc4_token_list[SOF_TOKEN_COUNT] = {
[SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)}, [SOF_DAI_TOKENS] = {"DAI tokens", dai_tokens, ARRAY_SIZE(dai_tokens)},
[SOF_PIPELINE_TOKENS] = {"Pipeline tokens", pipeline_tokens, ARRAY_SIZE(pipeline_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] = { ...@@ -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", [SOF_AUDIO_FMT_NUM_TOKENS] = {"IPC4 Audio format number tokens",
ipc4_audio_fmt_num_tokens, ARRAY_SIZE(ipc4_audio_fmt_num_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_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, 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) ...@@ -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) static int sof_ipc4_widget_setup_msg(struct snd_sof_widget *swidget, struct sof_ipc4_msg *msg)
{ {
struct sof_ipc4_fw_module *fw_module; struct sof_ipc4_fw_module *fw_module;
uint32_t type;
int ret; int ret;
ret = sof_ipc4_widget_set_module_info(swidget); 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_ ...@@ -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_PPL_ID(swidget->pipeline_id);
msg->extension |= SOF_IPC4_MOD_EXT_CORE_ID(swidget->core); 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; return 0;
} }
...@@ -740,6 +751,58 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget) ...@@ -740,6 +751,58 @@ static int sof_ipc4_widget_setup_comp_mixer(struct snd_sof_widget *swidget)
return ret; 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) static void sof_ipc4_widget_free_comp_mixer(struct snd_sof_widget *swidget)
{ {
struct sof_ipc4_mixer *mixer = swidget->private; struct sof_ipc4_mixer *mixer = swidget->private;
...@@ -891,7 +954,6 @@ static int sof_ipc4_init_audio_fmt(struct snd_sof_dev *sdev, ...@@ -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) 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 sof_ipc4_copier *ipc4_copier = NULL;
struct snd_sof_widget *pipe_widget; struct snd_sof_widget *pipe_widget;
struct sof_ipc4_pipeline *pipeline; struct sof_ipc4_pipeline *pipeline;
...@@ -925,8 +987,6 @@ static void sof_ipc4_unprepare_copier_module(struct snd_sof_widget *swidget) ...@@ -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_data = NULL;
ipc4_copier->ipc_config_size = 0; 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) #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, ...@@ -1254,15 +1314,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */ /* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config); sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &copier_data->base_config);
/* assign instance ID */ return 0;
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);
} }
static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget, 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, ...@@ -1287,8 +1339,7 @@ static int sof_ipc4_prepare_gain_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */ /* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config); sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &gain->base_config);
/* assign instance ID */ return 0;
return sof_ipc4_widget_assign_instance_id(sdev, swidget);
} }
static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget, 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, ...@@ -1314,8 +1365,38 @@ static int sof_ipc4_prepare_mixer_module(struct snd_sof_widget *swidget,
/* update pipeline memory usage */ /* update pipeline memory usage */
sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config); sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &mixer->base_config);
/* assign instance ID */ return 0;
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->min;
return 0;
} }
static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 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 ...@@ -1373,9 +1454,6 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
u32 ipc_size = 0; u32 ipc_size = 0;
int ret; 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) { switch (swidget->id) {
case snd_soc_dapm_scheduler: case snd_soc_dapm_scheduler:
pipeline = swidget->private; pipeline = swidget->private;
...@@ -1430,21 +1508,37 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget ...@@ -1430,21 +1508,37 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
msg = &mixer->msg; msg = &mixer->msg;
break; 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: default:
dev_err(sdev->dev, "widget type %d not supported", swidget->id); dev_err(sdev->dev, "widget type %d not supported", swidget->id);
return -EINVAL; return -EINVAL;
} }
if (swidget->id != snd_soc_dapm_scheduler) { 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; pipeline = pipe_widget->private;
msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK; msg->primary &= ~SOF_IPC4_MOD_INSTANCE_MASK;
msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id); msg->primary |= SOF_IPC4_MOD_INSTANCE(swidget->instance_id);
msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK; msg->extension &= ~SOF_IPC4_MOD_EXT_PARAM_SIZE_MASK;
msg->extension |= ipc_size >> 2; 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_size = ipc_size;
msg->data_ptr = ipc_data; msg->data_ptr = ipc_data;
...@@ -1458,6 +1552,7 @@ static int sof_ipc4_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget ...@@ -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) 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; int ret = 0;
/* freeing a pipeline frees all the widgets associated with it */ /* 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 ...@@ -1480,6 +1575,8 @@ static int sof_ipc4_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget
pipeline->mem_usage = 0; pipeline->mem_usage = 0;
pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED; pipeline->state = SOF_IPC4_PIPE_UNINITIALIZED;
} else {
ida_free(&fw_module->m_ida, swidget->instance_id);
} }
return ret; return ret;
...@@ -1766,6 +1863,15 @@ static enum sof_tokens mixer_token_list[] = { ...@@ -1766,6 +1863,15 @@ static enum sof_tokens mixer_token_list[] = {
SOF_COMP_EXT_TOKENS, 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] = { 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, [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, 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 ...@@ -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, [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, pga_token_list, ARRAY_SIZE(pga_token_list), NULL,
sof_ipc4_prepare_gain_module, 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, [snd_soc_dapm_mixer] = {sof_ipc4_widget_setup_comp_mixer, sof_ipc4_widget_free_comp_mixer,
mixer_token_list, ARRAY_SIZE(mixer_token_list), mixer_token_list, ARRAY_SIZE(mixer_token_list),
NULL, sof_ipc4_prepare_mixer_module, 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 = { const struct sof_ipc_tplg_ops ipc4_tplg_ops = {
......
...@@ -15,7 +15,18 @@ ...@@ -15,7 +15,18 @@
#define SOF_IPC4_FW_PAGE(x) ((((x) + BIT(12) - 1) & ~(BIT(12) - 1)) >> 12) #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_FW_ROUNDUP(x) (((x) + BIT(6) - 1) & (~(BIT(6) - 1)))
#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_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_MODULE_INSTANCE_LIST_ITEM_SIZE 12
#define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 #define SOF_IPC4_PIPELINE_OBJECT_SIZE 448
#define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128 #define SOF_IPC4_DATA_QUEUE_OBJECT_SIZE 128
...@@ -242,4 +253,18 @@ struct sof_ipc4_mixer { ...@@ -242,4 +253,18 @@ struct sof_ipc4_mixer {
struct sof_ipc4_msg msg; 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 #endif
...@@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream, ...@@ -270,9 +270,9 @@ static int sof_probes_compr_startup(struct snd_compr_stream *cstream,
if (ret) if (ret)
return 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) { 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; priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
sof_client_core_module_put(cdev); sof_client_core_module_put(cdev);
} }
...@@ -310,7 +310,7 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream, ...@@ -310,7 +310,7 @@ static int sof_probes_compr_shutdown(struct snd_compr_stream *cstream,
priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID; priv->extractor_stream_tag = SOF_PROBES_INVALID_NODE_ID;
snd_compr_free_pages(cstream); snd_compr_free_pages(cstream);
ret = ops->free(cdev, cstream, dai); ret = ops->shutdown(cdev, cstream, dai);
sof_client_core_module_put(cdev); sof_client_core_module_put(cdev);
...@@ -709,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev, ...@@ -709,7 +709,7 @@ static int sof_probes_client_probe(struct auxiliary_device *auxdev,
ops = dev->platform_data; 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) { !ops->pointer) {
dev_err(dev, "missing platform callback(s)\n"); dev_err(dev, "missing platform callback(s)\n");
return -ENODEV; return -ENODEV;
......
...@@ -14,9 +14,9 @@ struct snd_soc_dai; ...@@ -14,9 +14,9 @@ struct snd_soc_dai;
* DSP and host, like HDA. * DSP and host, like HDA.
*/ */
struct sof_probes_host_ops { struct sof_probes_host_ops {
int (*assign)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, int (*startup)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai, u32 *stream_id); struct snd_soc_dai *dai, u32 *stream_id);
int (*free)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, int (*shutdown)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_soc_dai *dai); struct snd_soc_dai *dai);
int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream, int (*set_params)(struct sof_client_dev *cdev, struct snd_compr_stream *cstream,
struct snd_compr_params *params, struct snd_compr_params *params,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment