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

Configure Feed

Select the types of activity you want to include in your feed.

ASoC: SOF: ipc4-topology: Add support for effect

Merge series from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:

The following series will add support for IPC4 process modules as effect
widgets. We can cover wide range of modules as a generic process or
effect module, the patches will lay down the fundation and the generic
code to handle them.

At initialization time process modules can receive additional
information on top of the base_cfg, which is defined as base_cfg_ext, an
extension for the base configuration struct. Other parameters or blobs
for these modules are sent as a separate message via
LARGE_CONFIG message, which is handled by the existing bytes control support.

+396 -16
+351 -16
sound/soc/sof/ipc4-topology.c
··· 6 6 // Copyright(c) 2022 Intel Corporation. All rights reserved. 7 7 // 8 8 // 9 + #include <linux/bitfield.h> 9 10 #include <uapi/sound/sof/tokens.h> 10 11 #include <sound/pcm_params.h> 11 12 #include <sound/sof/ext_manifest4.h> ··· 166 165 } 167 166 } 168 167 168 + static const struct sof_ipc4_audio_format * 169 + sof_ipc4_get_input_pin_audio_fmt(struct snd_sof_widget *swidget, int pin_index) 170 + { 171 + struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 172 + struct sof_ipc4_process *process; 173 + int i; 174 + 175 + if (swidget->id != snd_soc_dapm_effect) { 176 + struct sof_ipc4_base_module_cfg *base = swidget->private; 177 + 178 + /* For non-process modules, base module config format is used for all input pins */ 179 + return &base->audio_fmt; 180 + } 181 + 182 + process = swidget->private; 183 + base_cfg_ext = process->base_config_ext; 184 + 185 + /* 186 + * If there are multiple input formats available for a pin, the first available format 187 + * is chosen. 188 + */ 189 + for (i = 0; i < base_cfg_ext->num_input_pin_fmts; i++) { 190 + struct sof_ipc4_pin_format *pin_format = &base_cfg_ext->pin_formats[i]; 191 + 192 + if (pin_format->pin_index == pin_index) 193 + return &pin_format->audio_fmt; 194 + } 195 + 196 + return NULL; 197 + } 198 + 169 199 /** 170 200 * sof_ipc4_get_audio_fmt - get available audio formats from swidget->tuples 171 201 * @scomp: pointer to pointer to SOC component ··· 351 319 msg->extension |= SOF_IPC4_MOD_EXT_DOMAIN(type); 352 320 353 321 return 0; 322 + } 323 + 324 + static void sof_ipc4_widget_update_kcontrol_module_id(struct snd_sof_widget *swidget) 325 + { 326 + struct snd_soc_component *scomp = swidget->scomp; 327 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 328 + struct sof_ipc4_fw_module *fw_module = swidget->module_info; 329 + struct snd_sof_control *scontrol; 330 + 331 + /* update module ID for all kcontrols for this widget */ 332 + list_for_each_entry(scontrol, &sdev->kcontrol_list, list) { 333 + if (scontrol->comp_id == swidget->comp_id) { 334 + struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 335 + struct sof_ipc4_msg *msg = &cdata->msg; 336 + 337 + msg->primary |= fw_module->man4_module_entry.id; 338 + } 339 + } 354 340 } 355 341 356 342 static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget) ··· 678 628 static int sof_ipc4_widget_setup_comp_pga(struct snd_sof_widget *swidget) 679 629 { 680 630 struct snd_soc_component *scomp = swidget->scomp; 681 - struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 682 - struct sof_ipc4_fw_module *fw_module; 683 - struct snd_sof_control *scontrol; 684 631 struct sof_ipc4_gain *gain; 685 632 int ret; 686 633 ··· 710 663 if (ret) 711 664 goto err; 712 665 713 - fw_module = swidget->module_info; 714 - 715 - /* update module ID for all kcontrols for this widget */ 716 - list_for_each_entry(scontrol, &sdev->kcontrol_list, list) 717 - if (scontrol->comp_id == swidget->comp_id) { 718 - struct sof_ipc4_control_data *cdata = scontrol->ipc_control_data; 719 - struct sof_ipc4_msg *msg = &cdata->msg; 720 - 721 - msg->primary |= fw_module->man4_module_entry.id; 722 - } 666 + sof_ipc4_widget_update_kcontrol_module_id(swidget); 723 667 724 668 return 0; 725 669 err: ··· 826 788 swidget->private = NULL; 827 789 } 828 790 791 + /* 792 + * Add the process modules support. The process modules are defined as snd_soc_dapm_effect modules. 793 + */ 794 + static int sof_ipc4_widget_setup_comp_process(struct snd_sof_widget *swidget) 795 + { 796 + struct snd_soc_component *scomp = swidget->scomp; 797 + struct sof_ipc4_fw_module *fw_module; 798 + struct sof_ipc4_process *process; 799 + void *cfg; 800 + int ret; 801 + 802 + process = kzalloc(sizeof(*process), GFP_KERNEL); 803 + if (!process) 804 + return -ENOMEM; 805 + 806 + swidget->private = process; 807 + 808 + ret = sof_ipc4_get_audio_fmt(scomp, swidget, &process->available_fmt, 809 + &process->base_config); 810 + if (ret) 811 + goto err; 812 + 813 + ret = sof_ipc4_widget_setup_msg(swidget, &process->msg); 814 + if (ret) 815 + goto err; 816 + 817 + /* parse process init module payload config type from module info */ 818 + fw_module = swidget->module_info; 819 + process->init_config = FIELD_GET(SOF_IPC4_MODULE_INIT_CONFIG_MASK, 820 + fw_module->man4_module_entry.type); 821 + 822 + process->ipc_config_size = sizeof(struct sof_ipc4_base_module_cfg); 823 + 824 + /* allocate memory for base config extension if needed */ 825 + if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 826 + struct sof_ipc4_base_module_cfg_ext *base_cfg_ext; 827 + u32 ext_size = struct_size(base_cfg_ext, pin_formats, 828 + swidget->num_input_pins + swidget->num_output_pins); 829 + 830 + base_cfg_ext = kzalloc(ext_size, GFP_KERNEL); 831 + if (!base_cfg_ext) { 832 + ret = -ENOMEM; 833 + goto free_available_fmt; 834 + } 835 + 836 + base_cfg_ext->num_input_pin_fmts = swidget->num_input_pins; 837 + base_cfg_ext->num_output_pin_fmts = swidget->num_output_pins; 838 + process->base_config_ext = base_cfg_ext; 839 + process->base_config_ext_size = ext_size; 840 + process->ipc_config_size += ext_size; 841 + } 842 + 843 + cfg = kzalloc(process->ipc_config_size, GFP_KERNEL); 844 + if (!cfg) { 845 + ret = -ENOMEM; 846 + goto free_base_cfg_ext; 847 + } 848 + 849 + process->ipc_config_data = cfg; 850 + 851 + sof_ipc4_widget_update_kcontrol_module_id(swidget); 852 + 853 + return 0; 854 + free_base_cfg_ext: 855 + kfree(process->base_config_ext); 856 + process->base_config_ext = NULL; 857 + free_available_fmt: 858 + sof_ipc4_free_audio_fmt(&process->available_fmt); 859 + err: 860 + kfree(process); 861 + swidget->private = NULL; 862 + return ret; 863 + } 864 + 865 + static void sof_ipc4_widget_free_comp_process(struct snd_sof_widget *swidget) 866 + { 867 + struct sof_ipc4_process *process = swidget->private; 868 + 869 + if (!process) 870 + return; 871 + 872 + kfree(process->ipc_config_data); 873 + kfree(process->base_config_ext); 874 + sof_ipc4_free_audio_fmt(&process->available_fmt); 875 + kfree(swidget->private); 876 + swidget->private = NULL; 877 + } 878 + 829 879 static void 830 880 sof_ipc4_update_pipeline_mem_usage(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget, 831 881 struct sof_ipc4_base_module_cfg *base_config) ··· 961 835 swidget->widget->name); 962 836 return swidget->instance_id; 963 837 } 838 + 839 + return 0; 840 + } 841 + 842 + /* update hw_params based on the audio stream format */ 843 + static int sof_ipc4_update_hw_params(struct snd_sof_dev *sdev, struct snd_pcm_hw_params *params, 844 + struct sof_ipc4_audio_format *fmt) 845 + { 846 + snd_pcm_format_t snd_fmt; 847 + struct snd_interval *i; 848 + struct snd_mask *m; 849 + int valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(fmt->fmt_cfg); 850 + unsigned int channels, rate; 851 + 852 + switch (valid_bits) { 853 + case 16: 854 + snd_fmt = SNDRV_PCM_FORMAT_S16_LE; 855 + break; 856 + case 24: 857 + snd_fmt = SNDRV_PCM_FORMAT_S24_LE; 858 + break; 859 + case 32: 860 + snd_fmt = SNDRV_PCM_FORMAT_S32_LE; 861 + break; 862 + default: 863 + dev_err(sdev->dev, "invalid PCM valid_bits %d\n", valid_bits); 864 + return -EINVAL; 865 + } 866 + 867 + m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 868 + snd_mask_none(m); 869 + snd_mask_set_format(m, snd_fmt); 870 + 871 + rate = fmt->sampling_frequency; 872 + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 873 + i->min = rate; 874 + i->max = rate; 875 + 876 + channels = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(fmt->fmt_cfg); 877 + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 878 + i->min = channels; 879 + i->max = channels; 964 880 965 881 return 0; 966 882 } ··· 1665 1497 return 0; 1666 1498 } 1667 1499 1500 + static int 1501 + sof_ipc4_process_set_pin_formats(struct snd_sof_widget *swidget, int pin_type) 1502 + { 1503 + struct sof_ipc4_process *process = swidget->private; 1504 + struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 1505 + struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 1506 + struct sof_ipc4_pin_format *pin_format, *format_list_to_search; 1507 + struct snd_soc_component *scomp = swidget->scomp; 1508 + int num_pins, format_list_count; 1509 + int pin_format_offset = 0; 1510 + int i, j; 1511 + 1512 + /* set number of pins, offset of pin format and format list to search based on pin type */ 1513 + if (pin_type == SOF_PIN_TYPE_INPUT) { 1514 + num_pins = swidget->num_input_pins; 1515 + format_list_to_search = available_fmt->input_pin_fmts; 1516 + format_list_count = available_fmt->num_input_formats; 1517 + } else { 1518 + num_pins = swidget->num_output_pins; 1519 + pin_format_offset = swidget->num_input_pins; 1520 + format_list_to_search = available_fmt->output_pin_fmts; 1521 + format_list_count = available_fmt->num_output_formats; 1522 + } 1523 + 1524 + for (i = pin_format_offset; i < num_pins + pin_format_offset; i++) { 1525 + pin_format = &base_cfg_ext->pin_formats[i]; 1526 + 1527 + /* Pin 0 audio formats are derived from the base config input/output format */ 1528 + if (i == pin_format_offset) { 1529 + if (pin_type == SOF_PIN_TYPE_INPUT) { 1530 + pin_format->buffer_size = process->base_config.ibs; 1531 + pin_format->audio_fmt = process->base_config.audio_fmt; 1532 + } else { 1533 + pin_format->buffer_size = process->base_config.obs; 1534 + pin_format->audio_fmt = process->output_format; 1535 + } 1536 + continue; 1537 + } 1538 + 1539 + /* 1540 + * For all other pins, find the pin formats from those set in topology. If there 1541 + * is more than one format specified for a pin, this will pick the first available 1542 + * one. 1543 + */ 1544 + for (j = 0; j < format_list_count; j++) { 1545 + struct sof_ipc4_pin_format *pin_format_item = &format_list_to_search[j]; 1546 + 1547 + if (pin_format_item->pin_index == i - pin_format_offset) { 1548 + *pin_format = *pin_format_item; 1549 + break; 1550 + } 1551 + } 1552 + 1553 + if (j == format_list_count) { 1554 + dev_err(scomp->dev, "%s pin %d format not found for %s\n", 1555 + (pin_type == SOF_PIN_TYPE_INPUT) ? "input" : "output", 1556 + i - pin_format_offset, swidget->widget->name); 1557 + return -EINVAL; 1558 + } 1559 + } 1560 + 1561 + return 0; 1562 + } 1563 + 1564 + static int sof_ipc4_process_add_base_cfg_extn(struct snd_sof_widget *swidget) 1565 + { 1566 + int ret, i; 1567 + 1568 + /* copy input and output pin formats */ 1569 + for (i = 0; i <= SOF_PIN_TYPE_OUTPUT; i++) { 1570 + ret = sof_ipc4_process_set_pin_formats(swidget, i); 1571 + if (ret < 0) 1572 + return ret; 1573 + } 1574 + 1575 + return 0; 1576 + } 1577 + 1578 + static int sof_ipc4_prepare_process_module(struct snd_sof_widget *swidget, 1579 + struct snd_pcm_hw_params *fe_params, 1580 + struct snd_sof_platform_stream_params *platform_params, 1581 + struct snd_pcm_hw_params *pipeline_params, int dir) 1582 + { 1583 + struct snd_soc_component *scomp = swidget->scomp; 1584 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); 1585 + struct sof_ipc4_process *process = swidget->private; 1586 + struct sof_ipc4_available_audio_format *available_fmt = &process->available_fmt; 1587 + void *cfg = process->ipc_config_data; 1588 + int ret; 1589 + 1590 + ret = sof_ipc4_init_audio_fmt(sdev, swidget, &process->base_config, 1591 + pipeline_params, available_fmt, 1592 + available_fmt->input_pin_fmts, 1593 + available_fmt->num_input_formats); 1594 + if (ret < 0) 1595 + return ret; 1596 + 1597 + /* copy Pin 0 output format */ 1598 + if (available_fmt->num_output_formats && ret < available_fmt->num_output_formats && 1599 + !available_fmt->output_pin_fmts[ret].pin_index) { 1600 + memcpy(&process->output_format, &available_fmt->output_pin_fmts[ret].audio_fmt, 1601 + sizeof(struct sof_ipc4_audio_format)); 1602 + 1603 + /* modify the pipeline params with the pin 0 output format */ 1604 + ret = sof_ipc4_update_hw_params(sdev, pipeline_params, &process->output_format); 1605 + if (ret) 1606 + return ret; 1607 + } 1608 + 1609 + /* update pipeline memory usage */ 1610 + sof_ipc4_update_pipeline_mem_usage(sdev, swidget, &process->base_config); 1611 + 1612 + /* ipc_config_data is composed of the base_config followed by an optional extension */ 1613 + memcpy(cfg, &process->base_config, sizeof(struct sof_ipc4_base_module_cfg)); 1614 + cfg += sizeof(struct sof_ipc4_base_module_cfg); 1615 + 1616 + if (process->init_config == SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT) { 1617 + struct sof_ipc4_base_module_cfg_ext *base_cfg_ext = process->base_config_ext; 1618 + 1619 + ret = sof_ipc4_process_add_base_cfg_extn(swidget); 1620 + if (ret < 0) 1621 + return ret; 1622 + 1623 + memcpy(cfg, base_cfg_ext, process->base_config_ext_size); 1624 + } 1625 + 1626 + return 0; 1627 + } 1628 + 1668 1629 static int sof_ipc4_control_load_volume(struct snd_sof_dev *sdev, struct snd_sof_control *scontrol) 1669 1630 { 1670 1631 struct sof_ipc4_control_data *control_data; ··· 1992 1695 msg = &src->msg; 1993 1696 break; 1994 1697 } 1698 + case snd_soc_dapm_effect: 1699 + { 1700 + struct sof_ipc4_process *process = swidget->private; 1701 + 1702 + if (!process->ipc_config_size) { 1703 + dev_err(sdev->dev, "module %s has no config data!\n", 1704 + swidget->widget->name); 1705 + return -EINVAL; 1706 + } 1707 + 1708 + ipc_size = process->ipc_config_size; 1709 + ipc_data = process->ipc_config_data; 1710 + 1711 + msg = &process->msg; 1712 + break; 1713 + } 1995 1714 default: 1996 1715 dev_err(sdev->dev, "widget type %d not supported", swidget->id); 1997 1716 return -EINVAL; ··· 2177 1864 struct snd_sof_widget *sink_widget, 2178 1865 int sink_id) 2179 1866 { 2180 - struct sof_ipc4_base_module_cfg *sink_config = sink_widget->private; 2181 - struct sof_ipc4_base_module_cfg *src_config; 2182 1867 struct sof_ipc4_copier_config_set_sink_format format; 1868 + struct sof_ipc4_base_module_cfg *src_config; 1869 + const struct sof_ipc4_audio_format *pin_fmt; 2183 1870 struct sof_ipc4_fw_module *fw_module; 2184 1871 struct sof_ipc4_msg msg = {{ 0 }}; 2185 1872 u32 header, extension; ··· 2199 1886 2200 1887 format.sink_id = sink_id; 2201 1888 memcpy(&format.source_fmt, &src_config->audio_fmt, sizeof(format.source_fmt)); 2202 - memcpy(&format.sink_fmt, &sink_config->audio_fmt, sizeof(format.sink_fmt)); 1889 + 1890 + pin_fmt = sof_ipc4_get_input_pin_audio_fmt(sink_widget, sink_id); 1891 + if (!pin_fmt) { 1892 + dev_err(sdev->dev, "Unable to get pin %d format for %s", 1893 + sink_id, sink_widget->widget->name); 1894 + return -EINVAL; 1895 + } 1896 + 1897 + memcpy(&format.sink_fmt, pin_fmt, sizeof(format.sink_fmt)); 1898 + 2203 1899 msg.data_size = sizeof(format); 2204 1900 msg.data_ptr = &format; 2205 1901 ··· 2622 2300 SOF_COMP_EXT_TOKENS, 2623 2301 }; 2624 2302 2303 + static enum sof_tokens process_token_list[] = { 2304 + SOF_COMP_TOKENS, 2305 + SOF_AUDIO_FMT_NUM_TOKENS, 2306 + SOF_IN_AUDIO_FORMAT_TOKENS, 2307 + SOF_OUT_AUDIO_FORMAT_TOKENS, 2308 + SOF_COMP_EXT_TOKENS, 2309 + }; 2310 + 2625 2311 static const struct sof_ipc_tplg_widget_ops tplg_ipc4_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = { 2626 2312 [snd_soc_dapm_aif_in] = {sof_ipc4_widget_setup_pcm, sof_ipc4_widget_free_comp_pcm, 2627 2313 common_copier_token_list, ARRAY_SIZE(common_copier_token_list), ··· 2666 2336 [snd_soc_dapm_src] = {sof_ipc4_widget_setup_comp_src, sof_ipc4_widget_free_comp_src, 2667 2337 src_token_list, ARRAY_SIZE(src_token_list), 2668 2338 NULL, sof_ipc4_prepare_src_module, 2339 + NULL}, 2340 + [snd_soc_dapm_effect] = {sof_ipc4_widget_setup_comp_process, 2341 + sof_ipc4_widget_free_comp_process, 2342 + process_token_list, ARRAY_SIZE(process_token_list), 2343 + NULL, sof_ipc4_prepare_process_module, 2669 2344 NULL}, 2670 2345 }; 2671 2346
+45
sound/soc/sof/ipc4-topology.h
··· 26 26 #define SOF_IPC4_MODULE_LL BIT(5) 27 27 #define SOF_IPC4_MODULE_DP BIT(6) 28 28 #define SOF_IPC4_MODULE_LIB_CODE BIT(7) 29 + #define SOF_IPC4_MODULE_INIT_CONFIG_MASK GENMASK(11, 8) 30 + 31 + #define SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG 0 32 + #define SOF_IPC4_MODULE_INIT_CONFIG_TYPE_BASE_CFG_WITH_EXT 1 29 33 30 34 #define SOF_IPC4_MODULE_INSTANCE_LIST_ITEM_SIZE 12 31 35 #define SOF_IPC4_PIPELINE_OBJECT_SIZE 448 ··· 349 345 uint32_t sink_rate; 350 346 struct sof_ipc4_available_audio_format available_fmt; 351 347 struct sof_ipc4_msg msg; 348 + }; 349 + 350 + /** 351 + * struct sof_ipc4_base_module_cfg_ext - base module config extension containing the pin format 352 + * information for the module. Both @num_input_pin_fmts and @num_output_pin_fmts cannot be 0 for a 353 + * module. 354 + * @num_input_pin_fmts: number of input pin formats in the @pin_formats array 355 + * @num_output_pin_fmts: number of output pin formats in the @pin_formats array 356 + * @reserved: reserved for future use 357 + * @pin_formats: flexible array consisting of @num_input_pin_fmts input pin format items followed 358 + * by @num_output_pin_fmts output pin format items 359 + */ 360 + struct sof_ipc4_base_module_cfg_ext { 361 + u16 num_input_pin_fmts; 362 + u16 num_output_pin_fmts; 363 + u8 reserved[12]; 364 + DECLARE_FLEX_ARRAY(struct sof_ipc4_pin_format, pin_formats); 365 + } __packed; 366 + 367 + /** 368 + * struct sof_ipc4_process - process config data 369 + * @base_config: IPC base config data 370 + * @base_config_ext: Base config extension data for module init 371 + * @output_format: Output audio format 372 + * @available_fmt: Available audio format 373 + * @ipc_config_data: Process module config data 374 + * @ipc_config_size: Size of process module config data 375 + * @msg: IPC4 message struct containing header and data info 376 + * @base_config_ext_size: Size of the base config extension data in bytes 377 + * @init_config: Module init config type (SOF_IPC4_MODULE_INIT_CONFIG_TYPE_*) 378 + */ 379 + struct sof_ipc4_process { 380 + struct sof_ipc4_base_module_cfg base_config; 381 + struct sof_ipc4_base_module_cfg_ext *base_config_ext; 382 + struct sof_ipc4_audio_format output_format; 383 + struct sof_ipc4_available_audio_format available_fmt; 384 + void *ipc_config_data; 385 + uint32_t ipc_config_size; 386 + struct sof_ipc4_msg msg; 387 + u32 base_config_ext_size; 388 + u32 init_config; 352 389 }; 353 390 354 391 #endif