diff options
| author | Mark Brown <broonie@kernel.org> | 2022-03-18 20:11:08 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2022-03-18 20:11:08 +0000 |
| commit | 49a24e9d9c740d3bd8b1200f225f67d45e3d68a5 (patch) | |
| tree | d4c06e308b53335ac39f516bba4628b85c412309 | |
| parent | c639e85e93aa10ea0512ee416eead60da466e161 (diff) | |
| parent | 85f7a8b6e1bea0ad494fb786a5dd7d9715a976d2 (diff) | |
| download | linux-49a24e9d9c740d3bd8b1200f225f67d45e3d68a5.tar.gz linux-49a24e9d9c740d3bd8b1200f225f67d45e3d68a5.tar.bz2 linux-49a24e9d9c740d3bd8b1200f225f67d45e3d68a5.zip | |
Make the SOF control, PCM and PM code IPC agnostic
Merge series from Ranjani Sridharan <ranjani.sridharan@linux.intel.com>:
This series is a continuation to the SOF IPC abstraction work to support
the new IPC version introduced in the SOF firmware. It makes the top-level
control IO, PCM and PM code IPC-agnostic. Other than the first patch,
the rest are purely for abstraction and include no changes in
functionality.
| -rw-r--r-- | sound/soc/sof/Makefile | 2 | ||||
| -rw-r--r-- | sound/soc/sof/control.c | 545 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda-dai.c | 97 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda.c | 169 | ||||
| -rw-r--r-- | sound/soc/sof/intel/hda.h | 7 | ||||
| -rw-r--r-- | sound/soc/sof/ipc.c | 10 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3-control.c | 594 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3-ops.h | 21 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3-pcm.c | 372 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3-topology.c | 384 | ||||
| -rw-r--r-- | sound/soc/sof/ipc3.c | 45 | ||||
| -rw-r--r-- | sound/soc/sof/pcm.c | 354 | ||||
| -rw-r--r-- | sound/soc/sof/pm.c | 80 | ||||
| -rw-r--r-- | sound/soc/sof/sof-audio.c | 442 | ||||
| -rw-r--r-- | sound/soc/sof/sof-audio.h | 70 | ||||
| -rw-r--r-- | sound/soc/sof/sof-priv.h | 17 | ||||
| -rw-r--r-- | sound/soc/sof/topology.c | 55 |
17 files changed, 1805 insertions, 1459 deletions
diff --git a/sound/soc/sof/Makefile b/sound/soc/sof/Makefile index e13dab59764c..18acbc001b9a 100644 --- a/sound/soc/sof/Makefile +++ b/sound/soc/sof/Makefile @@ -2,7 +2,7 @@ snd-sof-objs := core.o ops.o loader.o ipc.o pcm.o pm.o debug.o topology.o\ control.o trace.o iomem-utils.o sof-audio.o stream-ipc.o\ - ipc3-topology.o + ipc3-topology.o ipc3.o ipc3-control.o ipc3-pcm.o ifneq ($(CONFIG_SND_SOC_SOF_CLIENT),) snd-sof-objs += sof-client.o endif diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c index 21ee0545945d..de1778c4002b 100644 --- a/sound/soc/sof/control.c +++ b/sound/soc/sof/control.c @@ -45,68 +45,17 @@ static void update_mute_led(struct snd_sof_control *scontrol, #endif } -static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size) -{ - if (value >= size) - return volume_map[size - 1]; - - return volume_map[value]; -} - -static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size) -{ - int i; - - for (i = 0; i < size; i++) { - if (volume_map[i] >= value) - return i; - } - - return i - 1; -} - -static void snd_sof_refresh_control(struct snd_sof_control *scontrol) -{ - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct snd_soc_component *scomp = scontrol->scomp; - int ret; - - if (!scontrol->comp_data_dirty) - return; - - if (!pm_runtime_active(scomp->dev)) - return; - - /* set the ABI header values */ - cdata->data->magic = SOF_ABI_MAGIC; - cdata->data->abi = SOF_ABI_VERSION; - - /* refresh the component data from DSP */ - scontrol->comp_data_dirty = false; - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); - if (ret < 0) { - dev_err(scomp->dev, "error: failed to get control data: %d\n", ret); - /* Set the flag to re-try next time to get the data */ - scontrol->comp_data_dirty = true; - } -} - int snd_sof_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *sm = - (struct soc_mixer_control *)kcontrol->private_value; + struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - - snd_sof_refresh_control(scontrol); + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* read back each channel */ - for (i = 0; i < channels; i++) - ucontrol->value.integer.value[i] = - ipc_to_mixer(cdata->chanv[i].value, - scontrol->volume_table, sm->max + 1); + if (tplg_ops->control->volume_get) + return tplg_ops->control->volume_get(scontrol, ucontrol); return 0; } @@ -114,28 +63,16 @@ int snd_sof_volume_get(struct snd_kcontrol *kcontrol, int snd_sof_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *sm = - (struct soc_mixer_control *)kcontrol->private_value; + struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - bool change = false; - u32 value; - - /* update each channel */ - for (i = 0; i < channels; i++) { - value = mixer_to_ipc(ucontrol->value.integer.value[i], - scontrol->volume_table, sm->max + 1); - change = change || (value != cdata->chanv[i].value); - cdata->chanv[i].channel = i; - cdata->chanv[i].value = value; - } + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* notify DSP of mixer updates */ - if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, true); - return change; + if (tplg_ops->control->volume_put) + return tplg_ops->control->volume_put(scontrol, ucontrol); + + return false; } int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -163,17 +100,14 @@ int snd_sof_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info int snd_sof_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *sm = - (struct soc_mixer_control *)kcontrol->private_value; + struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - - snd_sof_refresh_control(scontrol); + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* read back each channel */ - for (i = 0; i < channels; i++) - ucontrol->value.integer.value[i] = cdata->chanv[i].value; + if (tplg_ops->control->switch_get) + return tplg_ops->control->switch_get(scontrol, ucontrol); return 0; } @@ -181,47 +115,32 @@ int snd_sof_switch_get(struct snd_kcontrol *kcontrol, int snd_sof_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_mixer_control *sm = - (struct soc_mixer_control *)kcontrol->private_value; + struct soc_mixer_control *sm = (struct soc_mixer_control *)kcontrol->private_value; struct snd_sof_control *scontrol = sm->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - bool change = false; - u32 value; - - /* update each channel */ - for (i = 0; i < channels; i++) { - value = ucontrol->value.integer.value[i]; - change = change || (value != cdata->chanv[i].value); - cdata->chanv[i].channel = i; - cdata->chanv[i].value = value; - } + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; if (scontrol->led_ctl.use_led) update_mute_led(scontrol, kcontrol, ucontrol); - /* notify DSP of mixer updates */ - if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, true); + if (tplg_ops->control->switch_put) + return tplg_ops->control->switch_put(scontrol, ucontrol); - return change; + return false; } int snd_sof_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_enum *se = - (struct soc_enum *)kcontrol->private_value; + struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - - snd_sof_refresh_control(scontrol); + struct snd_soc_component *scomp = scontrol->scomp; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* read back each channel */ - for (i = 0; i < channels; i++) - ucontrol->value.enumerated.item[i] = cdata->chanv[i].value; + if (tplg_ops->control->enum_get) + return tplg_ops->control->enum_get(scontrol, ucontrol); return 0; } @@ -229,62 +148,29 @@ int snd_sof_enum_get(struct snd_kcontrol *kcontrol, int snd_sof_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_enum *se = - (struct soc_enum *)kcontrol->private_value; + struct soc_enum *se = (struct soc_enum *)kcontrol->private_value; struct snd_sof_control *scontrol = se->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - unsigned int i, channels = scontrol->num_channels; - bool change = false; - u32 value; - - /* update each channel */ - for (i = 0; i < channels; i++) { - value = ucontrol->value.enumerated.item[i]; - change = change || (value != cdata->chanv[i].value); - cdata->chanv[i].channel = i; - cdata->chanv[i].value = value; - } + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* notify DSP of enum updates */ - if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, true); + if (tplg_ops->control->enum_put) + return tplg_ops->control->enum_put(scontrol, ucontrol); - return change; + return false; } int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_bytes_ext *be = - (struct soc_bytes_ext *)kcontrol->private_value; + struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct sof_abi_hdr *data = cdata->data; - size_t size; - - snd_sof_refresh_control(scontrol); - - if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(scomp->dev, - "error: data max %d exceeds ucontrol data array size\n", - be->max); - return -EINVAL; - } + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ - if (data->size > be->max - sizeof(*data)) { - dev_err_ratelimited(scomp->dev, - "error: %u bytes of control data is invalid, max is %zu\n", - data->size, be->max - sizeof(*data)); - return -EINVAL; - } - - size = data->size + sizeof(*data); - - /* copy back to kcontrol */ - memcpy(ucontrol->value.bytes.data, data, size); + if (tplg_ops->control->bytes_get) + return tplg_ops->control->bytes_get(scontrol, ucontrol); return 0; } @@ -292,37 +178,14 @@ int snd_sof_bytes_get(struct snd_kcontrol *kcontrol, int snd_sof_bytes_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct soc_bytes_ext *be = - (struct soc_bytes_ext *)kcontrol->private_value; + struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct sof_abi_hdr *data = cdata->data; - size_t size; - - if (be->max > sizeof(ucontrol->value.bytes.data)) { - dev_err_ratelimited(scomp->dev, - "error: data max %d exceeds ucontrol data array size\n", - be->max); - return -EINVAL; - } - - /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ - if (data->size > be->max - sizeof(*data)) { - dev_err_ratelimited(scomp->dev, - "error: data size too big %u bytes max is %zu\n", - data->size, be->max - sizeof(*data)); - return -EINVAL; - } - - size = data->size + sizeof(*data); - - /* copy from kcontrol */ - memcpy(data, ucontrol->value.bytes.data, size); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* notify DSP of byte control updates */ - if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, true); + if (tplg_ops->control->bytes_put) + return tplg_ops->control->bytes_put(scontrol, ucontrol); return 0; } @@ -331,74 +194,18 @@ int snd_sof_bytes_ext_put(struct snd_kcontrol *kcontrol, const unsigned int __user *binary_data, unsigned int size) { - struct soc_bytes_ext *be = - (struct soc_bytes_ext *)kcontrol->private_value; + struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct snd_ctl_tlv header; - const struct snd_ctl_tlv __user *tlvd = - (const struct snd_ctl_tlv __user *)binary_data; + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; /* make sure we have at least a header */ if (size < sizeof(struct snd_ctl_tlv)) return -EINVAL; - /* - * The beginning of bytes data contains a header from where - * the length (as bytes) is needed to know the correct copy - * length of data from tlvd->tlv. - */ - if (copy_from_user(&header, tlvd, sizeof(struct snd_ctl_tlv))) - return -EFAULT; - - /* make sure TLV info is consistent */ - if (header.length + sizeof(struct snd_ctl_tlv) > size) { - dev_err_ratelimited(scomp->dev, "error: inconsistent TLV, data %d + header %zu > %d\n", - header.length, sizeof(struct snd_ctl_tlv), size); - return -EINVAL; - } - - /* be->max is coming from topology */ - if (header.length > be->max) { - dev_err_ratelimited(scomp->dev, "error: Bytes data size %d exceeds max %d.\n", - header.length, be->max); - return -EINVAL; - } - - /* Check that header id matches the command */ - if (header.numid != cdata->cmd) { - dev_err_ratelimited(scomp->dev, - "error: incorrect numid %d\n", - header.numid); - return -EINVAL; - } - - if (copy_from_user(cdata->data, tlvd->tlv, header.length)) - return -EFAULT; - - if (cdata->data->magic != SOF_ABI_MAGIC) { - dev_err_ratelimited(scomp->dev, - "error: Wrong ABI magic 0x%08x.\n", - cdata->data->magic); - return -EINVAL; - } - - if (SOF_ABI_VERSION_INCOMPATIBLE(SOF_ABI_VERSION, cdata->data->abi)) { - dev_err_ratelimited(scomp->dev, "error: Incompatible ABI version 0x%08x.\n", - cdata->data->abi); - return -EINVAL; - } - - /* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ - if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { - dev_err_ratelimited(scomp->dev, "error: Mismatch in ABI data size (truncated?).\n"); - return -EINVAL; - } - - /* notify DSP of byte control updates */ - if (pm_runtime_active(scomp->dev)) - snd_sof_ipc_set_get_comp_data(scontrol, true); + if (tplg_ops->control->bytes_ext_put) + return tplg_ops->control->bytes_ext_put(scontrol, binary_data, size); return 0; } @@ -409,67 +216,24 @@ int snd_sof_bytes_ext_volatile_get(struct snd_kcontrol *kcontrol, unsigned int _ struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct snd_ctl_tlv header; - struct snd_ctl_tlv __user *tlvd = (struct snd_ctl_tlv __user *)binary_data; - size_t data_size; - int ret; - int err; - - /* - * Decrement the limit by ext bytes header size to - * ensure the user space buffer is not exceeded. - */ - if (size < sizeof(struct snd_ctl_tlv)) - return -ENOSPC; - size -= sizeof(struct snd_ctl_tlv); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + int ret, err; ret = pm_runtime_get_sync(scomp->dev); if (ret < 0 && ret != -EACCES) { - dev_err_ratelimited(scomp->dev, "error: bytes_ext get failed to resume %d\n", ret); + dev_err_ratelimited(scomp->dev, "%s: failed to resume %d\n", __func__, ret); pm_runtime_put_noidle(scomp->dev); return ret; } - /* set the ABI header values */ - cdata->data->magic = SOF_ABI_MAGIC; - cdata->data->abi = SOF_ABI_VERSION; - /* get all the component data from DSP */ - ret = snd_sof_ipc_set_get_comp_data(scontrol, false); - if (ret < 0) - goto out; - - /* check data size doesn't exceed max coming from topology */ - if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { - dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", - cdata->data->size, - be->max - sizeof(struct sof_abi_hdr)); - ret = -EINVAL; - goto out; - } - - data_size = cdata->data->size + sizeof(struct sof_abi_hdr); - - /* make sure we don't exceed size provided by user space for data */ - if (data_size > size) { - ret = -ENOSPC; - goto out; - } - - header.numid = cdata->cmd; - header.length = data_size; - if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) { - ret = -EFAULT; - goto out; - } + if (tplg_ops->control->bytes_ext_volatile_get) + ret = tplg_ops->control->bytes_ext_volatile_get(scontrol, binary_data, size); - if (copy_to_user(tlvd->tlv, cdata->data, data_size)) - ret = -EFAULT; -out: pm_runtime_mark_last_busy(scomp->dev); err = pm_runtime_put_autosuspend(scomp->dev); if (err < 0) - dev_err_ratelimited(scomp->dev, "error: bytes_ext get failed to idle %d\n", err); + dev_err_ratelimited(scomp->dev, "%s: failed to idle %d\n", __func__, err); return ret; } @@ -478,195 +242,14 @@ int snd_sof_bytes_ext_get(struct snd_kcontrol *kcontrol, unsigned int __user *binary_data, unsigned int size) { - struct soc_bytes_ext *be = - (struct soc_bytes_ext *)kcontrol->private_value; + struct soc_bytes_ext *be = (struct soc_bytes_ext *)kcontrol->private_value; struct snd_sof_control *scontrol = be->dobj.private; struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data; - struct snd_ctl_tlv header; - struct snd_ctl_tlv __user *tlvd = - (struct snd_ctl_tlv __user *)binary_data; - size_t data_size; - - snd_sof_refresh_control(scontrol); - - /* - * Decrement the limit by ext bytes header size to - * ensure the user space buffer is not exceeded. - */ - if (size < sizeof(struct snd_ctl_tlv)) - return -ENOSPC; - size -= sizeof(struct snd_ctl_tlv); - - /* set the ABI header values */ - cdata->data->magic = SOF_ABI_MAGIC; - cdata->data->abi = SOF_ABI_VERSION; - - /* check data size doesn't exceed max coming from topology */ - if (cdata->data->size > be->max - sizeof(struct sof_abi_hdr)) { - dev_err_ratelimited(scomp->dev, "error: user data size %d exceeds max size %zu.\n", - cdata->data->size, - be->max - sizeof(struct sof_abi_hdr)); - return -EINVAL; - } - - data_size = cdata->data->size + sizeof(struct sof_abi_hdr); + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; - /* make sure we don't exceed size provided by user space for data */ - if (data_size > size) - return -ENOSPC; - - header.numid = cdata->cmd; - header.length = data_size; - if (copy_to_user(tlvd, &header, sizeof(struct snd_ctl_tlv))) - return -EFAULT; - - if (copy_to_user(tlvd->tlv, cdata->data, data_size)) - return -EFAULT; + if (tplg_ops->control->bytes_ext_get) + return tplg_ops->control->bytes_ext_get(scontrol, binary_data, size); return 0; } - -static void snd_sof_update_control(struct snd_sof_control *scontrol, - struct sof_ipc_ctrl_data *cdata) -{ - struct snd_soc_component *scomp = scontrol->scomp; - struct sof_ipc_ctrl_data *local_cdata; - int i; - - local_cdata = scontrol->ipc_control_data; - - if (cdata->cmd == SOF_CTRL_CMD_BINARY) { - if (cdata->num_elems != local_cdata->data->size) { - dev_err(scomp->dev, - "error: cdata binary size mismatch %u - %u\n", - cdata->num_elems, local_cdata->data->size); - return; - } - - /* copy the new binary data */ - memcpy(local_cdata->data, cdata->data, cdata->num_elems); - } else if (cdata->num_elems != scontrol->num_channels) { - dev_err(scomp->dev, - "error: cdata channel count mismatch %u - %d\n", - cdata->num_elems, scontrol->num_channels); - } else { - /* copy the new values */ - for (i = 0; i < cdata->num_elems; i++) - local_cdata->chanv[i].value = cdata->chanv[i].value; - } -} - -void snd_sof_control_notify(struct snd_sof_dev *sdev, - struct sof_ipc_ctrl_data *cdata) -{ - struct snd_soc_dapm_widget *widget; - struct snd_sof_control *scontrol; - struct snd_sof_widget *swidget; - struct snd_kcontrol *kc = NULL; - struct soc_mixer_control *sm; - struct soc_bytes_ext *be; - size_t expected_size; - struct soc_enum *se; - bool found = false; - int i, type; - - if (cdata->type == SOF_CTRL_TYPE_VALUE_COMP_GET || - cdata->type == SOF_CTRL_TYPE_VALUE_COMP_SET) { - dev_err(sdev->dev, - "Component data is not supported in control notification\n"); - return; - } - - /* Find the swidget first */ - list_for_each_entry(swidget, &sdev->widget_list, list) { - if (swidget->comp_id == cdata->comp_id) { - found = true; - break; - } - } - - if (!found) - return; - - /* Translate SOF cmd to TPLG type */ - switch (cdata->cmd) { - case SOF_CTRL_CMD_VOLUME: - case SOF_CTRL_CMD_SWITCH: - type = SND_SOC_TPLG_TYPE_MIXER; - break; - case SOF_CTRL_CMD_BINARY: - type = SND_SOC_TPLG_TYPE_BYTES; - break; - case SOF_CTRL_CMD_ENUM: - type = SND_SOC_TPLG_TYPE_ENUM; - break; - default: - dev_err(sdev->dev, "error: unknown cmd %u\n", cdata->cmd); - return; - } - - widget = swidget->widget; - for (i = 0; i < widget->num_kcontrols; i++) { - /* skip non matching types or non matching indexes within type */ - if (widget->dobj.widget.kcontrol_type[i] == type && - widget->kcontrol_news[i].index == cdata->index) { - kc = widget->kcontrols[i]; - break; - } - } - - if (!kc) - return; - - switch (cdata->cmd) { - case SOF_CTRL_CMD_VOLUME: - case SOF_CTRL_CMD_SWITCH: - sm = (struct soc_mixer_control *)kc->private_value; - scontrol = sm->dobj.private; - break; - case SOF_CTRL_CMD_BINARY: - be = (struct soc_bytes_ext *)kc->private_value; - scontrol = be->dobj.private; - break; - case SOF_CTRL_CMD_ENUM: - se = (struct soc_enum *)kc->private_value; - scontrol = se->dobj.private; - break; - default: - return; - } - - expected_size = sizeof(struct sof_ipc_ctrl_data); - switch (cdata->type) { - case SOF_CTRL_TYPE_VALUE_CHAN_GET: - case SOF_CTRL_TYPE_VALUE_CHAN_SET: - expected_size += cdata->num_elems * - sizeof(struct sof_ipc_ctrl_value_chan); - break; - case SOF_CTRL_TYPE_DATA_GET: - case SOF_CTRL_TYPE_DATA_SET: - expected_size += cdata->num_elems + sizeof(struct sof_abi_hdr); - break; - default: - return; - } - - if (cdata->rhdr.hdr.size != expected_size) { - dev_err(sdev->dev, "error: component notification size mismatch\n"); - return; - } - - if (cdata->num_elems) - /* - * The message includes the updated value/data, update the - * control's local cache using the received notification - */ - snd_sof_update_control(scontrol, cdata); - else - /* Mark the scontrol that the value/data is changed in SOF */ - scontrol->comp_data_dirty = true; - - snd_ctl_notify_one(swidget->scomp->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, kc, 0); -} diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index 9b78eea8d76b..f9cb9f1f0237 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -162,58 +162,19 @@ static int hda_link_dma_params(struct hdac_ext_stream *hext_stream, return 0; } -/* Update config for the DAI widget */ -static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w, - int channel) -{ - struct snd_sof_widget *swidget = w->dobj.private; - struct sof_dai_private_data *private; - struct sof_ipc_dai_config *config; - struct snd_sof_dai *sof_dai; - - if (!swidget) - return NULL; - - sof_dai = swidget->private; - - if (!sof_dai || !sof_dai->private) { - dev_err(swidget->scomp->dev, "%s: No private data for DAI %s\n", __func__, - w->name); - return NULL; - } - - private = sof_dai->private; - if (!private->dai_config) { - dev_err(swidget->scomp->dev, "%s: No config for DAI %s\n", __func__, w->name); - return NULL; - } - - config = &private->dai_config[sof_dai->current_config]; - - /* update config with stream tag */ - config->hda.link_dma_ch = channel; - - return config; -} - static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream, struct snd_soc_dapm_widget *w, int channel, bool widget_setup) { - struct snd_sof_dev *sdev = hda_stream->sdev; - struct sof_ipc_dai_config *config; + struct snd_sof_dai_config_data data; - config = hda_dai_update_config(w, channel); - if (!config) { - dev_err(sdev->dev, "error: no config for DAI %s\n", w->name); - return -ENOENT; - } + data.dai_data = channel; /* set up/free DAI widget and send DAI_CONFIG IPC */ if (widget_setup) - return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP); + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data); - return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data); } static int hda_link_hw_params(struct snd_pcm_substream *substream, @@ -302,35 +263,16 @@ static int hda_link_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w) struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct sof_dai_private_data *private; - struct sof_ipc_dai_config *config; - struct snd_sof_dai *sof_dai; - struct sof_ipc_reply reply; - int ret; - - sof_dai = swidget->private; - - if (!sof_dai || !sof_dai->private) { - dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name); - return -EINVAL; - } + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + int ret = 0; - private = sof_dai->private; - if (!private->dai_config) { - dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name); - return -EINVAL; + if (tplg_ops->dai_config) { + ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL); + if (ret < 0) + dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__, + w->name); } - config = &private->dai_config[sof_dai->current_config]; - - /* set PAUSE command flag */ - config->flags = FIELD_PREP(SOF_DAI_CONFIG_FLAGS_CMD_MASK, SOF_DAI_CONFIG_FLAGS_PAUSE); - - ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size, - &reply, sizeof(reply)); - if (ret < 0) - dev_err(sdev->dev, "DAI config for %s failed during pause push\n", w->name); - return ret; } @@ -470,30 +412,17 @@ struct ssp_dai_dma_data { static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, bool setup) { - struct snd_soc_component *component; - struct snd_sof_widget *swidget; struct snd_soc_dapm_widget *w; - struct sof_ipc_fw_version *v; - struct snd_sof_dev *sdev; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) w = dai->playback_widget; else w = dai->capture_widget; - swidget = w->dobj.private; - component = swidget->scomp; - sdev = snd_soc_component_get_drvdata(component); - v = &sdev->fw_ready.version; - - /* DAI_CONFIG IPC during hw_params is not supported in older firmware */ - if (v->abi_version < SOF_ABI_VER(3, 18, 0)) - return 0; - if (setup) - return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE); + return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL); - return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); + return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL); } static int ssp_dai_startup(struct snd_pcm_substream *substream, diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index 7403b9848a56..019f8d6b91d4 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -41,114 +41,68 @@ #define EXCEPT_MAX_HDR_SIZE 0x400 #define HDA_EXT_ROM_STATUS_SIZE 8 -int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags) +int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, unsigned int quirk_flags, + struct snd_sof_dai_config_data *data) { struct snd_sof_widget *swidget = w->dobj.private; struct snd_soc_component *component = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); - struct sof_ipc_dai_config *config; - struct sof_dai_private_data *private; - struct snd_sof_dai *sof_dai; - struct sof_ipc_reply reply; + const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg; + struct snd_sof_dai *sof_dai = swidget->private; int ret; - sof_dai = swidget->private; - - if (!sof_dai || !sof_dai->private) { - dev_err(sdev->dev, "%s: No private data for DAI %s\n", __func__, w->name); - return -EINVAL; - } - - private = sof_dai->private; - if (!private->dai_config) { - dev_err(sdev->dev, "%s: No config for DAI %s\n", __func__, w->name); + if (!sof_dai) { + dev_err(sdev->dev, "%s: No DAI for DAI widget %s\n", __func__, w->name); return -EINVAL; } - /* DAI already configured, reset it before reconfiguring it */ - if (sof_dai->configured) { - ret = hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE); - if (ret < 0) - return ret; - } - - config = &private->dai_config[sof_dai->current_config]; - - /* - * For static pipelines, the DAI widget would already be set up and calling - * sof_widget_setup() simply returns without doing anything. - * For dynamic pipelines, the DAI widget will be set up now. - */ - ret = sof_widget_setup(sdev, swidget); - if (ret < 0) { - dev_err(sdev->dev, "error: failed setting up DAI widget %s\n", w->name); - return ret; - } + if (tplg_o |
