1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2 // 3 // This file is provided under a dual BSD/GPLv2 license. When using or 4 // redistributing this file, you may do so under either license. 5 // 6 // Copyright(c) 2022 Intel Corporation. All rights reserved. 7 // 8 9 #include <sound/pcm_params.h> 10 #include <sound/sof/ipc4/header.h> 11 #include "sof-audio.h" 12 #include "sof-priv.h" 13 #include "ops.h" 14 #include "ipc4-priv.h" 15 #include "ipc4-topology.h" 16 #include "ipc4-fw-reg.h" 17 18 static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state, 19 struct ipc4_pipeline_set_state_data *trigger_list) 20 { 21 struct sof_ipc4_msg msg = {{ 0 }}; 22 u32 primary, ipc_size; 23 24 /* trigger a single pipeline */ 25 if (trigger_list->count == 1) 26 return sof_ipc4_set_pipeline_state(sdev, trigger_list->pipeline_ids[0], state); 27 28 primary = state; 29 primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); 30 primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 31 primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 32 msg.primary = primary; 33 34 /* trigger multiple pipelines with a single IPC */ 35 msg.extension = SOF_IPC4_GLB_PIPE_STATE_EXT_MULTI; 36 37 /* ipc_size includes the count and the pipeline IDs for the number of pipelines */ 38 ipc_size = sizeof(u32) * (trigger_list->count + 1); 39 msg.data_size = ipc_size; 40 msg.data_ptr = trigger_list; 41 42 return sof_ipc_tx_message(sdev->ipc, &msg, ipc_size, NULL, 0); 43 } 44 45 int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state) 46 { 47 struct sof_ipc4_msg msg = {{ 0 }}; 48 u32 primary; 49 50 dev_dbg(sdev->dev, "ipc4 set pipeline %d state %d", id, state); 51 52 primary = state; 53 primary |= SOF_IPC4_GLB_PIPE_STATE_ID(id); 54 primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE); 55 primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); 56 primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG); 57 58 msg.primary = primary; 59 60 return sof_ipc_tx_message(sdev->ipc, &msg, 0, NULL, 0); 61 } 62 EXPORT_SYMBOL(sof_ipc4_set_pipeline_state); 63 64 static void 65 sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state, 66 struct snd_sof_pipeline *spipe, 67 struct ipc4_pipeline_set_state_data *trigger_list) 68 { 69 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; 70 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 71 72 if (pipeline->skip_during_fe_trigger) 73 return; 74 75 switch (state) { 76 case SOF_IPC4_PIPE_RUNNING: 77 /* 78 * Trigger pipeline if all PCMs containing it are paused or if it is RUNNING 79 * for the first time 80 */ 81 if (spipe->started_count == spipe->paused_count) 82 trigger_list->pipeline_ids[trigger_list->count++] = 83 pipe_widget->instance_id; 84 break; 85 case SOF_IPC4_PIPE_RESET: 86 /* RESET if the pipeline is neither running nor paused */ 87 if (!spipe->started_count && !spipe->paused_count) 88 trigger_list->pipeline_ids[trigger_list->count++] = 89 pipe_widget->instance_id; 90 break; 91 case SOF_IPC4_PIPE_PAUSED: 92 /* Pause the pipeline only when its started_count is 1 more than paused_count */ 93 if (spipe->paused_count == (spipe->started_count - 1)) 94 trigger_list->pipeline_ids[trigger_list->count++] = 95 pipe_widget->instance_id; 96 break; 97 default: 98 break; 99 } 100 } 101 102 static void 103 sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd, 104 struct snd_sof_pipeline *spipe, 105 struct ipc4_pipeline_set_state_data *trigger_list) 106 { 107 struct snd_sof_widget *pipe_widget = spipe->pipe_widget; 108 struct sof_ipc4_pipeline *pipeline = pipe_widget->private; 109 int i; 110 111 if (pipeline->skip_during_fe_trigger) 112 return; 113 114 /* set state for pipeline if it was just triggered */ 115 for (i = 0; i < trigger_list->count; i++) { 116 if (trigger_list->pipeline_ids[i] == pipe_widget->instance_id) { 117 pipeline->state = state; 118 break; 119 } 120 } 121 122 switch (state) { 123 case SOF_IPC4_PIPE_PAUSED: 124 switch (cmd) { 125 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 126 /* 127 * increment paused_count if the PAUSED is the final state during 128 * the PAUSE trigger 129 */ 130 spipe->paused_count++; 131 break; 132 case SNDRV_PCM_TRIGGER_STOP: 133 case SNDRV_PCM_TRIGGER_SUSPEND: 134 /* 135 * decrement started_count if PAUSED is the final state during the 136 * STOP trigger 137 */ 138 spipe->started_count--; 139 break; 140 default: 141 break; 142 } 143 break; 144 case SOF_IPC4_PIPE_RUNNING: 145 switch (cmd) { 146 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 147 /* decrement paused_count for RELEASE */ 148 spipe->paused_count--; 149 break; 150 case SNDRV_PCM_TRIGGER_START: 151 case SNDRV_PCM_TRIGGER_RESUME: 152 /* increment started_count for START/RESUME */ 153 spipe->started_count++; 154 break; 155 default: 156 break; 157 } 158 break; 159 default: 160 break; 161 } 162 } 163 164 /* 165 * The picture below represents the pipeline state machine wrt PCM actions corresponding to the 166 * triggers and ioctls 167 * +---------------+ 168 * | | 169 * | INIT | 170 * | | 171 * +-------+-------+ 172 * | 173 * | 174 * | START 175 * | 176 * | 177 * +----------------+ +------v-------+ +-------------+ 178 * | | START | | HW_FREE | | 179 * | RUNNING <-------------+ PAUSED +--------------> + RESET | 180 * | | PAUSE | | | | 181 * +------+---------+ RELEASE +---------+----+ +-------------+ 182 * | ^ 183 * | | 184 * | | 185 * | | 186 * | PAUSE | 187 * +---------------------------------+ 188 * STOP/SUSPEND 189 * 190 * Note that during system suspend, the suspend trigger is followed by a hw_free in 191 * sof_pcm_trigger(). So, the final state during suspend would be RESET. 192 * Also, since the SOF driver doesn't support full resume, streams would be restarted with the 193 * prepare ioctl before the START trigger. 194 */ 195 196 static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, 197 struct snd_pcm_substream *substream, int state, int cmd) 198 { 199 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 200 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 201 struct snd_sof_pcm_stream_pipeline_list *pipeline_list; 202 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 203 struct ipc4_pipeline_set_state_data *trigger_list; 204 struct snd_sof_pipeline *spipe; 205 struct snd_sof_pcm *spcm; 206 int ret; 207 int i; 208 209 dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state); 210 211 spcm = snd_sof_find_spcm_dai(component, rtd); 212 if (!spcm) 213 return -EINVAL; 214 215 pipeline_list = &spcm->stream[substream->stream].pipeline_list; 216 217 /* nothing to trigger if the list is empty */ 218 if (!pipeline_list->pipelines || !pipeline_list->count) 219 return 0; 220 221 /* allocate memory for the pipeline data */ 222 trigger_list = kzalloc(struct_size(trigger_list, pipeline_ids, pipeline_list->count), 223 GFP_KERNEL); 224 if (!trigger_list) 225 return -ENOMEM; 226 227 mutex_lock(&ipc4_data->pipeline_state_mutex); 228 229 /* 230 * IPC4 requires pipelines to be triggered in order starting at the sink and 231 * walking all the way to the source. So traverse the pipeline_list in the order 232 * sink->source when starting PCM's and in the reverse order to pause/stop PCM's. 233 * Skip the pipelines that have their skip_during_fe_trigger flag set. If there is a fork 234 * in the pipeline, the order of triggering between the left/right paths will be 235 * indeterministic. But the sink->source trigger order sink->source would still be 236 * guaranteed for each fork independently. 237 */ 238 if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET) 239 for (i = pipeline_list->count - 1; i >= 0; i--) { 240 spipe = pipeline_list->pipelines[i]; 241 sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list); 242 } 243 else 244 for (i = 0; i < pipeline_list->count; i++) { 245 spipe = pipeline_list->pipelines[i]; 246 sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list); 247 } 248 249 /* return if all pipelines are in the requested state already */ 250 if (!trigger_list->count) { 251 ret = 0; 252 goto free; 253 } 254 255 /* no need to pause before reset or before pause release */ 256 if (state == SOF_IPC4_PIPE_RESET || cmd == SNDRV_PCM_TRIGGER_PAUSE_RELEASE) 257 goto skip_pause_transition; 258 259 /* 260 * set paused state for pipelines if the final state is PAUSED or when the pipeline 261 * is set to RUNNING for the first time after the PCM is started. 262 */ 263 ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list); 264 if (ret < 0) { 265 dev_err(sdev->dev, "failed to pause all pipelines\n"); 266 goto free; 267 } 268 269 /* update PAUSED state for all pipelines just triggered */ 270 for (i = 0; i < pipeline_list->count ; i++) { 271 spipe = pipeline_list->pipelines[i]; 272 sof_ipc4_update_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, cmd, spipe, 273 trigger_list); 274 } 275 276 /* return if this is the final state */ 277 if (state == SOF_IPC4_PIPE_PAUSED) 278 goto free; 279 skip_pause_transition: 280 /* else set the RUNNING/RESET state in the DSP */ 281 ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list); 282 if (ret < 0) { 283 dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state); 284 goto free; 285 } 286 287 /* update RUNNING/RESET state for all pipelines that were just triggered */ 288 for (i = 0; i < pipeline_list->count; i++) { 289 spipe = pipeline_list->pipelines[i]; 290 sof_ipc4_update_pipeline_state(sdev, state, cmd, spipe, trigger_list); 291 } 292 293 free: 294 mutex_unlock(&ipc4_data->pipeline_state_mutex); 295 kfree(trigger_list); 296 return ret; 297 } 298 299 static int sof_ipc4_pcm_trigger(struct snd_soc_component *component, 300 struct snd_pcm_substream *substream, int cmd) 301 { 302 int state; 303 304 /* determine the pipeline state */ 305 switch (cmd) { 306 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 307 state = SOF_IPC4_PIPE_PAUSED; 308 break; 309 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 310 case SNDRV_PCM_TRIGGER_RESUME: 311 case SNDRV_PCM_TRIGGER_START: 312 state = SOF_IPC4_PIPE_RUNNING; 313 break; 314 case SNDRV_PCM_TRIGGER_SUSPEND: 315 case SNDRV_PCM_TRIGGER_STOP: 316 state = SOF_IPC4_PIPE_PAUSED; 317 break; 318 default: 319 dev_err(component->dev, "%s: unhandled trigger cmd %d\n", __func__, cmd); 320 return -EINVAL; 321 } 322 323 /* set the pipeline state */ 324 return sof_ipc4_trigger_pipelines(component, substream, state, cmd); 325 } 326 327 static int sof_ipc4_pcm_hw_free(struct snd_soc_component *component, 328 struct snd_pcm_substream *substream) 329 { 330 /* command is not relevant with RESET, so just pass 0 */ 331 return sof_ipc4_trigger_pipelines(component, substream, SOF_IPC4_PIPE_RESET, 0); 332 } 333 334 static void ipc4_ssp_dai_config_pcm_params_match(struct snd_sof_dev *sdev, const char *link_name, 335 struct snd_pcm_hw_params *params) 336 { 337 struct snd_sof_dai_link *slink; 338 struct snd_sof_dai *dai; 339 bool dai_link_found = false; 340 int i; 341 342 list_for_each_entry(slink, &sdev->dai_link_list, list) { 343 if (!strcmp(slink->link->name, link_name)) { 344 dai_link_found = true; 345 break; 346 } 347 } 348 349 if (!dai_link_found) 350 return; 351 352 for (i = 0; i < slink->num_hw_configs; i++) { 353 struct snd_soc_tplg_hw_config *hw_config = &slink->hw_configs[i]; 354 355 if (params_rate(params) == le32_to_cpu(hw_config->fsync_rate)) { 356 /* set current config for all DAI's with matching name */ 357 list_for_each_entry(dai, &sdev->dai_list, list) 358 if (!strcmp(slink->link->name, dai->name)) 359 dai->current_config = le32_to_cpu(hw_config->id); 360 break; 361 } 362 } 363 } 364 365 /* 366 * Fixup DAI link parameters for sampling rate based on 367 * DAI copier configuration. 368 */ 369 static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, 370 struct snd_pcm_hw_params *params, 371 struct sof_ipc4_copier *ipc4_copier) 372 { 373 struct sof_ipc4_pin_format *pin_fmts = ipc4_copier->available_fmt.input_pin_fmts; 374 struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 375 int num_input_formats = ipc4_copier->available_fmt.num_input_formats; 376 unsigned int fe_rate = params_rate(params); 377 bool fe_be_rate_match = false; 378 bool single_be_rate = true; 379 unsigned int be_rate; 380 int i; 381 382 /* 383 * Copier does not change sampling rate, so we 384 * need to only consider the input pin information. 385 */ 386 for (i = 0; i < num_input_formats; i++) { 387 unsigned int val = pin_fmts[i].audio_fmt.sampling_frequency; 388 389 if (i == 0) 390 be_rate = val; 391 else if (val != be_rate) 392 single_be_rate = false; 393 394 if (val == fe_rate) { 395 fe_be_rate_match = true; 396 break; 397 } 398 } 399 400 /* 401 * If rate is different than FE rate, topology must 402 * contain an SRC. But we do require topology to 403 * define a single rate in the DAI copier config in 404 * this case (FE rate may be variable). 405 */ 406 if (!fe_be_rate_match) { 407 if (!single_be_rate) { 408 dev_err(sdev->dev, "Unable to select sampling rate for DAI link\n"); 409 return -EINVAL; 410 } 411 412 rate->min = be_rate; 413 rate->max = rate->min; 414 } 415 416 return 0; 417 } 418 419 static int sof_ipc4_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, 420 struct snd_pcm_hw_params *params) 421 { 422 struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME); 423 struct snd_sof_dai *dai = snd_sof_find_dai(component, rtd->dai_link->name); 424 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 425 struct sof_ipc4_copier *ipc4_copier; 426 int ret; 427 428 if (!dai) { 429 dev_err(component->dev, "%s: No DAI found with name %s\n", __func__, 430 rtd->dai_link->name); 431 return -EINVAL; 432 } 433 434 ipc4_copier = dai->private; 435 if (!ipc4_copier) { 436 dev_err(component->dev, "%s: No private data found for DAI %s\n", 437 __func__, rtd->dai_link->name); 438 return -EINVAL; 439 } 440 441 ret = sof_ipc4_pcm_dai_link_fixup_rate(sdev, params, ipc4_copier); 442 if (ret) 443 return ret; 444 445 switch (ipc4_copier->dai_type) { 446 case SOF_DAI_INTEL_SSP: 447 ipc4_ssp_dai_config_pcm_params_match(sdev, (char *)rtd->dai_link->name, params); 448 break; 449 default: 450 break; 451 } 452 453 return 0; 454 } 455 456 static void sof_ipc4_pcm_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm) 457 { 458 struct snd_sof_pcm_stream_pipeline_list *pipeline_list; 459 int stream; 460 461 for_each_pcm_streams(stream) { 462 pipeline_list = &spcm->stream[stream].pipeline_list; 463 kfree(pipeline_list->pipelines); 464 pipeline_list->pipelines = NULL; 465 kfree(spcm->stream[stream].private); 466 spcm->stream[stream].private = NULL; 467 } 468 } 469 470 static int sof_ipc4_pcm_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm) 471 { 472 struct snd_sof_pcm_stream_pipeline_list *pipeline_list; 473 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 474 struct sof_ipc4_timestamp_info *stream_info; 475 bool support_info = true; 476 u32 abi_version; 477 u32 abi_offset; 478 int stream; 479 480 abi_offset = offsetof(struct sof_ipc4_fw_registers, abi_ver); 481 sof_mailbox_read(sdev, sdev->fw_info_box.offset + abi_offset, &abi_version, 482 sizeof(abi_version)); 483 484 if (abi_version < SOF_IPC4_FW_REGS_ABI_VER) 485 support_info = false; 486 487 for_each_pcm_streams(stream) { 488 pipeline_list = &spcm->stream[stream].pipeline_list; 489 490 /* allocate memory for max number of pipeline IDs */ 491 pipeline_list->pipelines = kcalloc(ipc4_data->max_num_pipelines, 492 sizeof(struct snd_sof_widget *), GFP_KERNEL); 493 if (!pipeline_list->pipelines) { 494 sof_ipc4_pcm_free(sdev, spcm); 495 return -ENOMEM; 496 } 497 498 if (!support_info) 499 continue; 500 501 stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL); 502 if (!stream_info) { 503 sof_ipc4_pcm_free(sdev, spcm); 504 return -ENOMEM; 505 } 506 507 spcm->stream[stream].private = stream_info; 508 } 509 510 return 0; 511 } 512 513 static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *spcm) 514 { 515 struct sof_ipc4_copier *host_copier = NULL; 516 struct sof_ipc4_copier *dai_copier = NULL; 517 struct sof_ipc4_llp_reading_slot llp_slot; 518 struct sof_ipc4_timestamp_info *info; 519 struct snd_soc_dapm_widget *widget; 520 struct snd_sof_dai *dai; 521 int i; 522 523 /* find host & dai to locate info in memory window */ 524 for_each_dapm_widgets(spcm->list, i, widget) { 525 struct snd_sof_widget *swidget = widget->dobj.private; 526 527 if (!swidget) 528 continue; 529 530 if (WIDGET_IS_AIF(swidget->widget->id)) { 531 host_copier = swidget->private; 532 } else if (WIDGET_IS_DAI(swidget->widget->id)) { 533 dai = swidget->private; 534 dai_copier = dai->private; 535 } 536 } 537 538 /* both host and dai copier must be valid for time_info */ 539 if (!host_copier || !dai_copier) { 540 dev_err(sdev->dev, "host or dai copier are not found\n"); 541 return; 542 } 543 544 info = spcm->private; 545 info->host_copier = host_copier; 546 info->dai_copier = dai_copier; 547 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) + 548 sdev->fw_info_box.offset; 549 550 /* find llp slot used by current dai */ 551 for (i = 0; i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS; i++) { 552 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 553 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) 554 break; 555 556 info->llp_offset += sizeof(llp_slot); 557 } 558 559 if (i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS) 560 return; 561 562 /* if no llp gpdma slot is used, check aggregated sdw slot */ 563 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) + 564 sdev->fw_info_box.offset; 565 for (i = 0; i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS; i++) { 566 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 567 if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) 568 break; 569 570 info->llp_offset += sizeof(llp_slot); 571 } 572 573 if (i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS) 574 return; 575 576 /* check EVAD slot */ 577 info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) + 578 sdev->fw_info_box.offset; 579 sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 580 if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) { 581 dev_info(sdev->dev, "no llp found, fall back to default HDA path"); 582 info->llp_offset = 0; 583 } 584 } 585 586 static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, 587 struct snd_pcm_substream *substream, 588 struct snd_pcm_hw_params *params, 589 struct snd_sof_platform_stream_params *platform_params) 590 { 591 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 592 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 593 struct sof_ipc4_timestamp_info *time_info; 594 struct snd_sof_pcm *spcm; 595 596 spcm = snd_sof_find_spcm_dai(component, rtd); 597 time_info = spcm->stream[substream->stream].private; 598 /* delay calculation is not supported by current fw_reg ABI */ 599 if (!time_info) 600 return 0; 601 602 time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; 603 time_info->llp_offset = 0; 604 605 sof_ipc4_build_time_info(sdev, &spcm->stream[substream->stream]); 606 607 return 0; 608 } 609 610 static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, 611 struct snd_pcm_substream *substream, 612 struct snd_sof_pcm_stream *stream, 613 struct sof_ipc4_timestamp_info *time_info) 614 { 615 struct sof_ipc4_copier *host_copier = time_info->host_copier; 616 struct sof_ipc4_copier *dai_copier = time_info->dai_copier; 617 struct sof_ipc4_pipeline_registers ppl_reg; 618 u64 stream_start_position; 619 u32 dai_sample_size; 620 u32 ch, node_index; 621 u32 offset; 622 623 if (!host_copier || !dai_copier) 624 return -EINVAL; 625 626 if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) 627 return -EINVAL; 628 629 node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); 630 offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg); 631 sof_mailbox_read(sdev, sdev->fw_info_box.offset + offset, &ppl_reg, sizeof(ppl_reg)); 632 if (ppl_reg.stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) 633 return -EINVAL; 634 635 stream_start_position = ppl_reg.stream_start_offset; 636 ch = dai_copier->data.out_format.fmt_cfg; 637 ch = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(ch); 638 dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch; 639 /* convert offset to sample count */ 640 do_div(stream_start_position, dai_sample_size); 641 time_info->stream_start_offset = stream_start_position; 642 643 return 0; 644 } 645 646 static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component, 647 struct snd_pcm_substream *substream) 648 { 649 struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 650 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 651 struct sof_ipc4_timestamp_info *time_info; 652 struct sof_ipc4_llp_reading_slot llp; 653 snd_pcm_uframes_t head_ptr, tail_ptr; 654 struct snd_sof_pcm_stream *stream; 655 struct snd_sof_pcm *spcm; 656 u64 tmp_ptr; 657 int ret; 658 659 spcm = snd_sof_find_spcm_dai(component, rtd); 660 if (!spcm) 661 return 0; 662 663 stream = &spcm->stream[substream->stream]; 664 time_info = stream->private; 665 if (!time_info) 666 return 0; 667 668 /* 669 * stream_start_offset is updated to memory window by FW based on 670 * pipeline statistics and it may be invalid if host query happens before 671 * the statistics is complete. And it will not change after the first initiailization. 672 */ 673 if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { 674 ret = sof_ipc4_get_stream_start_offset(sdev, substream, stream, time_info); 675 if (ret < 0) 676 return 0; 677 } 678 679 /* 680 * HDaudio links don't support the LLP counter reported by firmware 681 * the link position is read directly from hardware registers. 682 */ 683 if (!time_info->llp_offset) { 684 tmp_ptr = snd_sof_pcm_get_stream_position(sdev, component, substream); 685 if (!tmp_ptr) 686 return 0; 687 } else { 688 sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); 689 tmp_ptr = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l; 690 } 691 692 /* In two cases dai dma position is not accurate 693 * (1) dai pipeline is started before host pipeline 694 * (2) multiple streams mixed into one. Each stream has the same dai dma position 695 * 696 * Firmware calculates correct stream_start_offset for all cases including above two. 697 * Driver subtracts stream_start_offset from dai dma position to get accurate one 698 */ 699 tmp_ptr -= time_info->stream_start_offset; 700 701 /* Calculate the delay taking into account that both pointer can wrap */ 702 div64_u64_rem(tmp_ptr, substream->runtime->boundary, &tmp_ptr); 703 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 704 head_ptr = substream->runtime->status->hw_ptr; 705 tail_ptr = tmp_ptr; 706 } else { 707 head_ptr = tmp_ptr; 708 tail_ptr = substream->runtime->status->hw_ptr; 709 } 710 711 if (head_ptr < tail_ptr) 712 return substream->runtime->boundary - tail_ptr + head_ptr; 713 714 return head_ptr - tail_ptr; 715 } 716 717 const struct sof_ipc_pcm_ops ipc4_pcm_ops = { 718 .hw_params = sof_ipc4_pcm_hw_params, 719 .trigger = sof_ipc4_pcm_trigger, 720 .hw_free = sof_ipc4_pcm_hw_free, 721 .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup, 722 .pcm_setup = sof_ipc4_pcm_setup, 723 .pcm_free = sof_ipc4_pcm_free, 724 .delay = sof_ipc4_pcm_delay 725 }; 726