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: core/ipc4/mtl: Add support for PCM delay

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

The following series adds support for the PCM delay reporting in SOF core level
and implements the needed infrastructure with IPC4 to finally enable it for MTL.

Currently this is only supported on MTL (and via IPC4), but with the
infrastructure in place it will be possible to support other platforms with
DeepBuffer.

+464
+14
sound/soc/sof/intel/mtl.c
··· 581 581 return mtl_enable_interrupts(sdev, false); 582 582 } 583 583 584 + static u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev, 585 + struct snd_soc_component *component, 586 + struct snd_pcm_substream *substream) 587 + { 588 + struct hdac_stream *hstream = substream->runtime->private_data; 589 + u32 llp_l, llp_u; 590 + 591 + llp_l = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPL(hstream->index)); 592 + llp_u = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPU(hstream->index)); 593 + return ((u64)llp_u << 32) | llp_l; 594 + } 595 + 584 596 /* Meteorlake ops */ 585 597 struct snd_sof_dsp_ops sof_mtl_ops; 586 598 EXPORT_SYMBOL_NS(sof_mtl_ops, SND_SOC_SOF_INTEL_HDA_COMMON); ··· 630 618 631 619 /* dsp core get/put */ 632 620 /* TODO: add core_get and core_put */ 621 + 622 + sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position; 633 623 634 624 sdev->private = devm_kzalloc(sdev->dev, sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); 635 625 if (!sdev->private)
+6
sound/soc/sof/intel/mtl.h
··· 6 6 * Copyright(c) 2020-2022 Intel Corporation. All rights reserved. 7 7 */ 8 8 9 + /* HDA Registers */ 10 + #define MTL_PPLCLLPL_BASE 0x948 11 + #define MTL_PPLCLLPU_STRIDE 0x10 12 + #define MTL_PPLCLLPL(x) (MTL_PPLCLLPL_BASE + (x) * MTL_PPLCLLPU_STRIDE) 13 + #define MTL_PPLCLLPU(x) (MTL_PPLCLLPL_BASE + 0x4 + (x) * MTL_PPLCLLPU_STRIDE) 14 + 9 15 /* DSP Registers */ 10 16 #define MTL_HFDSSCS 0x1000 11 17 #define MTL_HFDSSCS_SPA_MASK BIT(16)
+155
sound/soc/sof/ipc4-fw-reg.h
··· 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 + #ifndef __IPC4_FW_REG_H__ 10 + #define __IPC4_FW_REG_H__ 11 + 12 + #define SOF_IPC4_INVALID_STREAM_POSITION ULLONG_MAX 13 + 14 + /** 15 + * struct sof_ipc4_pipeline_registers - Pipeline start and end information in fw 16 + * @stream_start_offset: Stream start offset (LPIB) reported by mixin 17 + * module allocated on pipeline attached to Host Output Gateway when 18 + * first data is being mixed to mixout module. When data is not mixed 19 + * (right after creation/after reset) value "(u64)-1" is reported 20 + * @stream_end_offset: Stream end offset (LPIB) reported by mixin 21 + * module allocated on pipeline attached to Host Output Gateway 22 + * during transition from RUNNING to PAUSED. When data is not mixed 23 + * (right after creation or after reset) value "(u64)-1" is reported. 24 + * When first data is mixed then value "0"is reported. 25 + */ 26 + struct sof_ipc4_pipeline_registers { 27 + u64 stream_start_offset; 28 + u64 stream_end_offset; 29 + } __packed __aligned(4); 30 + 31 + #define SOF_IPC4_PV_MAX_SUPPORTED_CHANNELS 8 32 + 33 + /** 34 + * struct sof_ipc4_peak_volume_regs - Volume information in fw 35 + * @peak_meter: Peak volume value in fw 36 + * @current_volume: Current volume value in fw 37 + * @target_volume: Target volume value in fw 38 + */ 39 + struct sof_ipc4_peak_volume_regs { 40 + u32 peak_meter[SOF_IPC4_PV_MAX_SUPPORTED_CHANNELS]; 41 + u32 current_volume[SOF_IPC4_PV_MAX_SUPPORTED_CHANNELS]; 42 + u32 target_volume[SOF_IPC4_PV_MAX_SUPPORTED_CHANNELS]; 43 + } __packed __aligned(4); 44 + 45 + /** 46 + * struct sof_ipc4_llp_reading - Llp information in fw 47 + * @llp_l: Lower part of 64-bit LLP 48 + * @llp_u: Upper part of 64-bit LLP 49 + * @wclk_l: Lower part of 64-bit Wallclock 50 + * @wclk_u: Upper part of 64-bit Wallclock 51 + */ 52 + struct sof_ipc4_llp_reading { 53 + u32 llp_l; 54 + u32 llp_u; 55 + u32 wclk_l; 56 + u32 wclk_u; 57 + } __packed __aligned(4); 58 + 59 + /** 60 + * struct of sof_ipc4_llp_reading_extended - Extended llp info 61 + * @llp_reading: Llp information in memory window 62 + * @tpd_low: Total processed data (low part) 63 + * @tpd_high: Total processed data (high part) 64 + */ 65 + struct sof_ipc4_llp_reading_extended { 66 + struct sof_ipc4_llp_reading llp_reading; 67 + u32 tpd_low; 68 + u32 tpd_high; 69 + } __packed __aligned(4); 70 + 71 + /** 72 + * struct sof_ipc4_llp_reading_slot - Llp slot information in memory window 73 + * @node_id: Dai gateway node id 74 + * @reading: Llp information in memory window 75 + */ 76 + struct sof_ipc4_llp_reading_slot { 77 + u32 node_id; 78 + struct sof_ipc4_llp_reading reading; 79 + } __packed __aligned(4); 80 + 81 + /* ROM information */ 82 + #define SOF_IPC4_FW_FUSE_VALUE_MASK GENMASK(7, 0) 83 + #define SOF_IPC4_FW_LOAD_METHOD_MASK BIT(8) 84 + #define SOF_IPC4_FW_DOWNLINK_IPC_USE_DMA_MASK BIT(9) 85 + #define SOF_IPC4_FW_LOAD_METHOD_REV_MASK GENMASK(11, 10) 86 + #define SOF_IPC4_FW_REVISION_MIN_MASK GENMASK(15, 12) 87 + #define SOF_IPC4_FW_REVISION_MAJ_MASK GENMASK(19, 16) 88 + #define SOF_IPC4_FW_VERSION_MIN_MASK GENMASK(23, 20) 89 + #define SOF_IPC4_FW_VERSION_MAJ_MASK GENMASK(27, 24) 90 + 91 + /* Number of dsp core supported in FW Regs. */ 92 + #define SOF_IPC4_MAX_SUPPORTED_ADSP_CORES 8 93 + 94 + /* Number of host pipeline registers slots in FW Regs. */ 95 + #define SOF_IPC4_MAX_PIPELINE_REG_SLOTS 16 96 + 97 + /* Number of PeakVol registers slots in FW Regs. */ 98 + #define SOF_IPC4_MAX_PEAK_VOL_REG_SLOTS 16 99 + 100 + /* Number of GPDMA LLP Reading slots in FW Regs. */ 101 + #define SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS 24 102 + 103 + /* Number of Aggregated SNDW Reading slots in FW Regs. */ 104 + #define SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS 15 105 + 106 + /* Current ABI version of the Fw registers layout. */ 107 + #define SOF_IPC4_FW_REGS_ABI_VER 1 108 + 109 + /** 110 + * struct sof_ipc4_fw_registers - FW Registers exposes additional 111 + * DSP / FW state information to the driver 112 + * @fw_status: Current ROM / FW status 113 + * @lec: Last ROM / FW error code 114 + * @fps: Current DSP clock status 115 + * @lnec: Last Native Error Code(from external library) 116 + * @ltr: Copy of LTRC HW register value(FW only) 117 + * @rsvd0: Reserved0 118 + * @rom_info: ROM info 119 + * @abi_ver: Version of the layout, set to the current FW_REGS_ABI_VER 120 + * @slave_core_sts: Slave core states 121 + * @rsvd2: Reserved2 122 + * @pipeline_regs: State of pipelines attached to host output gateways 123 + * @peak_vol_regs: State of PeakVol instances indexed by the PeakVol's instance_id 124 + * @llp_gpdma_reading_slots: LLP Readings for single link gateways 125 + * @llp_sndw_reading_slots: SNDW aggregated link gateways 126 + * @llp_evad_reading_slot: LLP Readings for EVAD gateway 127 + */ 128 + struct sof_ipc4_fw_registers { 129 + u32 fw_status; 130 + u32 lec; 131 + u32 fps; 132 + u32 lnec; 133 + u32 ltr; 134 + u32 rsvd0; 135 + u32 rom_info; 136 + u32 abi_ver; 137 + u8 slave_core_sts[SOF_IPC4_MAX_SUPPORTED_ADSP_CORES]; 138 + u32 rsvd2[6]; 139 + 140 + struct sof_ipc4_pipeline_registers 141 + pipeline_regs[SOF_IPC4_MAX_PIPELINE_REG_SLOTS]; 142 + 143 + struct sof_ipc4_peak_volume_regs 144 + peak_vol_regs[SOF_IPC4_MAX_PEAK_VOL_REG_SLOTS]; 145 + 146 + struct sof_ipc4_llp_reading_slot 147 + llp_gpdma_reading_slots[SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS]; 148 + 149 + struct sof_ipc4_llp_reading_slot 150 + llp_sndw_reading_slots[SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS]; 151 + 152 + struct sof_ipc4_llp_reading_slot llp_evad_reading_slot; 153 + } __packed __aligned(4); 154 + 155 + #endif
+232
sound/soc/sof/ipc4-pcm.c
··· 10 10 #include <sound/sof/ipc4/header.h> 11 11 #include "sof-audio.h" 12 12 #include "sof-priv.h" 13 + #include "ops.h" 13 14 #include "ipc4-priv.h" 14 15 #include "ipc4-topology.h" 16 + #include "ipc4-fw-reg.h" 15 17 16 18 static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state, 17 19 struct ipc4_pipeline_set_state_data *trigger_list) ··· 412 410 pipeline_list = &spcm->stream[stream].pipeline_list; 413 411 kfree(pipeline_list->pipelines); 414 412 pipeline_list->pipelines = NULL; 413 + kfree(spcm->stream[stream].private); 414 + spcm->stream[stream].private = NULL; 415 415 } 416 416 } 417 417 ··· 421 417 { 422 418 struct snd_sof_pcm_stream_pipeline_list *pipeline_list; 423 419 struct sof_ipc4_fw_data *ipc4_data = sdev->private; 420 + struct sof_ipc4_timestamp_info *stream_info; 421 + bool support_info = true; 422 + u32 abi_version; 423 + u32 abi_offset; 424 424 int stream; 425 + 426 + abi_offset = offsetof(struct sof_ipc4_fw_registers, abi_ver); 427 + sof_mailbox_read(sdev, sdev->fw_info_box.offset + abi_offset, &abi_version, 428 + sizeof(abi_version)); 429 + 430 + if (abi_version < SOF_IPC4_FW_REGS_ABI_VER) 431 + support_info = false; 425 432 426 433 for_each_pcm_streams(stream) { 427 434 pipeline_list = &spcm->stream[stream].pipeline_list; ··· 444 429 sof_ipc4_pcm_free(sdev, spcm); 445 430 return -ENOMEM; 446 431 } 432 + 433 + if (!support_info) 434 + continue; 435 + 436 + stream_info = kzalloc(sizeof(*stream_info), GFP_KERNEL); 437 + if (!stream_info) { 438 + sof_ipc4_pcm_free(sdev, spcm); 439 + return -ENOMEM; 440 + } 441 + 442 + spcm->stream[stream].private = stream_info; 447 443 } 448 444 449 445 return 0; 450 446 } 451 447 448 + static void sof_ipc4_build_time_info(struct snd_sof_dev *sdev, struct snd_sof_pcm_stream *spcm) 449 + { 450 + struct sof_ipc4_copier *host_copier = NULL; 451 + struct sof_ipc4_copier *dai_copier = NULL; 452 + struct sof_ipc4_llp_reading_slot llp_slot; 453 + struct sof_ipc4_timestamp_info *info; 454 + struct snd_soc_dapm_widget *widget; 455 + struct snd_sof_dai *dai; 456 + int i; 457 + 458 + /* find host & dai to locate info in memory window */ 459 + for_each_dapm_widgets(spcm->list, i, widget) { 460 + struct snd_sof_widget *swidget = widget->dobj.private; 461 + 462 + if (!swidget) 463 + continue; 464 + 465 + if (WIDGET_IS_AIF(swidget->widget->id)) { 466 + host_copier = swidget->private; 467 + } else if (WIDGET_IS_DAI(swidget->widget->id)) { 468 + dai = swidget->private; 469 + dai_copier = dai->private; 470 + } 471 + } 472 + 473 + /* both host and dai copier must be valid for time_info */ 474 + if (!host_copier || !dai_copier) { 475 + dev_err(sdev->dev, "host or dai copier are not found\n"); 476 + return; 477 + } 478 + 479 + info = spcm->private; 480 + info->host_copier = host_copier; 481 + info->dai_copier = dai_copier; 482 + info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_gpdma_reading_slots) + 483 + sdev->fw_info_box.offset; 484 + 485 + /* find llp slot used by current dai */ 486 + for (i = 0; i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS; i++) { 487 + sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 488 + if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) 489 + break; 490 + 491 + info->llp_offset += sizeof(llp_slot); 492 + } 493 + 494 + if (i < SOF_IPC4_MAX_LLP_GPDMA_READING_SLOTS) 495 + return; 496 + 497 + /* if no llp gpdma slot is used, check aggregated sdw slot */ 498 + info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_sndw_reading_slots) + 499 + sdev->fw_info_box.offset; 500 + for (i = 0; i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS; i++) { 501 + sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 502 + if (llp_slot.node_id == dai_copier->data.gtw_cfg.node_id) 503 + break; 504 + 505 + info->llp_offset += sizeof(llp_slot); 506 + } 507 + 508 + if (i < SOF_IPC4_MAX_LLP_SNDW_READING_SLOTS) 509 + return; 510 + 511 + /* check EVAD slot */ 512 + info->llp_offset = offsetof(struct sof_ipc4_fw_registers, llp_evad_reading_slot) + 513 + sdev->fw_info_box.offset; 514 + sof_mailbox_read(sdev, info->llp_offset, &llp_slot, sizeof(llp_slot)); 515 + if (llp_slot.node_id != dai_copier->data.gtw_cfg.node_id) { 516 + dev_info(sdev->dev, "no llp found, fall back to default HDA path"); 517 + info->llp_offset = 0; 518 + } 519 + } 520 + 521 + static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component, 522 + struct snd_pcm_substream *substream, 523 + struct snd_pcm_hw_params *params, 524 + struct snd_sof_platform_stream_params *platform_params) 525 + { 526 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 527 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 528 + struct sof_ipc4_timestamp_info *time_info; 529 + struct snd_sof_pcm *spcm; 530 + 531 + spcm = snd_sof_find_spcm_dai(component, rtd); 532 + time_info = spcm->stream[substream->stream].private; 533 + /* delay calculation is not supported by current fw_reg ABI */ 534 + if (!time_info) 535 + return 0; 536 + 537 + time_info->stream_start_offset = SOF_IPC4_INVALID_STREAM_POSITION; 538 + time_info->llp_offset = 0; 539 + 540 + sof_ipc4_build_time_info(sdev, &spcm->stream[substream->stream]); 541 + 542 + return 0; 543 + } 544 + 545 + static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev, 546 + struct snd_pcm_substream *substream, 547 + struct snd_sof_pcm_stream *stream, 548 + struct sof_ipc4_timestamp_info *time_info) 549 + { 550 + struct sof_ipc4_copier *host_copier = time_info->host_copier; 551 + struct sof_ipc4_copier *dai_copier = time_info->dai_copier; 552 + struct sof_ipc4_pipeline_registers ppl_reg; 553 + u64 stream_start_position; 554 + u32 dai_sample_size; 555 + u32 ch, node_index; 556 + u32 offset; 557 + 558 + if (!host_copier || !dai_copier) 559 + return -EINVAL; 560 + 561 + if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_INVALID_NODE_ID) 562 + return -EINVAL; 563 + 564 + node_index = SOF_IPC4_NODE_INDEX(host_copier->data.gtw_cfg.node_id); 565 + offset = offsetof(struct sof_ipc4_fw_registers, pipeline_regs) + node_index * sizeof(ppl_reg); 566 + sof_mailbox_read(sdev, sdev->fw_info_box.offset + offset, &ppl_reg, sizeof(ppl_reg)); 567 + if (ppl_reg.stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) 568 + return -EINVAL; 569 + 570 + stream_start_position = ppl_reg.stream_start_offset; 571 + ch = dai_copier->data.out_format.fmt_cfg; 572 + ch = SOF_IPC4_AUDIO_FORMAT_CFG_CHANNELS_COUNT(ch); 573 + dai_sample_size = (dai_copier->data.out_format.bit_depth >> 3) * ch; 574 + /* convert offset to sample count */ 575 + do_div(stream_start_position, dai_sample_size); 576 + time_info->stream_start_offset = stream_start_position; 577 + 578 + return 0; 579 + } 580 + 581 + static snd_pcm_sframes_t sof_ipc4_pcm_delay(struct snd_soc_component *component, 582 + struct snd_pcm_substream *substream) 583 + { 584 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 585 + struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 586 + struct sof_ipc4_timestamp_info *time_info; 587 + struct sof_ipc4_llp_reading_slot llp; 588 + snd_pcm_uframes_t head_ptr, tail_ptr; 589 + struct snd_sof_pcm_stream *stream; 590 + struct snd_sof_pcm *spcm; 591 + u64 tmp_ptr; 592 + int ret; 593 + 594 + spcm = snd_sof_find_spcm_dai(component, rtd); 595 + if (!spcm) 596 + return 0; 597 + 598 + stream = &spcm->stream[substream->stream]; 599 + time_info = stream->private; 600 + if (!time_info) 601 + return 0; 602 + 603 + /* 604 + * stream_start_offset is updated to memory window by FW based on 605 + * pipeline statistics and it may be invalid if host query happens before 606 + * the statistics is complete. And it will not change after the first initiailization. 607 + */ 608 + if (time_info->stream_start_offset == SOF_IPC4_INVALID_STREAM_POSITION) { 609 + ret = sof_ipc4_get_stream_start_offset(sdev, substream, stream, time_info); 610 + if (ret < 0) 611 + return 0; 612 + } 613 + 614 + /* 615 + * HDaudio links don't support the LLP counter reported by firmware 616 + * the link position is read directly from hardware registers. 617 + */ 618 + if (!time_info->llp_offset) { 619 + tmp_ptr = snd_sof_pcm_get_stream_position(sdev, component, substream); 620 + if (!tmp_ptr) 621 + return 0; 622 + } else { 623 + sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp)); 624 + tmp_ptr = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l; 625 + } 626 + 627 + /* In two cases dai dma position is not accurate 628 + * (1) dai pipeline is started before host pipeline 629 + * (2) multiple streams mixed into one. Each stream has the same dai dma position 630 + * 631 + * Firmware calculates correct stream_start_offset for all cases including above two. 632 + * Driver subtracts stream_start_offset from dai dma position to get accurate one 633 + */ 634 + tmp_ptr -= time_info->stream_start_offset; 635 + 636 + /* Calculate the delay taking into account that both pointer can wrap */ 637 + div64_u64_rem(tmp_ptr, substream->runtime->boundary, &tmp_ptr); 638 + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 639 + head_ptr = substream->runtime->status->hw_ptr; 640 + tail_ptr = tmp_ptr; 641 + } else { 642 + head_ptr = tmp_ptr; 643 + tail_ptr = substream->runtime->status->hw_ptr; 644 + } 645 + 646 + if (head_ptr < tail_ptr) 647 + return substream->runtime->boundary - tail_ptr + head_ptr; 648 + 649 + return head_ptr - tail_ptr; 650 + } 651 + 452 652 const struct sof_ipc_pcm_ops ipc4_pcm_ops = { 653 + .hw_params = sof_ipc4_pcm_hw_params, 453 654 .trigger = sof_ipc4_pcm_trigger, 454 655 .hw_free = sof_ipc4_pcm_hw_free, 455 656 .dai_link_fixup = sof_ipc4_pcm_dai_link_fixup, 456 657 .pcm_setup = sof_ipc4_pcm_setup, 457 658 .pcm_free = sof_ipc4_pcm_free, 659 + .delay = sof_ipc4_pcm_delay 458 660 };
+15
sound/soc/sof/ipc4-priv.h
··· 14 14 #include "sof-priv.h" 15 15 16 16 /* The DSP window indices are fixed */ 17 + #define SOF_IPC4_INBOX_WINDOW_IDX 0 17 18 #define SOF_IPC4_OUTBOX_WINDOW_IDX 1 18 19 #define SOF_IPC4_DEBUG_WINDOW_IDX 2 19 20 ··· 85 84 int (*load_library)(struct snd_sof_dev *sdev, 86 85 struct sof_ipc4_fw_library *fw_lib, bool reload); 87 86 struct mutex pipeline_state_mutex; /* protect pipeline triggers, ref counts and states */ 87 + }; 88 + 89 + /** 90 + * struct sof_ipc4_timestamp_info - IPC4 timestamp info 91 + * @host_copier: the host copier of the pcm stream 92 + * @dai_copier: the dai copier of the pcm stream 93 + * @stream_start_offset: reported by fw in memory window 94 + * @llp_offset: llp offset in memory window 95 + */ 96 + struct sof_ipc4_timestamp_info { 97 + struct sof_ipc4_copier *host_copier; 98 + struct sof_ipc4_copier *dai_copier; 99 + u64 stream_start_offset; 100 + u32 llp_offset; 88 101 }; 89 102 90 103 extern const struct sof_ipc_fw_loader_ops ipc4_loader_ops;
+3
sound/soc/sof/ipc4.c
··· 13 13 #include <sound/sof/ipc4/header.h> 14 14 #include "sof-priv.h" 15 15 #include "sof-audio.h" 16 + #include "ipc4-fw-reg.h" 16 17 #include "ipc4-priv.h" 17 18 #include "ops.h" 18 19 ··· 543 542 outbox_offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_OUTBOX_WINDOW_IDX); 544 543 outbox_size = SOF_IPC4_MSG_MAX_SIZE; 545 544 545 + sdev->fw_info_box.offset = snd_sof_dsp_get_window_offset(sdev, SOF_IPC4_INBOX_WINDOW_IDX); 546 + sdev->fw_info_box.size = sizeof(struct sof_ipc4_fw_registers); 546 547 sdev->dsp_box.offset = inbox_offset; 547 548 sdev->dsp_box.size = inbox_size; 548 549 sdev->host_box.offset = outbox_offset;
+10
sound/soc/sof/ops.h
··· 511 511 return 0; 512 512 } 513 513 514 + static inline u64 snd_sof_pcm_get_stream_position(struct snd_sof_dev *sdev, 515 + struct snd_soc_component *component, 516 + struct snd_pcm_substream *substream) 517 + { 518 + if (sof_ops(sdev) && sof_ops(sdev)->get_stream_position) 519 + return sof_ops(sdev)->get_stream_position(sdev, component, substream); 520 + 521 + return 0; 522 + } 523 + 514 524 /* machine driver */ 515 525 static inline int 516 526 snd_sof_machine_register(struct snd_sof_dev *sdev, void *pdata)
+13
sound/soc/sof/pcm.c
··· 646 646 return snd_sof_pcm_platform_ack(sdev, substream); 647 647 } 648 648 649 + static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component, 650 + struct snd_pcm_substream *substream) 651 + { 652 + struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component); 653 + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); 654 + 655 + if (pcm_ops && pcm_ops->delay) 656 + return pcm_ops->delay(component, substream); 657 + 658 + return 0; 659 + } 660 + 649 661 void snd_sof_new_platform_drv(struct snd_sof_dev *sdev) 650 662 { 651 663 struct snd_soc_component_driver *pd = &sdev->plat_drv; ··· 682 670 pd->trigger = sof_pcm_trigger; 683 671 pd->pointer = sof_pcm_pointer; 684 672 pd->ack = sof_pcm_ack; 673 + pd->delay = sof_pcm_delay; 685 674 686 675 #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) 687 676 pd->compress_ops = &sof_compressed_ops;
+6
sound/soc/sof/sof-audio.h
··· 102 102 * additional memory in the SOF PCM stream structure 103 103 * @pcm_free: Function pointer for PCM free that can be used for freeing any 104 104 * additional memory in the SOF PCM stream structure 105 + * @delay: Function pointer for pcm delay calculation 105 106 */ 106 107 struct sof_ipc_pcm_ops { 107 108 int (*hw_params)(struct snd_soc_component *component, struct snd_pcm_substream *substream, ··· 114 113 int (*dai_link_fixup)(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params); 115 114 int (*pcm_setup)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); 116 115 void (*pcm_free)(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); 116 + snd_pcm_sframes_t (*delay)(struct snd_soc_component *component, 117 + struct snd_pcm_substream *substream); 117 118 }; 118 119 119 120 /** ··· 314 311 */ 315 312 bool suspend_ignored; 316 313 struct snd_sof_pcm_stream_pipeline_list pipeline_list; 314 + 315 + /* used by IPC implementation and core does not touch it */ 316 + void *private; 317 317 }; 318 318 319 319 /* ALSA SOF PCM device */
+10
sound/soc/sof/sof-priv.h
··· 248 248 /* pcm ack */ 249 249 int (*pcm_ack)(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream); /* optional */ 250 250 251 + /* 252 + * optional callback to retrieve the link DMA position for the substream 253 + * when the position is not reported in the shared SRAM windows but 254 + * instead from a host-accessible hardware counter. 255 + */ 256 + u64 (*get_stream_position)(struct snd_sof_dev *sdev, 257 + struct snd_soc_component *component, 258 + struct snd_pcm_substream *substream); /* optional */ 259 + 251 260 /* host read DSP stream data */ 252 261 int (*ipc_msg_data)(struct snd_sof_dev *sdev, 253 262 struct snd_sof_pcm_stream *sps, ··· 557 548 558 549 /* IPC */ 559 550 struct snd_sof_ipc *ipc; 551 + struct snd_sof_mailbox fw_info_box; /* FW shared memory */ 560 552 struct snd_sof_mailbox dsp_box; /* DSP initiated IPC */ 561 553 struct snd_sof_mailbox host_box; /* Host initiated IPC */ 562 554 struct snd_sof_mailbox stream_box; /* Stream position update */