Skip to content

Commit 3849c4d

Browse files
committed
ASoC: SOF: ipc4/Intel: Fix delay reporting
Merge series from Peter Ujfalusi <[email protected]>: The current version of delay reporting code can report incorrect values when paired with a firmware which enables this feature. Unfortunately there are several smaller issues that needed to be addressed to correct the behavior: Wrong information was used for the host side of counter For MTL/LNL used incorrect (in a sense that it was verified only on MTL) link side counter function. The link side counter needs compensation logic if pause/resume is used. The offset values were not refreshed from firmware. Finally, not strictly connected, but the ALSA buffer size needs to be constrained to avoid constant xrun from media players (like mpv) The series applies cleanly for 6.9 and 6.8.y stable, but older stable would need manual backport, but it is questionable if it is needed as MTL/LNL is missing features.
2 parents 56ebbd1 + 1abc264 commit 3849c4d

File tree

16 files changed

+351
-89
lines changed

16 files changed

+351
-89
lines changed

include/sound/hdaudio_ext.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ struct hdac_ext_stream {
5656
u32 pphcldpl;
5757
u32 pphcldpu;
5858

59+
u32 pplcllpl;
60+
u32 pplcllpu;
61+
5962
bool decoupled:1;
6063
bool link_locked:1;
6164
bool link_prepared;

sound/soc/sof/intel/hda-common-ops.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ struct snd_sof_dsp_ops sof_hda_common_ops = {
5757
.pcm_pointer = hda_dsp_pcm_pointer,
5858
.pcm_ack = hda_dsp_pcm_ack,
5959

60+
.get_dai_frame_counter = hda_dsp_get_stream_llp,
61+
.get_host_byte_counter = hda_dsp_get_stream_ldp,
62+
6063
/* firmware loading */
6164
.load_firmware = snd_sof_load_firmware_raw,
6265

sound/soc/sof/intel/hda-dai-ops.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <sound/pcm_params.h>
99
#include <sound/hdaudio_ext.h>
10+
#include <sound/hda_register.h>
1011
#include <sound/hda-mlink.h>
1112
#include <sound/sof/ipc4/header.h>
1213
#include <uapi/sound/sof/header.h>
@@ -362,6 +363,16 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
362363
case SNDRV_PCM_TRIGGER_STOP:
363364
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
364365
snd_hdac_ext_stream_clear(hext_stream);
366+
367+
/*
368+
* Save the LLP registers in case the stream is
369+
* restarting due PAUSE_RELEASE, or START without a pcm
370+
* close/open since in this case the LLP register is not reset
371+
* to 0 and the delay calculation will return with invalid
372+
* results.
373+
*/
374+
hext_stream->pplcllpl = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
375+
hext_stream->pplcllpu = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
365376
break;
366377
default:
367378
dev_err(sdev->dev, "unknown trigger command %d\n", cmd);

sound/soc/sof/intel/hda-pcm.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,37 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
259259
snd_pcm_hw_constraint_mask64(substream->runtime, SNDRV_PCM_HW_PARAM_FORMAT,
260260
SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_S32);
261261

262+
/*
263+
* The dsp_max_burst_size_in_ms is the length of the maximum burst size
264+
* of the host DMA in the ALSA buffer.
265+
*
266+
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
267+
* amount of data in one initial burst to fill up the host DMA buffer.
268+
* Consequent DMA burst sizes are shorter and their length can vary.
269+
* To make sure that userspace allocate large enough ALSA buffer we need
270+
* to place a constraint on the buffer time.
271+
*
272+
* On capture the DMA will transfer 1ms chunks.
273+
*
274+
* Exact dsp_max_burst_size_in_ms constraint is racy, so set the
275+
* constraint to a minimum of 2x dsp_max_burst_size_in_ms.
276+
*/
277+
if (spcm->stream[direction].dsp_max_burst_size_in_ms)
278+
snd_pcm_hw_constraint_minmax(substream->runtime,
279+
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
280+
spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
281+
UINT_MAX);
282+
262283
/* binding pcm substream to hda stream */
263284
substream->runtime->private_data = &dsp_stream->hstream;
285+
286+
/*
287+
* Reset the llp cache values (they are used for LLP compensation in
288+
* case the counter is not reset)
289+
*/
290+
dsp_stream->pplcllpl = 0;
291+
dsp_stream->pplcllpu = 0;
292+
264293
return 0;
265294
}
266295

sound/soc/sof/intel/hda-stream.c

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,3 +1063,73 @@ snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
10631063

10641064
return pos;
10651065
}
1066+
1067+
#define merge_u64(u32_u, u32_l) (((u64)(u32_u) << 32) | (u32_l))
1068+
1069+
/**
1070+
* hda_dsp_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream
1071+
* @sdev: SOF device
1072+
* @component: ASoC component
1073+
* @substream: PCM substream
1074+
*
1075+
* Returns the raw Linear Link Position value
1076+
*/
1077+
u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
1078+
struct snd_soc_component *component,
1079+
struct snd_pcm_substream *substream)
1080+
{
1081+
struct hdac_stream *hstream = substream->runtime->private_data;
1082+
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
1083+
u32 llp_l, llp_u;
1084+
1085+
/*
1086+
* The pplc_addr have been calculated during probe in
1087+
* hda_dsp_stream_init():
1088+
* pplc_addr = sdev->bar[HDA_DSP_PP_BAR] +
1089+
* SOF_HDA_PPLC_BASE +
1090+
* SOF_HDA_PPLC_MULTI * total_stream +
1091+
* SOF_HDA_PPLC_INTERVAL * stream_index
1092+
*
1093+
* Use this pre-calculated address to avoid repeated re-calculation.
1094+
*/
1095+
llp_l = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPL);
1096+
llp_u = readl(hext_stream->pplc_addr + AZX_REG_PPLCLLPU);
1097+
1098+
/* Compensate the LLP counter with the saved offset */
1099+
if (hext_stream->pplcllpl || hext_stream->pplcllpu)
1100+
return merge_u64(llp_u, llp_l) -
1101+
merge_u64(hext_stream->pplcllpu, hext_stream->pplcllpl);
1102+
1103+
return merge_u64(llp_u, llp_l);
1104+
}
1105+
1106+
/**
1107+
* hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream
1108+
* @sdev: SOF device
1109+
* @component: ASoC component
1110+
* @substream: PCM substream
1111+
*
1112+
* Returns the raw Linear Link Position value
1113+
*/
1114+
u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
1115+
struct snd_soc_component *component,
1116+
struct snd_pcm_substream *substream)
1117+
{
1118+
struct hdac_stream *hstream = substream->runtime->private_data;
1119+
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
1120+
u32 ldp_l, ldp_u;
1121+
1122+
/*
1123+
* The pphc_addr have been calculated during probe in
1124+
* hda_dsp_stream_init():
1125+
* pphc_addr = sdev->bar[HDA_DSP_PP_BAR] +
1126+
* SOF_HDA_PPHC_BASE +
1127+
* SOF_HDA_PPHC_INTERVAL * stream_index
1128+
*
1129+
* Use this pre-calculated address to avoid repeated re-calculation.
1130+
*/
1131+
ldp_l = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPL);
1132+
ldp_u = readl(hext_stream->pphc_addr + AZX_REG_PPHCLDPU);
1133+
1134+
return ((u64)ldp_u << 32) | ldp_l;
1135+
}

sound/soc/sof/intel/hda.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,12 @@ bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev);
662662

663663
snd_pcm_uframes_t hda_dsp_stream_get_position(struct hdac_stream *hstream,
664664
int direction, bool can_sleep);
665+
u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
666+
struct snd_soc_component *component,
667+
struct snd_pcm_substream *substream);
668+
u64 hda_dsp_get_stream_ldp(struct snd_sof_dev *sdev,
669+
struct snd_soc_component *component,
670+
struct snd_pcm_substream *substream);
665671

666672
struct hdac_ext_stream *
667673
hda_dsp_stream_get(struct snd_sof_dev *sdev, int direction, u32 flags);

sound/soc/sof/intel/lnl.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,6 @@ int sof_lnl_ops_init(struct snd_sof_dev *sdev)
134134
sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume;
135135
}
136136

137-
sof_lnl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
138-
139137
/* dsp core get/put */
140138
sof_lnl_ops.core_get = mtl_dsp_core_get;
141139
sof_lnl_ops.core_put = mtl_dsp_core_put;

sound/soc/sof/intel/mtl.c

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -626,18 +626,6 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev)
626626
return mtl_enable_interrupts(sdev, false);
627627
}
628628

629-
u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
630-
struct snd_soc_component *component,
631-
struct snd_pcm_substream *substream)
632-
{
633-
struct hdac_stream *hstream = substream->runtime->private_data;
634-
u32 llp_l, llp_u;
635-
636-
llp_l = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPL(hstream->index));
637-
llp_u = snd_sof_dsp_read(sdev, HDA_DSP_HDA_BAR, MTL_PPLCLLPU(hstream->index));
638-
return ((u64)llp_u << 32) | llp_l;
639-
}
640-
641629
int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core)
642630
{
643631
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
@@ -707,8 +695,6 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev)
707695
sof_mtl_ops.core_get = mtl_dsp_core_get;
708696
sof_mtl_ops.core_put = mtl_dsp_core_put;
709697

710-
sof_mtl_ops.get_stream_position = mtl_dsp_get_stream_hda_link_position;
711-
712698
sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL);
713699
if (!sdev->private)
714700
return -ENOMEM;

sound/soc/sof/intel/mtl.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,6 @@
66
* Copyright(c) 2020-2022 Intel Corporation. All rights reserved.
77
*/
88

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-
159
/* DSP Registers */
1610
#define MTL_HFDSSCS 0x1000
1711
#define MTL_HFDSSCS_SPA_MASK BIT(16)
@@ -103,9 +97,5 @@ int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id);
10397

10498
void mtl_ipc_dump(struct snd_sof_dev *sdev);
10599

106-
u64 mtl_dsp_get_stream_hda_link_position(struct snd_sof_dev *sdev,
107-
struct snd_soc_component *component,
108-
struct snd_pcm_substream *substream);
109-
110100
int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core);
111101
int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core);

0 commit comments

Comments
 (0)