1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright(c) 2021-2022 Intel Corporation. All rights reserved. 4 // 5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com> 6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> 7 // 8 9 #include <linux/slab.h> 10 #include "avs.h" 11 #include "messages.h" 12 13 #define AVS_CL_TIMEOUT_MS 5000 14 15 int avs_ipc_set_boot_config(struct avs_dev *adev, u32 dma_id, u32 purge) 16 { 17 union avs_global_msg msg = AVS_GLOBAL_REQUEST(ROM_CONTROL); 18 struct avs_ipc_msg request = {{0}}; 19 int ret; 20 21 msg.boot_cfg.rom_ctrl_msg_type = AVS_ROM_SET_BOOT_CONFIG; 22 msg.boot_cfg.dma_id = dma_id; 23 msg.boot_cfg.purge_request = purge; 24 request.header = msg.val; 25 26 ret = avs_dsp_send_rom_msg(adev, &request); 27 if (ret) 28 avs_ipc_err(adev, &request, "set boot config", ret); 29 30 return ret; 31 } 32 33 int avs_ipc_load_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids) 34 { 35 union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_MULTIPLE_MODULES); 36 struct avs_ipc_msg request; 37 int ret; 38 39 msg.load_multi_mods.mod_cnt = num_mod_ids; 40 request.header = msg.val; 41 request.data = mod_ids; 42 request.size = sizeof(*mod_ids) * num_mod_ids; 43 44 ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS); 45 if (ret) 46 avs_ipc_err(adev, &request, "load multiple modules", ret); 47 48 return ret; 49 } 50 51 int avs_ipc_unload_modules(struct avs_dev *adev, u16 *mod_ids, u32 num_mod_ids) 52 { 53 union avs_global_msg msg = AVS_GLOBAL_REQUEST(UNLOAD_MULTIPLE_MODULES); 54 struct avs_ipc_msg request; 55 int ret; 56 57 msg.load_multi_mods.mod_cnt = num_mod_ids; 58 request.header = msg.val; 59 request.data = mod_ids; 60 request.size = sizeof(*mod_ids) * num_mod_ids; 61 62 ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS); 63 if (ret) 64 avs_ipc_err(adev, &request, "unload multiple modules", ret); 65 66 return ret; 67 } 68 69 int avs_ipc_load_library(struct avs_dev *adev, u32 dma_id, u32 lib_id) 70 { 71 union avs_global_msg msg = AVS_GLOBAL_REQUEST(LOAD_LIBRARY); 72 struct avs_ipc_msg request = {{0}}; 73 int ret; 74 75 msg.load_lib.dma_id = dma_id; 76 msg.load_lib.lib_id = lib_id; 77 request.header = msg.val; 78 79 ret = avs_dsp_send_msg_timeout(adev, &request, NULL, AVS_CL_TIMEOUT_MS); 80 if (ret) 81 avs_ipc_err(adev, &request, "load library", ret); 82 83 return ret; 84 } 85 86 int avs_ipc_create_pipeline(struct avs_dev *adev, u16 req_size, u8 priority, 87 u8 instance_id, bool lp, u16 attributes) 88 { 89 union avs_global_msg msg = AVS_GLOBAL_REQUEST(CREATE_PIPELINE); 90 struct avs_ipc_msg request = {{0}}; 91 int ret; 92 93 msg.create_ppl.ppl_mem_size = req_size; 94 msg.create_ppl.ppl_priority = priority; 95 msg.create_ppl.instance_id = instance_id; 96 msg.ext.create_ppl.lp = lp; 97 msg.ext.create_ppl.attributes = attributes; 98 request.header = msg.val; 99 100 ret = avs_dsp_send_msg(adev, &request, NULL); 101 if (ret) 102 avs_ipc_err(adev, &request, "create pipeline", ret); 103 104 return ret; 105 } 106 107 int avs_ipc_delete_pipeline(struct avs_dev *adev, u8 instance_id) 108 { 109 union avs_global_msg msg = AVS_GLOBAL_REQUEST(DELETE_PIPELINE); 110 struct avs_ipc_msg request = {{0}}; 111 int ret; 112 113 msg.ppl.instance_id = instance_id; 114 request.header = msg.val; 115 116 ret = avs_dsp_send_msg(adev, &request, NULL); 117 if (ret) 118 avs_ipc_err(adev, &request, "delete pipeline", ret); 119 120 return ret; 121 } 122 123 int avs_ipc_set_pipeline_state(struct avs_dev *adev, u8 instance_id, 124 enum avs_pipeline_state state) 125 { 126 union avs_global_msg msg = AVS_GLOBAL_REQUEST(SET_PIPELINE_STATE); 127 struct avs_ipc_msg request = {{0}}; 128 int ret; 129 130 msg.set_ppl_state.ppl_id = instance_id; 131 msg.set_ppl_state.state = state; 132 request.header = msg.val; 133 134 ret = avs_dsp_send_msg(adev, &request, NULL); 135 if (ret) 136 avs_ipc_err(adev, &request, "set pipeline state", ret); 137 138 return ret; 139 } 140 141 int avs_ipc_get_pipeline_state(struct avs_dev *adev, u8 instance_id, 142 enum avs_pipeline_state *state) 143 { 144 union avs_global_msg msg = AVS_GLOBAL_REQUEST(GET_PIPELINE_STATE); 145 struct avs_ipc_msg request = {{0}}; 146 struct avs_ipc_msg reply = {{0}}; 147 int ret; 148 149 msg.get_ppl_state.ppl_id = instance_id; 150 request.header = msg.val; 151 152 ret = avs_dsp_send_msg(adev, &request, &reply); 153 if (ret) { 154 avs_ipc_err(adev, &request, "get pipeline state", ret); 155 return ret; 156 } 157 158 *state = reply.rsp.ext.get_ppl_state.state; 159 return ret; 160 } 161 162 /* 163 * avs_ipc_init_instance - Initialize module instance 164 * 165 * @adev: Driver context 166 * @module_id: Module-type id 167 * @instance_id: Unique module instance id 168 * @ppl_id: Parent pipeline id 169 * @core_id: DSP core to allocate module on 170 * @domain: Processing domain (low latency or data processing) 171 * @param: Module-type specific configuration 172 * @param_size: Size of @param in bytes 173 * 174 * Argument verification, as well as pipeline state checks are done by the 175 * firmware. 176 * 177 * Note: @ppl_id and @core_id are independent of each other as single pipeline 178 * can be composed of module instances located on different DSP cores. 179 */ 180 int avs_ipc_init_instance(struct avs_dev *adev, u16 module_id, u8 instance_id, 181 u8 ppl_id, u8 core_id, u8 domain, 182 void *param, u32 param_size) 183 { 184 union avs_module_msg msg = AVS_MODULE_REQUEST(INIT_INSTANCE); 185 struct avs_ipc_msg request; 186 int ret; 187 188 msg.module_id = module_id; 189 msg.instance_id = instance_id; 190 /* firmware expects size provided in dwords */ 191 msg.ext.init_instance.param_block_size = DIV_ROUND_UP(param_size, sizeof(u32)); 192 msg.ext.init_instance.ppl_instance_id = ppl_id; 193 msg.ext.init_instance.core_id = core_id; 194 msg.ext.init_instance.proc_domain = domain; 195 196 request.header = msg.val; 197 request.data = param; 198 request.size = param_size; 199 200 ret = avs_dsp_send_msg(adev, &request, NULL); 201 if (ret) 202 avs_ipc_err(adev, &request, "init instance", ret); 203 204 return ret; 205 } 206 207 /* 208 * avs_ipc_delete_instance - Delete module instance 209 * 210 * @adev: Driver context 211 * @module_id: Module-type id 212 * @instance_id: Unique module instance id 213 * 214 * Argument verification, as well as pipeline state checks are done by the 215 * firmware. 216 * 217 * Note: only standalone modules i.e. without a parent pipeline shall be 218 * deleted using this IPC message. In all other cases, pipeline owning the 219 * modules performs cleanup automatically when it is deleted. 220 */ 221 int avs_ipc_delete_instance(struct avs_dev *adev, u16 module_id, u8 instance_id) 222 { 223 union avs_module_msg msg = AVS_MODULE_REQUEST(DELETE_INSTANCE); 224 struct avs_ipc_msg request = {{0}}; 225 int ret; 226 227 msg.module_id = module_id; 228 msg.instance_id = instance_id; 229 request.header = msg.val; 230 231 ret = avs_dsp_send_msg(adev, &request, NULL); 232 if (ret) 233 avs_ipc_err(adev, &request, "delete instance", ret); 234 235 return ret; 236 } 237 238 /* 239 * avs_ipc_bind - Bind two module instances 240 * 241 * @adev: Driver context 242 * @module_id: Source module-type id 243 * @instance_id: Source module instance id 244 * @dst_module_id: Sink module-type id 245 * @dst_instance_id: Sink module instance id 246 * @dst_queue: Sink module pin to bind @src_queue with 247 * @src_queue: Source module pin to bind @dst_queue with 248 */ 249 int avs_ipc_bind(struct avs_dev *adev, u16 module_id, u8 instance_id, 250 u16 dst_module_id, u8 dst_instance_id, 251 u8 dst_queue, u8 src_queue) 252 { 253 union avs_module_msg msg = AVS_MODULE_REQUEST(BIND); 254 struct avs_ipc_msg request = {{0}}; 255 int ret; 256 257 msg.module_id = module_id; 258 msg.instance_id = instance_id; 259 msg.ext.bind_unbind.dst_module_id = dst_module_id; 260 msg.ext.bind_unbind.dst_instance_id = dst_instance_id; 261 msg.ext.bind_unbind.dst_queue = dst_queue; 262 msg.ext.bind_unbind.src_queue = src_queue; 263 request.header = msg.val; 264 265 ret = avs_dsp_send_msg(adev, &request, NULL); 266 if (ret) 267 avs_ipc_err(adev, &request, "bind modules", ret); 268 269 return ret; 270 } 271 272 /* 273 * avs_ipc_unbind - Unbind two module instances 274 * 275 * @adev: Driver context 276 * @module_id: Source module-type id 277 * @instance_id: Source module instance id 278 * @dst_module_id: Sink module-type id 279 * @dst_instance_id: Sink module instance id 280 * @dst_queue: Sink module pin to unbind @src_queue from 281 * @src_queue: Source module pin to unbind @dst_queue from 282 */ 283 int avs_ipc_unbind(struct avs_dev *adev, u16 module_id, u8 instance_id, 284 u16 dst_module_id, u8 dst_instance_id, 285 u8 dst_queue, u8 src_queue) 286 { 287 union avs_module_msg msg = AVS_MODULE_REQUEST(UNBIND); 288 struct avs_ipc_msg request = {{0}}; 289 int ret; 290 291 msg.module_id = module_id; 292 msg.instance_id = instance_id; 293 msg.ext.bind_unbind.dst_module_id = dst_module_id; 294 msg.ext.bind_unbind.dst_instance_id = dst_instance_id; 295 msg.ext.bind_unbind.dst_queue = dst_queue; 296 msg.ext.bind_unbind.src_queue = src_queue; 297 request.header = msg.val; 298 299 ret = avs_dsp_send_msg(adev, &request, NULL); 300 if (ret) 301 avs_ipc_err(adev, &request, "unbind modules", ret); 302 303 return ret; 304 } 305 306 static int __avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id, 307 u8 param_id, bool init_block, bool final_block, 308 u8 *request_data, size_t request_size, size_t off_size) 309 { 310 union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_SET); 311 struct avs_ipc_msg request; 312 int ret; 313 314 msg.module_id = module_id; 315 msg.instance_id = instance_id; 316 msg.ext.large_config.data_off_size = off_size; 317 msg.ext.large_config.large_param_id = param_id; 318 msg.ext.large_config.final_block = final_block; 319 msg.ext.large_config.init_block = init_block; 320 321 request.header = msg.val; 322 request.data = request_data; 323 request.size = request_size; 324 325 ret = avs_dsp_send_msg(adev, &request, NULL); 326 if (ret) 327 avs_ipc_err(adev, &request, "large config set", ret); 328 329 return ret; 330 } 331 332 int avs_ipc_set_large_config(struct avs_dev *adev, u16 module_id, 333 u8 instance_id, u8 param_id, 334 u8 *request, size_t request_size) 335 { 336 size_t remaining, tx_size; 337 bool final; 338 int ret; 339 340 remaining = request_size; 341 tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining); 342 final = (tx_size == remaining); 343 344 /* Initial request states total payload size. */ 345 ret = __avs_ipc_set_large_config(adev, module_id, instance_id, 346 param_id, 1, final, request, tx_size, 347 request_size); 348 if (ret) 349 return ret; 350 351 remaining -= tx_size; 352 353 /* Loop the rest only when payload exceeds mailbox's size. */ 354 while (remaining) { 355 size_t offset; 356 357 offset = request_size - remaining; 358 tx_size = min_t(size_t, AVS_MAILBOX_SIZE, remaining); 359 final = (tx_size == remaining); 360 361 ret = __avs_ipc_set_large_config(adev, module_id, instance_id, 362 param_id, 0, final, 363 request + offset, tx_size, 364 offset); 365 if (ret) 366 return ret; 367 368 remaining -= tx_size; 369 } 370 371 return 0; 372 } 373 374 int avs_ipc_get_large_config(struct avs_dev *adev, u16 module_id, u8 instance_id, 375 u8 param_id, u8 *request_data, size_t request_size, 376 u8 **reply_data, size_t *reply_size) 377 { 378 union avs_module_msg msg = AVS_MODULE_REQUEST(LARGE_CONFIG_GET); 379 struct avs_ipc_msg request; 380 struct avs_ipc_msg reply = {{0}}; 381 size_t size; 382 void *buf; 383 int ret; 384 385 reply.data = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); 386 if (!reply.data) 387 return -ENOMEM; 388 389 msg.module_id = module_id; 390 msg.instance_id = instance_id; 391 msg.ext.large_config.data_off_size = request_size; 392 msg.ext.large_config.large_param_id = param_id; 393 /* final_block is always 0 on request. Updated by fw on reply. */ 394 msg.ext.large_config.final_block = 0; 395 msg.ext.large_config.init_block = 1; 396 397 request.header = msg.val; 398 request.data = request_data; 399 request.size = request_size; 400 reply.size = AVS_MAILBOX_SIZE; 401 402 ret = avs_dsp_send_msg(adev, &request, &reply); 403 if (ret) { 404 avs_ipc_err(adev, &request, "large config get", ret); 405 kfree(reply.data); 406 return ret; 407 } 408 409 size = reply.rsp.ext.large_config.data_off_size; 410 buf = krealloc(reply.data, size, GFP_KERNEL); 411 if (!buf) { 412 kfree(reply.data); 413 return -ENOMEM; 414 } 415 416 *reply_data = buf; 417 *reply_size = size; 418 419 return 0; 420 } 421 422 int avs_ipc_set_dx(struct avs_dev *adev, u32 core_mask, bool powerup) 423 { 424 union avs_module_msg msg = AVS_MODULE_REQUEST(SET_DX); 425 struct avs_ipc_msg request; 426 struct avs_dxstate_info dx; 427 int ret; 428 429 dx.core_mask = core_mask; 430 dx.dx_mask = powerup ? core_mask : 0; 431 request.header = msg.val; 432 request.data = &dx; 433 request.size = sizeof(dx); 434 435 ret = avs_dsp_send_msg(adev, &request, NULL); 436 if (ret) 437 avs_ipc_err(adev, &request, "set dx", ret); 438 439 return ret; 440 } 441 442 /* 443 * avs_ipc_set_d0ix - Set power gating policy (entering D0IX substates) 444 * 445 * @enable_pg: Whether to enable or disable power gating 446 * @streaming: Whether a stream is running when transitioning 447 */ 448 int avs_ipc_set_d0ix(struct avs_dev *adev, bool enable_pg, bool streaming) 449 { 450 union avs_module_msg msg = AVS_MODULE_REQUEST(SET_D0IX); 451 struct avs_ipc_msg request = {{0}}; 452 int ret; 453 454 msg.ext.set_d0ix.wake = enable_pg; 455 msg.ext.set_d0ix.streaming = streaming; 456 457 request.header = msg.val; 458 459 ret = avs_dsp_send_msg(adev, &request, NULL); 460 if (ret) 461 avs_ipc_err(adev, &request, "set d0ix", ret); 462 463 return ret; 464 } 465 466 int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg) 467 { 468 struct avs_tlv *tlv; 469 size_t payload_size; 470 size_t offset = 0; 471 u8 *payload; 472 int ret; 473 474 ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, 475 AVS_BASEFW_FIRMWARE_CONFIG, NULL, 0, 476 &payload, &payload_size); 477 if (ret) 478 return ret; 479 480 while (offset < payload_size) { 481 tlv = (struct avs_tlv *)(payload + offset); 482 483 switch (tlv->type) { 484 case AVS_FW_CFG_FW_VERSION: 485 memcpy(&cfg->fw_version, tlv->value, sizeof(cfg->fw_version)); 486 break; 487 488 case AVS_FW_CFG_MEMORY_RECLAIMED: 489 cfg->memory_reclaimed = *tlv->value; 490 break; 491 492 case AVS_FW_CFG_SLOW_CLOCK_FREQ_HZ: 493 cfg->slow_clock_freq_hz = *tlv->value; 494 break; 495 496 case AVS_FW_CFG_FAST_CLOCK_FREQ_HZ: 497 cfg->fast_clock_freq_hz = *tlv->value; 498 break; 499 500 case AVS_FW_CFG_ALH_SUPPORT_LEVEL: 501 cfg->alh_support = *tlv->value; 502 break; 503 504 case AVS_FW_CFG_IPC_DL_MAILBOX_BYTES: 505 cfg->ipc_dl_mailbox_bytes = *tlv->value; 506 break; 507 508 case AVS_FW_CFG_IPC_UL_MAILBOX_BYTES: 509 cfg->ipc_ul_mailbox_bytes = *tlv->value; 510 break; 511 512 case AVS_FW_CFG_TRACE_LOG_BYTES: 513 cfg->trace_log_bytes = *tlv->value; 514 break; 515 516 case AVS_FW_CFG_MAX_PPL_COUNT: 517 cfg->max_ppl_count = *tlv->value; 518 break; 519 520 case AVS_FW_CFG_MAX_ASTATE_COUNT: 521 cfg->max_astate_count = *tlv->value; 522 break; 523 524 case AVS_FW_CFG_MAX_MODULE_PIN_COUNT: 525 cfg->max_module_pin_count = *tlv->value; 526 break; 527 528 case AVS_FW_CFG_MODULES_COUNT: 529 cfg->modules_count = *tlv->value; 530 break; 531 532 case AVS_FW_CFG_MAX_MOD_INST_COUNT: 533 cfg->max_mod_inst_count = *tlv->value; 534 break; 535 536 case AVS_FW_CFG_MAX_LL_TASKS_PER_PRI_COUNT: 537 cfg->max_ll_tasks_per_pri_count = *tlv->value; 538 break; 539 540 case AVS_FW_CFG_LL_PRI_COUNT: 541 cfg->ll_pri_count = *tlv->value; 542 break; 543 544 case AVS_FW_CFG_MAX_DP_TASKS_COUNT: 545 cfg->max_dp_tasks_count = *tlv->value; 546 break; 547 548 case AVS_FW_CFG_MAX_LIBS_COUNT: 549 cfg->max_libs_count = *tlv->value; 550 break; 551 552 case AVS_FW_CFG_XTAL_FREQ_HZ: 553 cfg->xtal_freq_hz = *tlv->value; 554 break; 555 556 case AVS_FW_CFG_POWER_GATING_POLICY: 557 cfg->power_gating_policy = *tlv->value; 558 break; 559 560 /* Known but not useful to us. */ 561 case AVS_FW_CFG_DMA_BUFFER_CONFIG: 562 case AVS_FW_CFG_SCHEDULER_CONFIG: 563 case AVS_FW_CFG_CLOCKS_CONFIG: 564 break; 565 566 default: 567 dev_info(adev->dev, "Unrecognized fw param: %d\n", tlv->type); 568 break; 569 } 570 571 offset += sizeof(*tlv) + tlv->length; 572 } 573 574 /* No longer needed, free it as it's owned by the get_large_config() caller. */ 575 kfree(payload); 576 return ret; 577 } 578 579 int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg) 580 { 581 struct avs_tlv *tlv; 582 size_t payload_size; 583 size_t size, offset = 0; 584 u8 *payload; 585 int ret; 586 587 ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, 588 AVS_BASEFW_HARDWARE_CONFIG, NULL, 0, 589 &payload, &payload_size); 590 if (ret) 591 return ret; 592 593 while (offset < payload_size) { 594 tlv = (struct avs_tlv *)(payload + offset); 595 596 switch (tlv->type) { 597 case AVS_HW_CFG_AVS_VER: 598 cfg->avs_version = *tlv->value; 599 break; 600 601 case AVS_HW_CFG_DSP_CORES: 602 cfg->dsp_cores = *tlv->value; 603 break; 604 605 case AVS_HW_CFG_MEM_PAGE_BYTES: 606 cfg->mem_page_bytes = *tlv->value; 607 break; 608 609 case AVS_HW_CFG_TOTAL_PHYS_MEM_PAGES: 610 cfg->total_phys_mem_pages = *tlv->value; 611 break; 612 613 case AVS_HW_CFG_I2S_CAPS: 614 cfg->i2s_caps.i2s_version = tlv->value[0]; 615 size = tlv->value[1]; 616 cfg->i2s_caps.ctrl_count = size; 617 if (!size) 618 break; 619 620 /* Multiply to get entire array size. */ 621 size *= sizeof(*cfg->i2s_caps.ctrl_base_addr); 622 cfg->i2s_caps.ctrl_base_addr = devm_kmemdup(adev->dev, 623 &tlv->value[2], 624 size, GFP_KERNEL); 625 if (!cfg->i2s_caps.ctrl_base_addr) { 626 ret = -ENOMEM; 627 goto exit; 628 } 629 break; 630 631 case AVS_HW_CFG_GATEWAY_COUNT: 632 cfg->gateway_count = *tlv->value; 633 break; 634 635 case AVS_HW_CFG_HP_EBB_COUNT: 636 cfg->hp_ebb_count = *tlv->value; 637 break; 638 639 case AVS_HW_CFG_LP_EBB_COUNT: 640 cfg->lp_ebb_count = *tlv->value; 641 break; 642 643 case AVS_HW_CFG_EBB_SIZE_BYTES: 644 cfg->ebb_size_bytes = *tlv->value; 645 break; 646 647 case AVS_HW_CFG_GPDMA_CAPS: 648 break; 649 650 default: 651 dev_info(adev->dev, "Unrecognized hw config: %d\n", tlv->type); 652 break; 653 } 654 655 offset += sizeof(*tlv) + tlv->length; 656 } 657 658 exit: 659 /* No longer needed, free it as it's owned by the get_large_config() caller. */ 660 kfree(payload); 661 return ret; 662 } 663 664 int avs_ipc_get_modules_info(struct avs_dev *adev, struct avs_mods_info **info) 665 { 666 size_t payload_size; 667 u8 *payload; 668 int ret; 669 670 ret = avs_ipc_get_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, 671 AVS_BASEFW_MODULES_INFO, NULL, 0, 672 &payload, &payload_size); 673 if (ret) 674 return ret; 675 676 *info = (struct avs_mods_info *)payload; 677 return 0; 678 } 679 680 int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, 681 u8 instance_id, u32 sink_id, 682 const struct avs_audio_format *src_fmt, 683 const struct avs_audio_format *sink_fmt) 684 { 685 struct avs_copier_sink_format cpr_fmt; 686 687 cpr_fmt.sink_id = sink_id; 688 /* Firmware expects driver to resend copier's input format. */ 689 cpr_fmt.src_fmt = *src_fmt; 690 cpr_fmt.sink_fmt = *sink_fmt; 691 692 return avs_ipc_set_large_config(adev, module_id, instance_id, 693 AVS_COPIER_SET_SINK_FORMAT, 694 (u8 *)&cpr_fmt, sizeof(cpr_fmt)); 695 } 696