Skip to content

Commit ca7a231

Browse files
committed
Merge tag 'asoc-fix-v6.18-merge-window' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus
ASoC: Fixes for v6.18 A small pile of fixes, almost all for the Intel and SOF code surrounding management of the host buffer. We've also got one fix for Meson and new device IDs and quirk supporting the RT722VB.
2 parents f4ace70 + a275398 commit ca7a231

File tree

11 files changed

+179
-48
lines changed

11 files changed

+179
-48
lines changed

sound/soc/codecs/rt722-sdca-sdw.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg)
2121
switch (reg) {
2222
case 0x2f01 ... 0x2f0a:
2323
case 0x2f35 ... 0x2f36:
24-
case 0x2f50:
24+
case 0x2f50 ... 0x2f52:
2525
case 0x2f54:
2626
case 0x2f58 ... 0x2f5d:
2727
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):

sound/soc/codecs/rt722-sdca.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,9 @@ static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
13781378
/* PHYtiming TDZ/TZD control */
13791379
regmap_write(rt722->regmap, 0x2f03, 0x06);
13801380

1381+
if (rt722->hw_vid == RT722_VB)
1382+
regmap_write(rt722->regmap, 0x2f52, 0x00);
1383+
13811384
/* clear flag */
13821385
regmap_write(rt722->regmap,
13831386
SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
@@ -1415,6 +1418,9 @@ static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
14151418
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
14161419
RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
14171420

1421+
if (rt722->hw_vid == RT722_VB)
1422+
regmap_write(rt722->regmap, 0x2f54, 0x00);
1423+
14181424
/* clear flag */
14191425
regmap_write(rt722->regmap,
14201426
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
@@ -1506,6 +1512,9 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
15061512
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
15071513
0x0010);
15081514

1515+
if (rt722->hw_vid == RT722_VB)
1516+
regmap_write(rt722->regmap, 0x2f51, 0x00);
1517+
15091518
/* clear flag */
15101519
regmap_write(rt722->regmap,
15111520
SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
@@ -1516,6 +1525,7 @@ static void rt722_sdca_jack_preset(struct rt722_sdca_priv *rt722)
15161525
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
15171526
{
15181527
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
1528+
unsigned int val;
15191529

15201530
rt722->disable_irq = false;
15211531

@@ -1545,6 +1555,10 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
15451555

15461556
pm_runtime_get_noresume(&slave->dev);
15471557

1558+
rt722_sdca_index_read(rt722, RT722_VENDOR_REG, RT722_JD_PRODUCT_NUM, &val);
1559+
rt722->hw_vid = (val & 0x0f00) >> 8;
1560+
dev_dbg(&slave->dev, "%s hw_vid=0x%x\n", __func__, rt722->hw_vid);
1561+
15481562
rt722_sdca_dmic_preset(rt722);
15491563
rt722_sdca_amp_preset(rt722);
15501564
rt722_sdca_jack_preset(rt722);

sound/soc/codecs/rt722-sdca.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct rt722_sdca_priv {
3939
/* For DMIC */
4040
bool fu1e_dapm_mute;
4141
bool fu1e_mixer_mute[4];
42+
int hw_vid;
4243
};
4344

4445
struct rt722_sdca_dmic_kctrl_priv {
@@ -233,6 +234,11 @@ enum rt722_sdca_jd_src {
233234
RT722_JD1,
234235
};
235236

237+
enum rt722_sdca_version {
238+
RT722_VA,
239+
RT722_VB,
240+
};
241+
236242
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
237243
int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
238244
int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,

sound/soc/meson/aiu-encoder-i2s.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
236236
inv == SND_SOC_DAIFMT_IB_IF)
237237
val |= AIU_CLK_CTRL_LRCLK_INVERT;
238238

239-
if (inv == SND_SOC_DAIFMT_IB_NF ||
240-
inv == SND_SOC_DAIFMT_IB_IF)
239+
/*
240+
* The SoC changes data on the rising edge of the bitclock
241+
* so an inversion of the bitclock is required in normal mode
242+
*/
243+
if (inv == SND_SOC_DAIFMT_NB_NF ||
244+
inv == SND_SOC_DAIFMT_NB_IF)
241245
val |= AIU_CLK_CTRL_AOCLK_INVERT;
242246

243247
/* Signal skew */
@@ -328,4 +332,3 @@ const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
328332
.startup = aiu_encoder_i2s_startup,
329333
.shutdown = aiu_encoder_i2s_shutdown,
330334
};
331-

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
#define SDnFMT_BITS(x) ((x) << 4)
3030
#define SDnFMT_CHAN(x) ((x) << 0)
3131

32+
#define HDA_MAX_PERIOD_TIME_HEADROOM 10
33+
3234
static bool hda_always_enable_dmi_l1;
3335
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
3436
MODULE_PARM_DESC(always_enable_dmi_l1, "SOF HDA always enable DMI l1");
@@ -291,19 +293,30 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
291293
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
292294
* amount of data in one initial burst to fill up the host DMA buffer.
293295
* Consequent DMA burst sizes are shorter and their length can vary.
294-
* To make sure that userspace allocate large enough ALSA buffer we need
295-
* to place a constraint on the buffer time.
296+
* To avoid immediate xrun by the initial burst we need to place
297+
* constraint on the period size (via PERIOD_TIME) to cover the size of
298+
* the host buffer.
299+
* We need to add headroom of max 10ms as the firmware needs time to
300+
* settle to the 1ms pacing and initially it can run faster for few
301+
* internal periods.
296302
*
297303
* On capture the DMA will transfer 1ms chunks.
298-
*
299-
* Exact dsp_max_burst_size_in_ms constraint is racy, so set the
300-
* constraint to a minimum of 2x dsp_max_burst_size_in_ms.
301304
*/
302-
if (spcm->stream[direction].dsp_max_burst_size_in_ms)
305+
if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
306+
unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
307+
308+
/*
309+
* add headroom over the maximum burst size to cover the time
310+
* needed for the DMA pace to settle.
311+
* Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
312+
*/
313+
period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
314+
303315
snd_pcm_hw_constraint_minmax(substream->runtime,
304-
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
305-
spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
316+
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
317+
period_time * USEC_PER_MSEC,
306318
UINT_MAX);
319+
}
307320

308321
/* binding pcm substream to hda stream */
309322
substream->runtime->private_data = &dsp_stream->hstream;

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,10 +1129,35 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
11291129
struct snd_soc_component *component,
11301130
struct snd_pcm_substream *substream)
11311131
{
1132-
struct hdac_stream *hstream = substream->runtime->private_data;
1133-
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
1132+
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
1133+
struct snd_soc_pcm_runtime *be_rtd = NULL;
1134+
struct hdac_ext_stream *hext_stream;
1135+
struct snd_soc_dai *cpu_dai;
1136+
struct snd_soc_dpcm *dpcm;
11341137
u32 llp_l, llp_u;
11351138

1139+
/*
1140+
* The LLP needs to be read from the Link DMA used for this FE as it is
1141+
* allowed to use any combination of Link and Host channels
1142+
*/
1143+
for_each_dpcm_be(rtd, substream->stream, dpcm) {
1144+
if (dpcm->fe != rtd)
1145+
continue;
1146+
1147+
be_rtd = dpcm->be;
1148+
}
1149+
1150+
if (!be_rtd)
1151+
return 0;
1152+
1153+
cpu_dai = snd_soc_rtd_to_cpu(be_rtd, 0);
1154+
if (!cpu_dai)
1155+
return 0;
1156+
1157+
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
1158+
if (!hext_stream)
1159+
return 0;
1160+
11361161
/*
11371162
* The pplc_addr have been calculated during probe in
11381163
* hda_dsp_stream_init():

sound/soc/sof/ipc3-topology.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,11 +2473,6 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
24732473
if (ret < 0)
24742474
return ret;
24752475

2476-
/* free all the scheduler widgets now */
2477-
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
2478-
if (ret < 0)
2479-
return ret;
2480-
24812476
/*
24822477
* Tear down all pipelines associated with PCMs that did not get suspended
24832478
* and unset the prepare flag so that they can be set up again during resume.
@@ -2493,6 +2488,11 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
24932488
}
24942489
}
24952490

2491+
/* free all the scheduler widgets now. This will also power down the secondary cores */
2492+
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
2493+
if (ret < 0)
2494+
return ret;
2495+
24962496
list_for_each_entry(sroute, &sdev->route_list, list)
24972497
sroute->setup = false;
24982498

sound/soc/sof/ipc4-pcm.c

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@
1919
* struct sof_ipc4_timestamp_info - IPC4 timestamp info
2020
* @host_copier: the host copier of the pcm stream
2121
* @dai_copier: the dai copier of the pcm stream
22-
* @stream_start_offset: reported by fw in memory window (converted to frames)
23-
* @stream_end_offset: reported by fw in memory window (converted to frames)
22+
* @stream_start_offset: reported by fw in memory window (converted to
23+
* frames at host_copier sampling rate)
24+
* @stream_end_offset: reported by fw in memory window (converted to
25+
* frames at host_copier sampling rate)
2426
* @llp_offset: llp offset in memory window
25-
* @boundary: wrap boundary should be used for the LLP frame counter
2627
* @delay: Calculated and stored in pointer callback. The stored value is
27-
* returned in the delay callback.
28+
* returned in the delay callback. Expressed in frames at host copier
29+
* sampling rate.
2830
*/
2931
struct sof_ipc4_timestamp_info {
3032
struct sof_ipc4_copier *host_copier;
@@ -33,7 +35,6 @@ struct sof_ipc4_timestamp_info {
3335
u64 stream_end_offset;
3436
u32 llp_offset;
3537

36-
u64 boundary;
3738
snd_pcm_sframes_t delay;
3839
};
3940

@@ -48,6 +49,18 @@ struct sof_ipc4_pcm_stream_priv {
4849
bool chain_dma_allocated;
4950
};
5051

52+
/*
53+
* Modulus to use to compare host and link position counters. The sampling
54+
* rates may be different, so the raw hardware counters will wrap
55+
* around at different times. To calculate differences, use
56+
* DELAY_BOUNDARY as a common modulus. This value must be smaller than
57+
* the wrap-around point of any hardware counter, and larger than any
58+
* valid delay measurement.
59+
*/
60+
#define DELAY_BOUNDARY U32_MAX
61+
62+
#define DELAY_MAX (DELAY_BOUNDARY >> 1)
63+
5164
static inline struct sof_ipc4_timestamp_info *
5265
sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
5366
{
@@ -1049,6 +1062,35 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
10491062
return 0;
10501063
}
10511064

1065+
static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value)
1066+
{
1067+
u64 dai_rate, host_rate;
1068+
1069+
if (!time_info->dai_copier || !time_info->host_copier)
1070+
return value;
1071+
1072+
/*
1073+
* copiers do not change sampling rate, so we can use the
1074+
* out_format independently of stream direction
1075+
*/
1076+
dai_rate = time_info->dai_copier->data.out_format.sampling_frequency;
1077+
host_rate = time_info->host_copier->data.out_format.sampling_frequency;
1078+
1079+
if (!dai_rate || !host_rate || dai_rate == host_rate)
1080+
return value;
1081+
1082+
/* take care not to overflow u64, rates can be up to 768000 */
1083+
if (value > U32_MAX) {
1084+
value = div64_u64(value, dai_rate);
1085+
value *= host_rate;
1086+
} else {
1087+
value *= host_rate;
1088+
value = div64_u64(value, dai_rate);
1089+
}
1090+
1091+
return value;
1092+
}
1093+
10521094
static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
10531095
struct snd_pcm_substream *substream,
10541096
struct snd_sof_pcm_stream *sps,
@@ -1068,18 +1110,24 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
10681110
return -EINVAL;
10691111
} else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
10701112
/*
1071-
* While the firmware does not supports time_info reporting for
1113+
* While the firmware does not support time_info reporting for
10721114
* streams using ChainDMA, it is granted that ChainDMA can only
10731115
* be used on Host+Link pairs where the link position is
10741116
* accessible from the host side.
10751117
*
10761118
* Enable delay calculation in case of ChainDMA via host
10771119
* accessible registers.
10781120
*
1079-
* The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
1080-
* when 1ms data is available
1121+
* The ChainDMA prefills the link DMA with a preamble
1122+
* of zero samples. Set the stream start offset based
1123+
* on size of the preamble (driver provided fifo size
1124+
* multiplied by 2.5). We add 1ms of margin as the FW
1125+
* will align the buffer size to DMA hardware
1126+
* alignment that is not known to host.
10811127
*/
1082-
time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
1128+
int pre_ms = SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 5 / 2 + 1;
1129+
1130+
time_info->stream_start_offset = pre_ms * substream->runtime->rate / MSEC_PER_SEC;
10831131
goto out;
10841132
}
10851133

@@ -1099,14 +1147,13 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
10991147
time_info->stream_end_offset = ppl_reg.stream_end_offset;
11001148
do_div(time_info->stream_end_offset, dai_sample_size);
11011149

1150+
/* convert to host frame time */
1151+
time_info->stream_start_offset =
1152+
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_start_offset);
1153+
time_info->stream_end_offset =
1154+
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_end_offset);
1155+
11021156
out:
1103-
/*
1104-
* Calculate the wrap boundary need to be used for delay calculation
1105-
* The host counter is in bytes, it will wrap earlier than the frames
1106-
* based link counter.
1107-
*/
1108-
time_info->boundary = div64_u64(~((u64)0),
1109-
frames_to_bytes(substream->runtime, 1));
11101157
/* Initialize the delay value to 0 (no delay) */
11111158
time_info->delay = 0;
11121159

@@ -1149,6 +1196,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
11491196

11501197
/* For delay calculation we need the host counter */
11511198
host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream);
1199+
1200+
/* Store the original value to host_ptr */
11521201
host_ptr = host_cnt;
11531202

11541203
/* convert the host_cnt to frames */
@@ -1167,6 +1216,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
11671216
sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp));
11681217
dai_cnt = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l;
11691218
}
1219+
1220+
dai_cnt = sof_ipc4_frames_dai_to_host(time_info, dai_cnt);
11701221
dai_cnt += time_info->stream_end_offset;
11711222

11721223
/* In two cases dai dma counter is not accurate
@@ -1200,8 +1251,9 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
12001251
dai_cnt -= time_info->stream_start_offset;
12011252
}
12021253

1203-
/* Wrap the dai counter at the boundary where the host counter wraps */
1204-
div64_u64_rem(dai_cnt, time_info->boundary, &dai_cnt);
1254+
/* Convert to a common base before comparisons */
1255+
dai_cnt &= DELAY_BOUNDARY;
1256+
host_cnt &= DELAY_BOUNDARY;
12051257

12061258
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
12071259
head_cnt = host_cnt;
@@ -1211,14 +1263,18 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
12111263
tail_cnt = host_cnt;
12121264
}
12131265

1214-
if (head_cnt < tail_cnt) {
1215-
time_info->delay = time_info->boundary - tail_cnt + head_cnt;
1216-
goto out;
1217-
}
1266+
if (unlikely(head_cnt < tail_cnt))
1267+
time_info->delay = DELAY_BOUNDARY - tail_cnt + head_cnt;
1268+
else
1269+
time_info->delay = head_cnt - tail_cnt;
12181270

1219-
time_info->delay = head_cnt - tail_cnt;
1271+
if (time_info->delay > DELAY_MAX) {
1272+
spcm_dbg_ratelimited(spcm, substream->stream,
1273+
"inaccurate delay, host %llu dai_cnt %llu",
1274+
host_cnt, dai_cnt);
1275+
time_info->delay = 0;
1276+
}
12201277

1221-
out:
12221278
/*
12231279
* Convert the host byte counter to PCM pointer which wraps in buffer
12241280
* and it is in frames

0 commit comments

Comments
 (0)