1101 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2021 Intel Corporation4//5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>6// Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>7//8 9#include <linux/acpi.h>10#include <acpi/nhlt.h>11#include <sound/pcm_params.h>12#include <sound/soc.h>13#include "avs.h"14#include "control.h"15#include "path.h"16#include "topology.h"17 18/* Must be called with adev->comp_list_mutex held. */19static struct avs_tplg *20avs_path_find_tplg(struct avs_dev *adev, const char *name)21{22 struct avs_soc_component *acomp;23 24 list_for_each_entry(acomp, &adev->comp_list, node)25 if (!strcmp(acomp->tplg->name, name))26 return acomp->tplg;27 return NULL;28}29 30static struct avs_path_module *31avs_path_find_module(struct avs_path_pipeline *ppl, u32 template_id)32{33 struct avs_path_module *mod;34 35 list_for_each_entry(mod, &ppl->mod_list, node)36 if (mod->template->id == template_id)37 return mod;38 return NULL;39}40 41static struct avs_path_pipeline *42avs_path_find_pipeline(struct avs_path *path, u32 template_id)43{44 struct avs_path_pipeline *ppl;45 46 list_for_each_entry(ppl, &path->ppl_list, node)47 if (ppl->template->id == template_id)48 return ppl;49 return NULL;50}51 52static struct avs_path *53avs_path_find_path(struct avs_dev *adev, const char *name, u32 template_id)54{55 struct avs_tplg_path_template *pos, *template = NULL;56 struct avs_tplg *tplg;57 struct avs_path *path;58 59 tplg = avs_path_find_tplg(adev, name);60 if (!tplg)61 return NULL;62 63 list_for_each_entry(pos, &tplg->path_tmpl_list, node) {64 if (pos->id == template_id) {65 template = pos;66 break;67 }68 }69 if (!template)70 return NULL;71 72 spin_lock(&adev->path_list_lock);73 /* Only one variant of given path template may be instantiated at a time. */74 list_for_each_entry(path, &adev->path_list, node) {75 if (path->template->owner == template) {76 spin_unlock(&adev->path_list_lock);77 return path;78 }79 }80 81 spin_unlock(&adev->path_list_lock);82 return NULL;83}84 85static bool avs_test_hw_params(struct snd_pcm_hw_params *params,86 struct avs_audio_format *fmt)87{88 return (params_rate(params) == fmt->sampling_freq &&89 params_channels(params) == fmt->num_channels &&90 params_physical_width(params) == fmt->bit_depth &&91 snd_pcm_hw_params_bits(params) == fmt->valid_bit_depth);92}93 94static struct avs_tplg_path *95avs_path_find_variant(struct avs_dev *adev,96 struct avs_tplg_path_template *template,97 struct snd_pcm_hw_params *fe_params,98 struct snd_pcm_hw_params *be_params)99{100 struct avs_tplg_path *variant;101 102 list_for_each_entry(variant, &template->path_list, node) {103 dev_dbg(adev->dev, "check FE rate %d chn %d vbd %d bd %d\n",104 variant->fe_fmt->sampling_freq, variant->fe_fmt->num_channels,105 variant->fe_fmt->valid_bit_depth, variant->fe_fmt->bit_depth);106 dev_dbg(adev->dev, "check BE rate %d chn %d vbd %d bd %d\n",107 variant->be_fmt->sampling_freq, variant->be_fmt->num_channels,108 variant->be_fmt->valid_bit_depth, variant->be_fmt->bit_depth);109 110 if (variant->fe_fmt && avs_test_hw_params(fe_params, variant->fe_fmt) &&111 variant->be_fmt && avs_test_hw_params(be_params, variant->be_fmt))112 return variant;113 }114 115 return NULL;116}117 118__maybe_unused119static bool avs_dma_type_is_host(u32 dma_type)120{121 return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||122 dma_type == AVS_DMA_HDA_HOST_INPUT;123}124 125__maybe_unused126static bool avs_dma_type_is_link(u32 dma_type)127{128 return !avs_dma_type_is_host(dma_type);129}130 131__maybe_unused132static bool avs_dma_type_is_output(u32 dma_type)133{134 return dma_type == AVS_DMA_HDA_HOST_OUTPUT ||135 dma_type == AVS_DMA_HDA_LINK_OUTPUT ||136 dma_type == AVS_DMA_I2S_LINK_OUTPUT;137}138 139__maybe_unused140static bool avs_dma_type_is_input(u32 dma_type)141{142 return !avs_dma_type_is_output(dma_type);143}144 145static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod)146{147 struct avs_tplg_module *t = mod->template;148 struct avs_copier_cfg *cfg;149 struct acpi_nhlt_format_config *ep_blob;150 struct acpi_nhlt_endpoint *ep;151 union avs_connector_node_id node_id = {0};152 size_t cfg_size, data_size;153 void *data = NULL;154 u32 dma_type;155 int ret;156 157 data_size = sizeof(cfg->gtw_cfg.config);158 dma_type = t->cfg_ext->copier.dma_type;159 node_id.dma_type = dma_type;160 161 switch (dma_type) {162 struct avs_audio_format *fmt;163 int direction;164 165 case AVS_DMA_I2S_LINK_OUTPUT:166 case AVS_DMA_I2S_LINK_INPUT:167 if (avs_dma_type_is_input(dma_type))168 direction = SNDRV_PCM_STREAM_CAPTURE;169 else170 direction = SNDRV_PCM_STREAM_PLAYBACK;171 172 if (t->cfg_ext->copier.blob_fmt)173 fmt = t->cfg_ext->copier.blob_fmt;174 else if (direction == SNDRV_PCM_STREAM_CAPTURE)175 fmt = t->in_fmt;176 else177 fmt = t->cfg_ext->copier.out_fmt;178 179 ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP,180 ACPI_NHLT_DEVICETYPE_CODEC, direction,181 t->cfg_ext->copier.vindex.i2s.instance);182 ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,183 fmt->valid_bit_depth, fmt->bit_depth);184 if (!ep_blob) {185 dev_err(adev->dev, "no I2S ep_blob found\n");186 return -ENOENT;187 }188 189 data = ep_blob->config.capabilities;190 data_size = ep_blob->config.capabilities_size;191 /* I2S gateway's vindex is statically assigned in topology */192 node_id.vindex = t->cfg_ext->copier.vindex.val;193 194 break;195 196 case AVS_DMA_DMIC_LINK_INPUT:197 direction = SNDRV_PCM_STREAM_CAPTURE;198 199 if (t->cfg_ext->copier.blob_fmt)200 fmt = t->cfg_ext->copier.blob_fmt;201 else202 fmt = t->in_fmt;203 204 ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, direction, 0);205 ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq,206 fmt->valid_bit_depth, fmt->bit_depth);207 if (!ep_blob) {208 dev_err(adev->dev, "no DMIC ep_blob found\n");209 return -ENOENT;210 }211 212 data = ep_blob->config.capabilities;213 data_size = ep_blob->config.capabilities_size;214 /* DMIC gateway's vindex is statically assigned in topology */215 node_id.vindex = t->cfg_ext->copier.vindex.val;216 217 break;218 219 case AVS_DMA_HDA_HOST_OUTPUT:220 case AVS_DMA_HDA_HOST_INPUT:221 /* HOST gateway's vindex is dynamically assigned with DMA id */222 node_id.vindex = mod->owner->owner->dma_id;223 break;224 225 case AVS_DMA_HDA_LINK_OUTPUT:226 case AVS_DMA_HDA_LINK_INPUT:227 node_id.vindex = t->cfg_ext->copier.vindex.val |228 mod->owner->owner->dma_id;229 break;230 231 case INVALID_OBJECT_ID:232 default:233 node_id = INVALID_NODE_ID;234 break;235 }236 237 cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config) + data_size;238 if (cfg_size > AVS_MAILBOX_SIZE)239 return -EINVAL;240 241 cfg = adev->modcfg_buf;242 memset(cfg, 0, cfg_size);243 cfg->base.cpc = t->cfg_base->cpc;244 cfg->base.ibs = t->cfg_base->ibs;245 cfg->base.obs = t->cfg_base->obs;246 cfg->base.is_pages = t->cfg_base->is_pages;247 cfg->base.audio_fmt = *t->in_fmt;248 cfg->out_fmt = *t->cfg_ext->copier.out_fmt;249 cfg->feature_mask = t->cfg_ext->copier.feature_mask;250 cfg->gtw_cfg.node_id = node_id;251 cfg->gtw_cfg.dma_buffer_size = t->cfg_ext->copier.dma_buffer_size;252 /* config_length in DWORDs */253 cfg->gtw_cfg.config_length = DIV_ROUND_UP(data_size, 4);254 if (data)255 memcpy(&cfg->gtw_cfg.config.blob, data, data_size);256 257 mod->gtw_attrs = cfg->gtw_cfg.config.attrs;258 259 ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,260 t->core_id, t->domain, cfg, cfg_size,261 &mod->instance_id);262 return ret;263}264 265static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod)266{267 struct avs_tplg_module *t = mod->template;268 struct avs_tplg_path_template *path_tmpl;269 struct snd_soc_dapm_widget *w;270 int i;271 272 path_tmpl = t->owner->owner->owner;273 w = path_tmpl->w;274 275 for (i = 0; i < w->num_kcontrols; i++) {276 struct avs_control_data *ctl_data;277 struct soc_mixer_control *mc;278 279 mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value;280 ctl_data = (struct avs_control_data *)mc->dobj.private;281 if (ctl_data->id == t->ctl_id)282 return ctl_data;283 }284 285 return NULL;286}287 288static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod)289{290 struct avs_tplg_module *t = mod->template;291 struct avs_control_data *ctl_data;292 struct avs_peakvol_cfg *cfg;293 int volume = S32_MAX;294 size_t cfg_size;295 int ret;296 297 ctl_data = avs_get_module_control(mod);298 if (ctl_data)299 volume = ctl_data->volume;300 301 /* As 2+ channels controls are unsupported, have a single block for all channels. */302 cfg_size = struct_size(cfg, vols, 1);303 if (cfg_size > AVS_MAILBOX_SIZE)304 return -EINVAL;305 306 cfg = adev->modcfg_buf;307 memset(cfg, 0, cfg_size);308 cfg->base.cpc = t->cfg_base->cpc;309 cfg->base.ibs = t->cfg_base->ibs;310 cfg->base.obs = t->cfg_base->obs;311 cfg->base.is_pages = t->cfg_base->is_pages;312 cfg->base.audio_fmt = *t->in_fmt;313 cfg->vols[0].target_volume = volume;314 cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK;315 cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE;316 cfg->vols[0].curve_duration = 0;317 318 ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id,319 t->domain, cfg, cfg_size, &mod->instance_id);320 321 return ret;322}323 324static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod)325{326 struct avs_tplg_module *t = mod->template;327 struct avs_updown_mixer_cfg cfg;328 int i;329 330 cfg.base.cpc = t->cfg_base->cpc;331 cfg.base.ibs = t->cfg_base->ibs;332 cfg.base.obs = t->cfg_base->obs;333 cfg.base.is_pages = t->cfg_base->is_pages;334 cfg.base.audio_fmt = *t->in_fmt;335 cfg.out_channel_config = t->cfg_ext->updown_mix.out_channel_config;336 cfg.coefficients_select = t->cfg_ext->updown_mix.coefficients_select;337 for (i = 0; i < AVS_CHANNELS_MAX; i++)338 cfg.coefficients[i] = t->cfg_ext->updown_mix.coefficients[i];339 cfg.channel_map = t->cfg_ext->updown_mix.channel_map;340 341 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,342 t->core_id, t->domain, &cfg, sizeof(cfg),343 &mod->instance_id);344}345 346static int avs_src_create(struct avs_dev *adev, struct avs_path_module *mod)347{348 struct avs_tplg_module *t = mod->template;349 struct avs_src_cfg cfg;350 351 cfg.base.cpc = t->cfg_base->cpc;352 cfg.base.ibs = t->cfg_base->ibs;353 cfg.base.obs = t->cfg_base->obs;354 cfg.base.is_pages = t->cfg_base->is_pages;355 cfg.base.audio_fmt = *t->in_fmt;356 cfg.out_freq = t->cfg_ext->src.out_freq;357 358 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,359 t->core_id, t->domain, &cfg, sizeof(cfg),360 &mod->instance_id);361}362 363static int avs_asrc_create(struct avs_dev *adev, struct avs_path_module *mod)364{365 struct avs_tplg_module *t = mod->template;366 struct avs_asrc_cfg cfg;367 368 memset(&cfg, 0, sizeof(cfg));369 cfg.base.cpc = t->cfg_base->cpc;370 cfg.base.ibs = t->cfg_base->ibs;371 cfg.base.obs = t->cfg_base->obs;372 cfg.base.is_pages = t->cfg_base->is_pages;373 cfg.base.audio_fmt = *t->in_fmt;374 cfg.out_freq = t->cfg_ext->asrc.out_freq;375 cfg.mode = t->cfg_ext->asrc.mode;376 cfg.disable_jitter_buffer = t->cfg_ext->asrc.disable_jitter_buffer;377 378 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,379 t->core_id, t->domain, &cfg, sizeof(cfg),380 &mod->instance_id);381}382 383static int avs_aec_create(struct avs_dev *adev, struct avs_path_module *mod)384{385 struct avs_tplg_module *t = mod->template;386 struct avs_aec_cfg cfg;387 388 cfg.base.cpc = t->cfg_base->cpc;389 cfg.base.ibs = t->cfg_base->ibs;390 cfg.base.obs = t->cfg_base->obs;391 cfg.base.is_pages = t->cfg_base->is_pages;392 cfg.base.audio_fmt = *t->in_fmt;393 cfg.ref_fmt = *t->cfg_ext->aec.ref_fmt;394 cfg.out_fmt = *t->cfg_ext->aec.out_fmt;395 cfg.cpc_lp_mode = t->cfg_ext->aec.cpc_lp_mode;396 397 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,398 t->core_id, t->domain, &cfg, sizeof(cfg),399 &mod->instance_id);400}401 402static int avs_mux_create(struct avs_dev *adev, struct avs_path_module *mod)403{404 struct avs_tplg_module *t = mod->template;405 struct avs_mux_cfg cfg;406 407 cfg.base.cpc = t->cfg_base->cpc;408 cfg.base.ibs = t->cfg_base->ibs;409 cfg.base.obs = t->cfg_base->obs;410 cfg.base.is_pages = t->cfg_base->is_pages;411 cfg.base.audio_fmt = *t->in_fmt;412 cfg.ref_fmt = *t->cfg_ext->mux.ref_fmt;413 cfg.out_fmt = *t->cfg_ext->mux.out_fmt;414 415 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,416 t->core_id, t->domain, &cfg, sizeof(cfg),417 &mod->instance_id);418}419 420static int avs_wov_create(struct avs_dev *adev, struct avs_path_module *mod)421{422 struct avs_tplg_module *t = mod->template;423 struct avs_wov_cfg cfg;424 425 cfg.base.cpc = t->cfg_base->cpc;426 cfg.base.ibs = t->cfg_base->ibs;427 cfg.base.obs = t->cfg_base->obs;428 cfg.base.is_pages = t->cfg_base->is_pages;429 cfg.base.audio_fmt = *t->in_fmt;430 cfg.cpc_lp_mode = t->cfg_ext->wov.cpc_lp_mode;431 432 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,433 t->core_id, t->domain, &cfg, sizeof(cfg),434 &mod->instance_id);435}436 437static int avs_micsel_create(struct avs_dev *adev, struct avs_path_module *mod)438{439 struct avs_tplg_module *t = mod->template;440 struct avs_micsel_cfg cfg;441 442 cfg.base.cpc = t->cfg_base->cpc;443 cfg.base.ibs = t->cfg_base->ibs;444 cfg.base.obs = t->cfg_base->obs;445 cfg.base.is_pages = t->cfg_base->is_pages;446 cfg.base.audio_fmt = *t->in_fmt;447 cfg.out_fmt = *t->cfg_ext->micsel.out_fmt;448 449 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,450 t->core_id, t->domain, &cfg, sizeof(cfg),451 &mod->instance_id);452}453 454static int avs_modbase_create(struct avs_dev *adev, struct avs_path_module *mod)455{456 struct avs_tplg_module *t = mod->template;457 struct avs_modcfg_base cfg;458 459 cfg.cpc = t->cfg_base->cpc;460 cfg.ibs = t->cfg_base->ibs;461 cfg.obs = t->cfg_base->obs;462 cfg.is_pages = t->cfg_base->is_pages;463 cfg.audio_fmt = *t->in_fmt;464 465 return avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,466 t->core_id, t->domain, &cfg, sizeof(cfg),467 &mod->instance_id);468}469 470static int avs_modext_create(struct avs_dev *adev, struct avs_path_module *mod)471{472 struct avs_tplg_module *t = mod->template;473 struct avs_tplg_modcfg_ext *tcfg = t->cfg_ext;474 struct avs_modcfg_ext *cfg;475 size_t cfg_size, num_pins;476 int ret, i;477 478 num_pins = tcfg->generic.num_input_pins + tcfg->generic.num_output_pins;479 cfg_size = struct_size(cfg, pin_fmts, num_pins);480 481 if (cfg_size > AVS_MAILBOX_SIZE)482 return -EINVAL;483 484 cfg = adev->modcfg_buf;485 memset(cfg, 0, cfg_size);486 cfg->base.cpc = t->cfg_base->cpc;487 cfg->base.ibs = t->cfg_base->ibs;488 cfg->base.obs = t->cfg_base->obs;489 cfg->base.is_pages = t->cfg_base->is_pages;490 cfg->base.audio_fmt = *t->in_fmt;491 cfg->num_input_pins = tcfg->generic.num_input_pins;492 cfg->num_output_pins = tcfg->generic.num_output_pins;493 494 /* configure pin formats */495 for (i = 0; i < num_pins; i++) {496 struct avs_tplg_pin_format *tpin = &tcfg->generic.pin_fmts[i];497 struct avs_pin_format *pin = &cfg->pin_fmts[i];498 499 pin->pin_index = tpin->pin_index;500 pin->iobs = tpin->iobs;501 pin->audio_fmt = *tpin->fmt;502 }503 504 ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id,505 t->core_id, t->domain, cfg, cfg_size,506 &mod->instance_id);507 return ret;508}509 510static int avs_probe_create(struct avs_dev *adev, struct avs_path_module *mod)511{512 dev_err(adev->dev, "Probe module can't be instantiated by topology");513 return -EINVAL;514}515 516struct avs_module_create {517 guid_t *guid;518 int (*create)(struct avs_dev *adev, struct avs_path_module *mod);519};520 521static struct avs_module_create avs_module_create[] = {522 { &AVS_MIXIN_MOD_UUID, avs_modbase_create },523 { &AVS_MIXOUT_MOD_UUID, avs_modbase_create },524 { &AVS_KPBUFF_MOD_UUID, avs_modbase_create },525 { &AVS_COPIER_MOD_UUID, avs_copier_create },526 { &AVS_PEAKVOL_MOD_UUID, avs_peakvol_create },527 { &AVS_GAIN_MOD_UUID, avs_peakvol_create },528 { &AVS_MICSEL_MOD_UUID, avs_micsel_create },529 { &AVS_MUX_MOD_UUID, avs_mux_create },530 { &AVS_UPDWMIX_MOD_UUID, avs_updown_mix_create },531 { &AVS_SRCINTC_MOD_UUID, avs_src_create },532 { &AVS_AEC_MOD_UUID, avs_aec_create },533 { &AVS_ASRC_MOD_UUID, avs_asrc_create },534 { &AVS_INTELWOV_MOD_UUID, avs_wov_create },535 { &AVS_PROBE_MOD_UUID, avs_probe_create },536};537 538static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod)539{540 const guid_t *type = &mod->template->cfg_ext->type;541 542 for (int i = 0; i < ARRAY_SIZE(avs_module_create); i++)543 if (guid_equal(type, avs_module_create[i].guid))544 return avs_module_create[i].create(adev, mod);545 546 return avs_modext_create(adev, mod);547}548 549static int avs_path_module_send_init_configs(struct avs_dev *adev, struct avs_path_module *mod)550{551 struct avs_soc_component *acomp;552 553 acomp = to_avs_soc_component(mod->template->owner->owner->owner->owner->comp);554 555 u32 num_ids = mod->template->num_config_ids;556 u32 *ids = mod->template->config_ids;557 558 for (int i = 0; i < num_ids; i++) {559 struct avs_tplg_init_config *config = &acomp->tplg->init_configs[ids[i]];560 size_t len = config->length;561 void *data = config->data;562 u32 param = config->param;563 int ret;564 565 ret = avs_ipc_set_large_config(adev, mod->module_id, mod->instance_id,566 param, data, len);567 if (ret) {568 dev_err(adev->dev, "send initial module config failed: %d\n", ret);569 return AVS_IPC_RET(ret);570 }571 }572 573 return 0;574}575 576static void avs_path_module_free(struct avs_dev *adev, struct avs_path_module *mod)577{578 kfree(mod);579}580 581static struct avs_path_module *582avs_path_module_create(struct avs_dev *adev,583 struct avs_path_pipeline *owner,584 struct avs_tplg_module *template)585{586 struct avs_path_module *mod;587 int module_id, ret;588 589 module_id = avs_get_module_id(adev, &template->cfg_ext->type);590 if (module_id < 0)591 return ERR_PTR(module_id);592 593 mod = kzalloc(sizeof(*mod), GFP_KERNEL);594 if (!mod)595 return ERR_PTR(-ENOMEM);596 597 mod->template = template;598 mod->module_id = module_id;599 mod->owner = owner;600 INIT_LIST_HEAD(&mod->node);601 602 ret = avs_path_module_type_create(adev, mod);603 if (ret) {604 dev_err(adev->dev, "module-type create failed: %d\n", ret);605 kfree(mod);606 return ERR_PTR(ret);607 }608 609 ret = avs_path_module_send_init_configs(adev, mod);610 if (ret) {611 kfree(mod);612 return ERR_PTR(ret);613 }614 615 return mod;616}617 618static int avs_path_binding_arm(struct avs_dev *adev, struct avs_path_binding *binding)619{620 struct avs_path_module *this_mod, *target_mod;621 struct avs_path_pipeline *target_ppl;622 struct avs_path *target_path;623 struct avs_tplg_binding *t;624 625 t = binding->template;626 this_mod = avs_path_find_module(binding->owner,627 t->mod_id);628 if (!this_mod) {629 dev_err(adev->dev, "path mod %d not found\n", t->mod_id);630 return -EINVAL;631 }632 633 /* update with target_tplg_name too */634 target_path = avs_path_find_path(adev, t->target_tplg_name,635 t->target_path_tmpl_id);636 if (!target_path) {637 dev_err(adev->dev, "target path %s:%d not found\n",638 t->target_tplg_name, t->target_path_tmpl_id);639 return -EINVAL;640 }641 642 target_ppl = avs_path_find_pipeline(target_path,643 t->target_ppl_id);644 if (!target_ppl) {645 dev_err(adev->dev, "target ppl %d not found\n", t->target_ppl_id);646 return -EINVAL;647 }648 649 target_mod = avs_path_find_module(target_ppl, t->target_mod_id);650 if (!target_mod) {651 dev_err(adev->dev, "target mod %d not found\n", t->target_mod_id);652 return -EINVAL;653 }654 655 if (t->is_sink) {656 binding->sink = this_mod;657 binding->sink_pin = t->mod_pin;658 binding->source = target_mod;659 binding->source_pin = t->target_mod_pin;660 } else {661 binding->sink = target_mod;662 binding->sink_pin = t->target_mod_pin;663 binding->source = this_mod;664 binding->source_pin = t->mod_pin;665 }666 667 return 0;668}669 670static void avs_path_binding_free(struct avs_dev *adev, struct avs_path_binding *binding)671{672 kfree(binding);673}674 675static struct avs_path_binding *avs_path_binding_create(struct avs_dev *adev,676 struct avs_path_pipeline *owner,677 struct avs_tplg_binding *t)678{679 struct avs_path_binding *binding;680 681 binding = kzalloc(sizeof(*binding), GFP_KERNEL);682 if (!binding)683 return ERR_PTR(-ENOMEM);684 685 binding->template = t;686 binding->owner = owner;687 INIT_LIST_HEAD(&binding->node);688 689 return binding;690}691 692static int avs_path_pipeline_arm(struct avs_dev *adev,693 struct avs_path_pipeline *ppl)694{695 struct avs_path_module *mod;696 697 list_for_each_entry(mod, &ppl->mod_list, node) {698 struct avs_path_module *source, *sink;699 int ret;700 701 /*702 * Only one module (so it's implicitly last) or it is the last703 * one, either way we don't have next module to bind it to.704 */705 if (mod == list_last_entry(&ppl->mod_list,706 struct avs_path_module, node))707 break;708 709 /* bind current module to next module on list */710 source = mod;711 sink = list_next_entry(mod, node);712 713 ret = avs_ipc_bind(adev, source->module_id, source->instance_id,714 sink->module_id, sink->instance_id, 0, 0);715 if (ret)716 return AVS_IPC_RET(ret);717 }718 719 return 0;720}721 722static void avs_path_pipeline_free(struct avs_dev *adev,723 struct avs_path_pipeline *ppl)724{725 struct avs_path_binding *binding, *bsave;726 struct avs_path_module *mod, *save;727 728 list_for_each_entry_safe(binding, bsave, &ppl->binding_list, node) {729 list_del(&binding->node);730 avs_path_binding_free(adev, binding);731 }732 733 avs_dsp_delete_pipeline(adev, ppl->instance_id);734 735 /* Unload resources occupied by owned modules */736 list_for_each_entry_safe(mod, save, &ppl->mod_list, node) {737 avs_dsp_delete_module(adev, mod->module_id, mod->instance_id,738 mod->owner->instance_id,739 mod->template->core_id);740 avs_path_module_free(adev, mod);741 }742 743 list_del(&ppl->node);744 kfree(ppl);745}746 747static struct avs_path_pipeline *748avs_path_pipeline_create(struct avs_dev *adev, struct avs_path *owner,749 struct avs_tplg_pipeline *template)750{751 struct avs_path_pipeline *ppl;752 struct avs_tplg_pplcfg *cfg = template->cfg;753 struct avs_tplg_module *tmod;754 int ret, i;755 756 ppl = kzalloc(sizeof(*ppl), GFP_KERNEL);757 if (!ppl)758 return ERR_PTR(-ENOMEM);759 760 ppl->template = template;761 ppl->owner = owner;762 INIT_LIST_HEAD(&ppl->binding_list);763 INIT_LIST_HEAD(&ppl->mod_list);764 INIT_LIST_HEAD(&ppl->node);765 766 ret = avs_dsp_create_pipeline(adev, cfg->req_size, cfg->priority,767 cfg->lp, cfg->attributes,768 &ppl->instance_id);769 if (ret) {770 dev_err(adev->dev, "error creating pipeline %d\n", ret);771 kfree(ppl);772 return ERR_PTR(ret);773 }774 775 list_for_each_entry(tmod, &template->mod_list, node) {776 struct avs_path_module *mod;777 778 mod = avs_path_module_create(adev, ppl, tmod);779 if (IS_ERR(mod)) {780 ret = PTR_ERR(mod);781 dev_err(adev->dev, "error creating module %d\n", ret);782 goto init_err;783 }784 785 list_add_tail(&mod->node, &ppl->mod_list);786 }787 788 for (i = 0; i < template->num_bindings; i++) {789 struct avs_path_binding *binding;790 791 binding = avs_path_binding_create(adev, ppl, template->bindings[i]);792 if (IS_ERR(binding)) {793 ret = PTR_ERR(binding);794 dev_err(adev->dev, "error creating binding %d\n", ret);795 goto init_err;796 }797 798 list_add_tail(&binding->node, &ppl->binding_list);799 }800 801 return ppl;802 803init_err:804 avs_path_pipeline_free(adev, ppl);805 return ERR_PTR(ret);806}807 808static int avs_path_init(struct avs_dev *adev, struct avs_path *path,809 struct avs_tplg_path *template, u32 dma_id)810{811 struct avs_tplg_pipeline *tppl;812 813 path->owner = adev;814 path->template = template;815 path->dma_id = dma_id;816 INIT_LIST_HEAD(&path->ppl_list);817 INIT_LIST_HEAD(&path->node);818 819 /* create all the pipelines */820 list_for_each_entry(tppl, &template->ppl_list, node) {821 struct avs_path_pipeline *ppl;822 823 ppl = avs_path_pipeline_create(adev, path, tppl);824 if (IS_ERR(ppl))825 return PTR_ERR(ppl);826 827 list_add_tail(&ppl->node, &path->ppl_list);828 }829 830 spin_lock(&adev->path_list_lock);831 list_add_tail(&path->node, &adev->path_list);832 spin_unlock(&adev->path_list_lock);833 834 return 0;835}836 837static int avs_path_arm(struct avs_dev *adev, struct avs_path *path)838{839 struct avs_path_pipeline *ppl;840 struct avs_path_binding *binding;841 int ret;842 843 list_for_each_entry(ppl, &path->ppl_list, node) {844 /*845 * Arm all ppl bindings before binding internal modules846 * as it costs no IPCs which isn't true for the latter.847 */848 list_for_each_entry(binding, &ppl->binding_list, node) {849 ret = avs_path_binding_arm(adev, binding);850 if (ret < 0)851 return ret;852 }853 854 ret = avs_path_pipeline_arm(adev, ppl);855 if (ret < 0)856 return ret;857 }858 859 return 0;860}861 862static void avs_path_free_unlocked(struct avs_path *path)863{864 struct avs_path_pipeline *ppl, *save;865 866 spin_lock(&path->owner->path_list_lock);867 list_del(&path->node);868 spin_unlock(&path->owner->path_list_lock);869 870 list_for_each_entry_safe(ppl, save, &path->ppl_list, node)871 avs_path_pipeline_free(path->owner, ppl);872 873 kfree(path);874}875 876static struct avs_path *avs_path_create_unlocked(struct avs_dev *adev, u32 dma_id,877 struct avs_tplg_path *template)878{879 struct avs_path *path;880 int ret;881 882 path = kzalloc(sizeof(*path), GFP_KERNEL);883 if (!path)884 return ERR_PTR(-ENOMEM);885 886 ret = avs_path_init(adev, path, template, dma_id);887 if (ret < 0)888 goto err;889 890 ret = avs_path_arm(adev, path);891 if (ret < 0)892 goto err;893 894 path->state = AVS_PPL_STATE_INVALID;895 return path;896err:897 avs_path_free_unlocked(path);898 return ERR_PTR(ret);899}900 901void avs_path_free(struct avs_path *path)902{903 struct avs_dev *adev = path->owner;904 905 mutex_lock(&adev->path_mutex);906 avs_path_free_unlocked(path);907 mutex_unlock(&adev->path_mutex);908}909 910struct avs_path *avs_path_create(struct avs_dev *adev, u32 dma_id,911 struct avs_tplg_path_template *template,912 struct snd_pcm_hw_params *fe_params,913 struct snd_pcm_hw_params *be_params)914{915 struct avs_tplg_path *variant;916 struct avs_path *path;917 918 variant = avs_path_find_variant(adev, template, fe_params, be_params);919 if (!variant) {920 dev_err(adev->dev, "no matching variant found\n");921 return ERR_PTR(-ENOENT);922 }923 924 /* Serialize path and its components creation. */925 mutex_lock(&adev->path_mutex);926 /* Satisfy needs of avs_path_find_tplg(). */927 mutex_lock(&adev->comp_list_mutex);928 929 path = avs_path_create_unlocked(adev, dma_id, variant);930 931 mutex_unlock(&adev->comp_list_mutex);932 mutex_unlock(&adev->path_mutex);933 934 return path;935}936 937static int avs_path_bind_prepare(struct avs_dev *adev,938 struct avs_path_binding *binding)939{940 const struct avs_audio_format *src_fmt, *sink_fmt;941 struct avs_tplg_module *tsource = binding->source->template;942 struct avs_path_module *source = binding->source;943 int ret;944 945 /*946 * only copier modules about to be bound947 * to output pin other than 0 need preparation948 */949 if (!binding->source_pin)950 return 0;951 if (!guid_equal(&tsource->cfg_ext->type, &AVS_COPIER_MOD_UUID))952 return 0;953 954 src_fmt = tsource->in_fmt;955 sink_fmt = binding->sink->template->in_fmt;956 957 ret = avs_ipc_copier_set_sink_format(adev, source->module_id,958 source->instance_id, binding->source_pin,959 src_fmt, sink_fmt);960 if (ret) {961 dev_err(adev->dev, "config copier failed: %d\n", ret);962 return AVS_IPC_RET(ret);963 }964 965 return 0;966}967 968int avs_path_bind(struct avs_path *path)969{970 struct avs_path_pipeline *ppl;971 struct avs_dev *adev = path->owner;972 int ret;973 974 list_for_each_entry(ppl, &path->ppl_list, node) {975 struct avs_path_binding *binding;976 977 list_for_each_entry(binding, &ppl->binding_list, node) {978 struct avs_path_module *source, *sink;979 980 source = binding->source;981 sink = binding->sink;982 983 ret = avs_path_bind_prepare(adev, binding);984 if (ret < 0)985 return ret;986 987 ret = avs_ipc_bind(adev, source->module_id,988 source->instance_id, sink->module_id,989 sink->instance_id, binding->sink_pin,990 binding->source_pin);991 if (ret) {992 dev_err(adev->dev, "bind path failed: %d\n", ret);993 return AVS_IPC_RET(ret);994 }995 }996 }997 998 return 0;999}1000 1001int avs_path_unbind(struct avs_path *path)1002{1003 struct avs_path_pipeline *ppl;1004 struct avs_dev *adev = path->owner;1005 int ret;1006 1007 list_for_each_entry(ppl, &path->ppl_list, node) {1008 struct avs_path_binding *binding;1009 1010 list_for_each_entry(binding, &ppl->binding_list, node) {1011 struct avs_path_module *source, *sink;1012 1013 source = binding->source;1014 sink = binding->sink;1015 1016 ret = avs_ipc_unbind(adev, source->module_id,1017 source->instance_id, sink->module_id,1018 sink->instance_id, binding->sink_pin,1019 binding->source_pin);1020 if (ret) {1021 dev_err(adev->dev, "unbind path failed: %d\n", ret);1022 return AVS_IPC_RET(ret);1023 }1024 }1025 }1026 1027 return 0;1028}1029 1030int avs_path_reset(struct avs_path *path)1031{1032 struct avs_path_pipeline *ppl;1033 struct avs_dev *adev = path->owner;1034 int ret;1035 1036 if (path->state == AVS_PPL_STATE_RESET)1037 return 0;1038 1039 list_for_each_entry(ppl, &path->ppl_list, node) {1040 ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id,1041 AVS_PPL_STATE_RESET);1042 if (ret) {1043 dev_err(adev->dev, "reset path failed: %d\n", ret);1044 path->state = AVS_PPL_STATE_INVALID;1045 return AVS_IPC_RET(ret);1046 }1047 }1048 1049 path->state = AVS_PPL_STATE_RESET;1050 return 0;1051}1052 1053int avs_path_pause(struct avs_path *path)1054{1055 struct avs_path_pipeline *ppl;1056 struct avs_dev *adev = path->owner;1057 int ret;1058 1059 if (path->state == AVS_PPL_STATE_PAUSED)1060 return 0;1061 1062 list_for_each_entry_reverse(ppl, &path->ppl_list, node) {1063 ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id,1064 AVS_PPL_STATE_PAUSED);1065 if (ret) {1066 dev_err(adev->dev, "pause path failed: %d\n", ret);1067 path->state = AVS_PPL_STATE_INVALID;1068 return AVS_IPC_RET(ret);1069 }1070 }1071 1072 path->state = AVS_PPL_STATE_PAUSED;1073 return 0;1074}1075 1076int avs_path_run(struct avs_path *path, int trigger)1077{1078 struct avs_path_pipeline *ppl;1079 struct avs_dev *adev = path->owner;1080 int ret;1081 1082 if (path->state == AVS_PPL_STATE_RUNNING && trigger == AVS_TPLG_TRIGGER_AUTO)1083 return 0;1084 1085 list_for_each_entry(ppl, &path->ppl_list, node) {1086 if (ppl->template->cfg->trigger != trigger)1087 continue;1088 1089 ret = avs_ipc_set_pipeline_state(adev, ppl->instance_id,1090 AVS_PPL_STATE_RUNNING);1091 if (ret) {1092 dev_err(adev->dev, "run path failed: %d\n", ret);1093 path->state = AVS_PPL_STATE_INVALID;1094 return AVS_IPC_RET(ret);1095 }1096 }1097 1098 path->state = AVS_PPL_STATE_RUNNING;1099 return 0;1100}1101