Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Add support for DSP volume controls

Merge series from Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>:

Some devices like DMIC don't expose native controls or need volume limit
due to possible HW damage. Add support for volume controls allowing to
change volume level in DSP. Maximum volume level is imposed by the
topology file which defines given path.

+336 -1
+4
include/uapi/sound/intel/avs/tokens.h
··· 108 108 AVS_TKN_MOD_CORE_ID_U8 = 1704, 109 109 AVS_TKN_MOD_PROC_DOMAIN_U8 = 1705, 110 110 AVS_TKN_MOD_MODCFG_EXT_ID_U32 = 1706, 111 + AVS_TKN_MOD_KCONTROL_ID_U32 = 1707, 111 112 112 113 /* struct avs_tplg_path_template */ 113 114 AVS_TKN_PATH_TMPL_ID_U32 = 1801, ··· 122 121 AVS_TKN_PIN_FMT_INDEX_U32 = 2201, 123 122 AVS_TKN_PIN_FMT_IOBS_U32 = 2202, 124 123 AVS_TKN_PIN_FMT_AFMT_ID_U32 = 2203, 124 + 125 + /* struct avs_tplg_kcontrol */ 126 + AVS_TKN_KCONTROL_ID_U32 = 2301, 125 127 }; 126 128 127 129 #endif
+1 -1
sound/soc/intel/avs/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 3 3 snd-soc-avs-objs := dsp.o ipc.o messages.o utils.o core.o loader.o \ 4 - topology.o path.o pcm.o board_selection.o 4 + topology.o path.o pcm.o board_selection.o control.o 5 5 snd-soc-avs-objs += cldma.o 6 6 snd-soc-avs-objs += skl.o apl.o 7 7
+105
sound/soc/intel/avs/control.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // 3 + // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4 + // 5 + // Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 6 + // Cezary Rojewski <cezary.rojewski@intel.com> 7 + // 8 + 9 + #include <sound/soc.h> 10 + #include "avs.h" 11 + #include "control.h" 12 + #include "messages.h" 13 + #include "path.h" 14 + 15 + static struct avs_dev *avs_get_kcontrol_adev(struct snd_kcontrol *kcontrol) 16 + { 17 + struct snd_soc_dapm_widget *w; 18 + 19 + w = snd_soc_dapm_kcontrol_widget(kcontrol); 20 + 21 + return to_avs_dev(w->dapm->component->dev); 22 + } 23 + 24 + static struct avs_path_module *avs_get_kcontrol_module(struct avs_dev *adev, u32 id) 25 + { 26 + struct avs_path *path; 27 + struct avs_path_pipeline *ppl; 28 + struct avs_path_module *mod; 29 + 30 + list_for_each_entry(path, &adev->path_list, node) 31 + list_for_each_entry(ppl, &path->ppl_list, node) 32 + list_for_each_entry(mod, &ppl->mod_list, node) 33 + if (mod->template->ctl_id && mod->template->ctl_id == id) 34 + return mod; 35 + 36 + return NULL; 37 + } 38 + 39 + int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 40 + { 41 + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 42 + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; 43 + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); 44 + struct avs_volume_cfg *dspvols = NULL; 45 + struct avs_path_module *active_module; 46 + size_t num_dspvols; 47 + int ret = 0; 48 + 49 + /* prevent access to modules while path is being constructed */ 50 + mutex_lock(&adev->path_mutex); 51 + 52 + active_module = avs_get_kcontrol_module(adev, ctl_data->id); 53 + if (active_module) { 54 + ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, 55 + active_module->instance_id, &dspvols, 56 + &num_dspvols); 57 + if (!ret) 58 + ucontrol->value.integer.value[0] = dspvols[0].target_volume; 59 + 60 + ret = AVS_IPC_RET(ret); 61 + kfree(dspvols); 62 + } else { 63 + ucontrol->value.integer.value[0] = ctl_data->volume; 64 + } 65 + 66 + mutex_unlock(&adev->path_mutex); 67 + return ret; 68 + } 69 + 70 + int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 71 + { 72 + struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; 73 + struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; 74 + struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); 75 + long *volume = &ctl_data->volume; 76 + struct avs_path_module *active_module; 77 + struct avs_volume_cfg dspvol = {0}; 78 + long ctlvol = ucontrol->value.integer.value[0]; 79 + int ret = 0, changed = 0; 80 + 81 + if (ctlvol < 0 || ctlvol > mc->max) 82 + return -EINVAL; 83 + 84 + /* prevent access to modules while path is being constructed */ 85 + mutex_lock(&adev->path_mutex); 86 + 87 + if (*volume != ctlvol) { 88 + *volume = ctlvol; 89 + changed = 1; 90 + } 91 + 92 + active_module = avs_get_kcontrol_module(adev, ctl_data->id); 93 + if (active_module) { 94 + dspvol.channel_id = AVS_ALL_CHANNELS_MASK; 95 + dspvol.target_volume = *volume; 96 + 97 + ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id, 98 + active_module->instance_id, &dspvol); 99 + ret = AVS_IPC_RET(ret); 100 + } 101 + 102 + mutex_unlock(&adev->path_mutex); 103 + 104 + return ret ? ret : changed; 105 + }
+23
sound/soc/intel/avs/control.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4 + * 5 + * Authors: Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 6 + * Cezary Rojewski <cezary.rojewski@intel.com> 7 + */ 8 + 9 + #ifndef __SOUND_SOC_INTEL_AVS_CTRL_H 10 + #define __SOUND_SOC_INTEL_AVS_CTRL_H 11 + 12 + #include <sound/control.h> 13 + 14 + struct avs_control_data { 15 + u32 id; 16 + 17 + long volume; 18 + }; 19 + 20 + int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); 21 + int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); 22 + 23 + #endif
+29
sound/soc/intel/avs/messages.c
··· 702 702 (u8 *)&cpr_fmt, sizeof(cpr_fmt)); 703 703 } 704 704 705 + int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, 706 + struct avs_volume_cfg *vol) 707 + { 708 + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol, 709 + sizeof(*vol)); 710 + } 711 + 712 + int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, 713 + struct avs_volume_cfg **vols, size_t *num_vols) 714 + { 715 + size_t payload_size; 716 + u8 *payload; 717 + int ret; 718 + 719 + ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, NULL, 0, 720 + &payload, &payload_size); 721 + if (ret) 722 + return ret; 723 + 724 + /* Non-zero payload expected for PEAKVOL_VOLUME. */ 725 + if (!payload_size) 726 + return -EREMOTEIO; 727 + 728 + *vols = (struct avs_volume_cfg *)payload; 729 + *num_vols = payload_size / sizeof(**vols); 730 + 731 + return 0; 732 + } 733 + 705 734 #ifdef CONFIG_DEBUG_FS 706 735 int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) 707 736 {
+33
sound/soc/intel/avs/messages.h
··· 561 561 #define AVS_COPIER_MOD_UUID \ 562 562 GUID_INIT(0x9BA00C83, 0xCA12, 0x4A83, 0x94, 0x3C, 0x1F, 0xA2, 0xE8, 0x2F, 0x9D, 0xDA) 563 563 564 + #define AVS_PEAKVOL_MOD_UUID \ 565 + GUID_INIT(0x8A171323, 0x94A3, 0x4E1D, 0xAF, 0xE9, 0xFE, 0x5D, 0xBA, 0xa4, 0xC3, 0x93) 566 + 567 + #define AVS_GAIN_MOD_UUID \ 568 + GUID_INIT(0x61BCA9A8, 0x18D0, 0x4A18, 0x8E, 0x7B, 0x26, 0x39, 0x21, 0x98, 0x04, 0xB7) 569 + 564 570 #define AVS_KPBUFF_MOD_UUID \ 565 571 GUID_INIT(0xA8A0CB32, 0x4A77, 0x4DB1, 0x85, 0xC7, 0x53, 0xD7, 0xEE, 0x07, 0xBC, 0xE6) 566 572 ··· 735 729 struct avs_copier_gtw_cfg gtw_cfg; 736 730 } __packed; 737 731 732 + struct avs_volume_cfg { 733 + u32 channel_id; 734 + u32 target_volume; 735 + u32 curve_type; 736 + u32 reserved; /* alignment */ 737 + u64 curve_duration; 738 + } __packed; 739 + 740 + struct avs_peakvol_cfg { 741 + struct avs_modcfg_base base; 742 + struct avs_volume_cfg vols[]; 743 + } __packed; 744 + 738 745 struct avs_micsel_cfg { 739 746 struct avs_modcfg_base base; 740 747 struct avs_audio_format out_fmt; ··· 820 801 u8 instance_id, u32 sink_id, 821 802 const struct avs_audio_format *src_fmt, 822 803 const struct avs_audio_format *sink_fmt); 804 + 805 + enum avs_peakvol_runtime_param { 806 + AVS_PEAKVOL_VOLUME = 0, 807 + }; 808 + 809 + enum avs_audio_curve_type { 810 + AVS_AUDIO_CURVE_NONE = 0, 811 + AVS_AUDIO_CURVE_WINDOWS_FADE = 1, 812 + }; 813 + 814 + int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, 815 + struct avs_volume_cfg *vol); 816 + int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, 817 + struct avs_volume_cfg **vols, size_t *num_vols); 823 818 824 819 #define AVS_PROBE_INST_ID 0 825 820
+62
sound/soc/intel/avs/path.c
··· 10 10 #include <sound/pcm_params.h> 11 11 #include <sound/soc.h> 12 12 #include "avs.h" 13 + #include "control.h" 13 14 #include "path.h" 14 15 #include "topology.h" 15 16 ··· 265 264 return ret; 266 265 } 267 266 267 + static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod) 268 + { 269 + struct avs_tplg_module *t = mod->template; 270 + struct avs_tplg_path_template *path_tmpl; 271 + struct snd_soc_dapm_widget *w; 272 + int i; 273 + 274 + path_tmpl = t->owner->owner->owner; 275 + w = path_tmpl->w; 276 + 277 + for (i = 0; i < w->num_kcontrols; i++) { 278 + struct avs_control_data *ctl_data; 279 + struct soc_mixer_control *mc; 280 + 281 + mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value; 282 + ctl_data = (struct avs_control_data *)mc->dobj.private; 283 + if (ctl_data->id == t->ctl_id) 284 + return ctl_data; 285 + } 286 + 287 + return NULL; 288 + } 289 + 290 + static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) 291 + { 292 + struct avs_tplg_module *t = mod->template; 293 + struct avs_control_data *ctl_data; 294 + struct avs_peakvol_cfg *cfg; 295 + int volume = S32_MAX; 296 + size_t size; 297 + int ret; 298 + 299 + ctl_data = avs_get_module_control(mod); 300 + if (ctl_data) 301 + volume = ctl_data->volume; 302 + 303 + /* As 2+ channels controls are unsupported, have a single block for all channels. */ 304 + size = struct_size(cfg, vols, 1); 305 + cfg = kzalloc(size, GFP_KERNEL); 306 + if (!cfg) 307 + return -ENOMEM; 308 + 309 + cfg->base.cpc = t->cfg_base->cpc; 310 + cfg->base.ibs = t->cfg_base->ibs; 311 + cfg->base.obs = t->cfg_base->obs; 312 + cfg->base.is_pages = t->cfg_base->is_pages; 313 + cfg->base.audio_fmt = *t->in_fmt; 314 + cfg->vols[0].target_volume = volume; 315 + cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK; 316 + cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE; 317 + cfg->vols[0].curve_duration = 0; 318 + 319 + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, 320 + t->domain, cfg, size, &mod->instance_id); 321 + 322 + kfree(cfg); 323 + return ret; 324 + } 325 + 268 326 static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod) 269 327 { 270 328 struct avs_tplg_module *t = mod->template; ··· 525 465 { &AVS_MIXOUT_MOD_UUID, avs_modbase_create }, 526 466 { &AVS_KPBUFF_MOD_UUID, avs_modbase_create }, 527 467 { &AVS_COPIER_MOD_UUID, avs_copier_create }, 468 + { &AVS_PEAKVOL_MOD_UUID, avs_peakvol_create }, 469 + { &AVS_GAIN_MOD_UUID, avs_peakvol_create }, 528 470 { &AVS_MICSEL_MOD_UUID, avs_micsel_create }, 529 471 { &AVS_MUX_MOD_UUID, avs_mux_create }, 530 472 { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create },
+76
sound/soc/intel/avs/topology.c
··· 13 13 #include <sound/soc-topology.h> 14 14 #include <uapi/sound/intel/avs/tokens.h> 15 15 #include "avs.h" 16 + #include "control.h" 16 17 #include "topology.h" 17 18 18 19 /* Get pointer to vendor array at the specified offset. */ ··· 1071 1070 .offset = offsetof(struct avs_tplg_module, cfg_ext), 1072 1071 .parse = avs_parse_modcfg_ext_ptr, 1073 1072 }, 1073 + { 1074 + .token = AVS_TKN_MOD_KCONTROL_ID_U32, 1075 + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, 1076 + .offset = offsetof(struct avs_tplg_module, ctl_id), 1077 + .parse = avs_parse_byte_token, 1078 + }, 1074 1079 }; 1075 1080 1076 1081 static struct avs_tplg_module * ··· 1442 1435 return 0; 1443 1436 } 1444 1437 1438 + static int avs_widget_ready(struct snd_soc_component *comp, int index, 1439 + struct snd_soc_dapm_widget *w, 1440 + struct snd_soc_tplg_dapm_widget *dw) 1441 + { 1442 + struct avs_tplg_path_template *template = w->priv; 1443 + 1444 + template->w = w; 1445 + return 0; 1446 + } 1447 + 1445 1448 static int avs_dai_load(struct snd_soc_component *comp, int index, 1446 1449 struct snd_soc_dai_driver *dai_drv, struct snd_soc_tplg_pcm *pcm, 1447 1450 struct snd_soc_dai *dai) ··· 1603 1586 return avs_tplg_parse_bindings(comp, tuples, remaining); 1604 1587 } 1605 1588 1589 + #define AVS_CONTROL_OPS_VOLUME 257 1590 + 1591 + static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { 1592 + { 1593 + .id = AVS_CONTROL_OPS_VOLUME, 1594 + .get = avs_control_volume_get, 1595 + .put = avs_control_volume_put, 1596 + }, 1597 + }; 1598 + 1599 + static const struct avs_tplg_token_parser control_parsers[] = { 1600 + { 1601 + .token = AVS_TKN_KCONTROL_ID_U32, 1602 + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, 1603 + .offset = offsetof(struct avs_control_data, id), 1604 + .parse = avs_parse_word_token, 1605 + }, 1606 + }; 1607 + 1608 + static int 1609 + avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_new *ctmpl, 1610 + struct snd_soc_tplg_ctl_hdr *hdr) 1611 + { 1612 + struct snd_soc_tplg_vendor_array *tuples; 1613 + struct snd_soc_tplg_mixer_control *tmc; 1614 + struct avs_control_data *ctl_data; 1615 + struct soc_mixer_control *mc; 1616 + size_t block_size; 1617 + int ret; 1618 + 1619 + switch (hdr->type) { 1620 + case SND_SOC_TPLG_TYPE_MIXER: 1621 + tmc = container_of(hdr, typeof(*tmc), hdr); 1622 + tuples = tmc->priv.array; 1623 + block_size = le32_to_cpu(tmc->priv.size); 1624 + break; 1625 + default: 1626 + return -EINVAL; 1627 + } 1628 + 1629 + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); 1630 + if (!ctl_data) 1631 + return -ENOMEM; 1632 + 1633 + ret = parse_dictionary_entries(comp, tuples, block_size, ctl_data, 1, sizeof(*ctl_data), 1634 + AVS_TKN_KCONTROL_ID_U32, control_parsers, 1635 + ARRAY_SIZE(control_parsers)); 1636 + if (ret) 1637 + return ret; 1638 + 1639 + mc = (struct soc_mixer_control *)ctmpl->private_value; 1640 + mc->dobj.private = ctl_data; 1641 + return 0; 1642 + } 1643 + 1606 1644 static struct snd_soc_tplg_ops avs_tplg_ops = { 1645 + .io_ops = avs_control_ops, 1646 + .io_ops_count = ARRAY_SIZE(avs_control_ops), 1647 + .control_load = avs_control_load, 1607 1648 .dapm_route_load = avs_route_load, 1608 1649 .widget_load = avs_widget_load, 1650 + .widget_ready = avs_widget_ready, 1609 1651 .dai_load = avs_dai_load, 1610 1652 .link_load = avs_link_load, 1611 1653 .manifest = avs_manifest,
+3
sound/soc/intel/avs/topology.h
··· 138 138 struct avs_tplg_path_template { 139 139 u32 id; 140 140 141 + struct snd_soc_dapm_widget *w; 142 + 141 143 struct list_head path_list; 142 144 143 145 struct avs_tplg *owner; ··· 182 180 u8 core_id; 183 181 u8 domain; 184 182 struct avs_tplg_modcfg_ext *cfg_ext; 183 + u32 ctl_id; 185 184 186 185 struct avs_tplg_pipeline *owner; 187 186 /* Pipeline modules management. */