sound fixes for 6.18-rc1

A few more small fixes for 6.18-rc1.
 Most of changes are about ASoC Intel and SOF drivers, while a few
 other device-specific fixes are found for HD-audio, USB-audio, ASoC
 RT722VB and Meson.
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmjpDRYOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE8E2w//ZZ+SGtxenwlrFGdBiPeU82/Zjfq5Iqjyx1ka
 3lptovcX6wAJUkczdyMFiMZgx+B+tnCF8zUMb5VnsKLe5GkS13NcKgWfyjfC5aSW
 M6nmF+fI96CVOr+jwqWtAKU5aGMY4pKUhPYfLg4jFyx2kZJcKA+HJ4DP89qw+y1S
 sOBchQdcwuBXBRPXbI5Fc1EEwpNwn4BNM7E98m4GEx8nsZhT7VLPEdqbwugz19ZY
 csP5JX4UM4dHYjSrK8QdBFjOTwFZwrLsjYJrw4bpORRmIw4WSCnvuBIzgp/xbrq4
 eGQFRFImwj71ZbaiQKfUez3MYxWY1ffjDVV9BRmioEE0os5i8aZnRyEy40OZcUvI
 5s8UQmnI2VE2jXVKl3Kzd7qj2Rhsby5B6wz82IJ7M9sXZiov3MkijKprS95UBCMt
 IpmzyhPB0QxmiibqOoWyYdSSXpwTPr0u/z+m1EWYHmi5y0vgII1oFnyJqXY9QV9n
 UqeZ6P1U96HW4nKfGH1s/Ck3/oFqAUQvcvEJ0IrLb9vUQei5eJn6EoE4+pFfSTz6
 WzK383BtrF6sJd/Gf866tFs2KC7qCwspYuQjQjW+hSdLGvQXvcdi/s87iYqR4iXs
 t/92Xk/MueWVg9Ix19ffZI2ntscr+2kRPy4B5mVdgkCHv0ICIPG0Qn8K3tBpnKey
 AJwRPT4=
 =sfXN
 -----END PGP SIGNATURE-----

Merge tag 'sound-fix-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound fixes from Takashi Iwai:
 "A few more small fixes for 6.18-rc1.

  Most of changes are about ASoC Intel and SOF drivers, while a few
  other device-specific fixes are found for HD-audio, USB-audio, ASoC
  RT722VB and Meson"

* tag 'sound-fix-6.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound:
  ASoC: rt722: add settings for rt722VB
  ASoC: meson: aiu-encoder-i2s: fix bit clock polarity
  ALSA: usb: fpc: replace kmalloc_array followed by copy_from_user with memdup_array_user
  ALSA: hda/tas2781: Enable init_profile_id for device initialization
  ALSA: emu10k1: Fix typo in docs
  ALSA: hda/realtek: Add quirk for ASUS ROG Zephyrus Duo
  ASoC: SOF: Intel: Read the LLP via the associated Link DMA channel
  ASoC: SOF: ipc4-pcm: do not report invalid delay values
  ASoC: SOF: sof-audio: add dev_dbg_ratelimited wrapper
  ASoC: SOF: Intel: hda-pcm: Place the constraint on period time instead of buffer time
  ASoC: SOF: ipc4-topology: Account for different ChainDMA host buffer size
  ASoC: SOF: ipc4-topology: Correct the minimum host DMA buffer size
  ASoC: SOF: ipc4-pcm: fix start offset calculation for chain DMA
  ASoC: SOF: ipc4-pcm: fix delay calculation when DSP resamples
  ASoC: SOF: ipc3-topology: Fix multi-core and static pipelines tear down
  ALSA: hda/hdmi: Add pin fix for HP ProDesk model
This commit is contained in:
Linus Torvalds 2025-10-10 09:55:19 -07:00
commit fdfa38e95e
16 changed files with 206 additions and 55 deletions

View File

@ -66,7 +66,7 @@ FX-bus
name='Clock Source',index=0
---------------------------
This control allows switching the word clock between interally generated
This control allows switching the word clock between internally generated
44.1 or 48 kHz, or a number of external sources.
Note: the sources for the 1616 CardBus card are unclear. Please report your

View File

@ -1549,6 +1549,7 @@ static const struct snd_pci_quirk force_connect_list[] = {
SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1),
SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1),
SND_PCI_QUIRK(0x103c, 0x845a, "HP EliteDesk 800 G4 DM 65W", 1),
SND_PCI_QUIRK(0x103c, 0x83f3, "HP ProDesk 400", 1),
SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),

View File

@ -3735,6 +3735,7 @@ enum {
ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@ -6164,6 +6165,14 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
},
[ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
{ 0x17, 0x90170151 }, /* Internal Speaker LFE */
{ 0x1e, 0x90170150 }, /* Internal Speaker */
{ }
},
}
};
static const struct hda_quirk alc269_fixup_tbl[] = {
@ -6718,6 +6727,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1652, "ASUS ROG Zephyrus Do 15 SE", ALC289_FIXUP_ASUS_ZEPHYRUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),

View File

@ -474,6 +474,12 @@ static void tasdevice_dspfw_init(void *context)
if (tas_priv->fmw->nr_configurations > 0)
tas_priv->cur_conf = 0;
/* Init common setting for different audio profiles */
if (tas_priv->rcabin.init_profile_id >= 0)
tasdevice_select_cfg_blk(tas_priv,
tas_priv->rcabin.init_profile_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
/* If calibrated data occurs error, dsp will still works with default
* calibrated data inside algo.
*/
@ -770,6 +776,12 @@ static int tas2781_system_resume(struct device *dev)
tasdevice_reset(tas_hda->priv);
tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
/* Init common setting for different audio profiles */
if (tas_hda->priv->rcabin.init_profile_id >= 0)
tasdevice_select_cfg_blk(tas_hda->priv,
tas_hda->priv->rcabin.init_profile_id,
TASDEVICE_BIN_BLK_PRE_POWER_UP);
if (tas_hda->priv->playback_started)
tasdevice_tuning_switch(tas_hda->priv, 0);

View File

@ -21,7 +21,7 @@ static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg)
switch (reg) {
case 0x2f01 ... 0x2f0a:
case 0x2f35 ... 0x2f36:
case 0x2f50:
case 0x2f50 ... 0x2f52:
case 0x2f54:
case 0x2f58 ... 0x2f5d:
case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0):

View File

@ -1378,6 +1378,9 @@ static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
/* PHYtiming TDZ/TZD control */
regmap_write(rt722->regmap, 0x2f03, 0x06);
if (rt722->hw_vid == RT722_VB)
regmap_write(rt722->regmap, 0x2f52, 0x00);
/* clear flag */
regmap_write(rt722->regmap,
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)
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23,
RT722_SDCA_CTL_VENDOR_DEF, CH_08), 0x04);
if (rt722->hw_vid == RT722_VB)
regmap_write(rt722->regmap, 0x2f54, 0x00);
/* clear flag */
regmap_write(rt722->regmap,
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)
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_DIGITAL_MISC_CTRL4,
0x0010);
if (rt722->hw_vid == RT722_VB)
regmap_write(rt722->regmap, 0x2f51, 0x00);
/* clear flag */
regmap_write(rt722->regmap,
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)
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
{
struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev);
unsigned int val;
rt722->disable_irq = false;
@ -1545,6 +1555,10 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave)
pm_runtime_get_noresume(&slave->dev);
rt722_sdca_index_read(rt722, RT722_VENDOR_REG, RT722_JD_PRODUCT_NUM, &val);
rt722->hw_vid = (val & 0x0f00) >> 8;
dev_dbg(&slave->dev, "%s hw_vid=0x%x\n", __func__, rt722->hw_vid);
rt722_sdca_dmic_preset(rt722);
rt722_sdca_amp_preset(rt722);
rt722_sdca_jack_preset(rt722);

View File

@ -39,6 +39,7 @@ struct rt722_sdca_priv {
/* For DMIC */
bool fu1e_dapm_mute;
bool fu1e_mixer_mute[4];
int hw_vid;
};
struct rt722_sdca_dmic_kctrl_priv {
@ -233,6 +234,11 @@ enum rt722_sdca_jd_src {
RT722_JD1,
};
enum rt722_sdca_version {
RT722_VA,
RT722_VB,
};
int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave);
int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave);
int rt722_sdca_index_write(struct rt722_sdca_priv *rt722,

View File

@ -236,8 +236,12 @@ static int aiu_encoder_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
inv == SND_SOC_DAIFMT_IB_IF)
val |= AIU_CLK_CTRL_LRCLK_INVERT;
if (inv == SND_SOC_DAIFMT_IB_NF ||
inv == SND_SOC_DAIFMT_IB_IF)
/*
* The SoC changes data on the rising edge of the bitclock
* so an inversion of the bitclock is required in normal mode
*/
if (inv == SND_SOC_DAIFMT_NB_NF ||
inv == SND_SOC_DAIFMT_NB_IF)
val |= AIU_CLK_CTRL_AOCLK_INVERT;
/* Signal skew */
@ -328,4 +332,3 @@ const struct snd_soc_dai_ops aiu_encoder_i2s_dai_ops = {
.startup = aiu_encoder_i2s_startup,
.shutdown = aiu_encoder_i2s_shutdown,
};

View File

@ -29,6 +29,8 @@
#define SDnFMT_BITS(x) ((x) << 4)
#define SDnFMT_CHAN(x) ((x) << 0)
#define HDA_MAX_PERIOD_TIME_HEADROOM 10
static bool hda_always_enable_dmi_l1;
module_param_named(always_enable_dmi_l1, hda_always_enable_dmi_l1, bool, 0444);
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,
* On playback start the DMA will transfer dsp_max_burst_size_in_ms
* amount of data in one initial burst to fill up the host DMA buffer.
* Consequent DMA burst sizes are shorter and their length can vary.
* To make sure that userspace allocate large enough ALSA buffer we need
* to place a constraint on the buffer time.
* To avoid immediate xrun by the initial burst we need to place
* constraint on the period size (via PERIOD_TIME) to cover the size of
* the host buffer.
* We need to add headroom of max 10ms as the firmware needs time to
* settle to the 1ms pacing and initially it can run faster for few
* internal periods.
*
* On capture the DMA will transfer 1ms chunks.
*
* Exact dsp_max_burst_size_in_ms constraint is racy, so set the
* constraint to a minimum of 2x dsp_max_burst_size_in_ms.
*/
if (spcm->stream[direction].dsp_max_burst_size_in_ms)
if (spcm->stream[direction].dsp_max_burst_size_in_ms) {
unsigned int period_time = spcm->stream[direction].dsp_max_burst_size_in_ms;
/*
* add headroom over the maximum burst size to cover the time
* needed for the DMA pace to settle.
* Limit the headroom time to HDA_MAX_PERIOD_TIME_HEADROOM
*/
period_time += min(period_time, HDA_MAX_PERIOD_TIME_HEADROOM);
snd_pcm_hw_constraint_minmax(substream->runtime,
SNDRV_PCM_HW_PARAM_BUFFER_TIME,
spcm->stream[direction].dsp_max_burst_size_in_ms * USEC_PER_MSEC * 2,
SNDRV_PCM_HW_PARAM_PERIOD_TIME,
period_time * USEC_PER_MSEC,
UINT_MAX);
}
/* binding pcm substream to hda stream */
substream->runtime->private_data = &dsp_stream->hstream;

View File

@ -1129,10 +1129,35 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
struct snd_soc_pcm_runtime *be_rtd = NULL;
struct hdac_ext_stream *hext_stream;
struct snd_soc_dai *cpu_dai;
struct snd_soc_dpcm *dpcm;
u32 llp_l, llp_u;
/*
* The LLP needs to be read from the Link DMA used for this FE as it is
* allowed to use any combination of Link and Host channels
*/
for_each_dpcm_be(rtd, substream->stream, dpcm) {
if (dpcm->fe != rtd)
continue;
be_rtd = dpcm->be;
}
if (!be_rtd)
return 0;
cpu_dai = snd_soc_rtd_to_cpu(be_rtd, 0);
if (!cpu_dai)
return 0;
hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
if (!hext_stream)
return 0;
/*
* The pplc_addr have been calculated during probe in
* hda_dsp_stream_init():

View File

@ -2473,11 +2473,6 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif
if (ret < 0)
return ret;
/* free all the scheduler widgets now */
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
if (ret < 0)
return ret;
/*
* Tear down all pipelines associated with PCMs that did not get suspended
* 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
}
}
/* free all the scheduler widgets now. This will also power down the secondary cores */
ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify);
if (ret < 0)
return ret;
list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false;

View File

@ -19,12 +19,14 @@
* struct sof_ipc4_timestamp_info - IPC4 timestamp info
* @host_copier: the host copier of the pcm stream
* @dai_copier: the dai copier of the pcm stream
* @stream_start_offset: reported by fw in memory window (converted to frames)
* @stream_end_offset: reported by fw in memory window (converted to frames)
* @stream_start_offset: reported by fw in memory window (converted to
* frames at host_copier sampling rate)
* @stream_end_offset: reported by fw in memory window (converted to
* frames at host_copier sampling rate)
* @llp_offset: llp offset in memory window
* @boundary: wrap boundary should be used for the LLP frame counter
* @delay: Calculated and stored in pointer callback. The stored value is
* returned in the delay callback.
* returned in the delay callback. Expressed in frames at host copier
* sampling rate.
*/
struct sof_ipc4_timestamp_info {
struct sof_ipc4_copier *host_copier;
@ -33,7 +35,6 @@ struct sof_ipc4_timestamp_info {
u64 stream_end_offset;
u32 llp_offset;
u64 boundary;
snd_pcm_sframes_t delay;
};
@ -48,6 +49,18 @@ struct sof_ipc4_pcm_stream_priv {
bool chain_dma_allocated;
};
/*
* Modulus to use to compare host and link position counters. The sampling
* rates may be different, so the raw hardware counters will wrap
* around at different times. To calculate differences, use
* DELAY_BOUNDARY as a common modulus. This value must be smaller than
* the wrap-around point of any hardware counter, and larger than any
* valid delay measurement.
*/
#define DELAY_BOUNDARY U32_MAX
#define DELAY_MAX (DELAY_BOUNDARY >> 1)
static inline struct sof_ipc4_timestamp_info *
sof_ipc4_sps_to_time_info(struct snd_sof_pcm_stream *sps)
{
@ -1049,6 +1062,35 @@ static int sof_ipc4_pcm_hw_params(struct snd_soc_component *component,
return 0;
}
static u64 sof_ipc4_frames_dai_to_host(struct sof_ipc4_timestamp_info *time_info, u64 value)
{
u64 dai_rate, host_rate;
if (!time_info->dai_copier || !time_info->host_copier)
return value;
/*
* copiers do not change sampling rate, so we can use the
* out_format independently of stream direction
*/
dai_rate = time_info->dai_copier->data.out_format.sampling_frequency;
host_rate = time_info->host_copier->data.out_format.sampling_frequency;
if (!dai_rate || !host_rate || dai_rate == host_rate)
return value;
/* take care not to overflow u64, rates can be up to 768000 */
if (value > U32_MAX) {
value = div64_u64(value, dai_rate);
value *= host_rate;
} else {
value *= host_rate;
value = div64_u64(value, dai_rate);
}
return value;
}
static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream,
struct snd_sof_pcm_stream *sps,
@ -1068,7 +1110,7 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
return -EINVAL;
} else if (host_copier->data.gtw_cfg.node_id == SOF_IPC4_CHAIN_DMA_NODE_ID) {
/*
* While the firmware does not supports time_info reporting for
* While the firmware does not support time_info reporting for
* streams using ChainDMA, it is granted that ChainDMA can only
* be used on Host+Link pairs where the link position is
* accessible from the host side.
@ -1076,10 +1118,16 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
* Enable delay calculation in case of ChainDMA via host
* accessible registers.
*
* The ChainDMA uses 2x 1ms ping-pong buffer, dai side starts
* when 1ms data is available
* The ChainDMA prefills the link DMA with a preamble
* of zero samples. Set the stream start offset based
* on size of the preamble (driver provided fifo size
* multiplied by 2.5). We add 1ms of margin as the FW
* will align the buffer size to DMA hardware
* alignment that is not known to host.
*/
time_info->stream_start_offset = substream->runtime->rate / MSEC_PER_SEC;
int pre_ms = SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS * 5 / 2 + 1;
time_info->stream_start_offset = pre_ms * substream->runtime->rate / MSEC_PER_SEC;
goto out;
}
@ -1099,14 +1147,13 @@ static int sof_ipc4_get_stream_start_offset(struct snd_sof_dev *sdev,
time_info->stream_end_offset = ppl_reg.stream_end_offset;
do_div(time_info->stream_end_offset, dai_sample_size);
/* convert to host frame time */
time_info->stream_start_offset =
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_start_offset);
time_info->stream_end_offset =
sof_ipc4_frames_dai_to_host(time_info, time_info->stream_end_offset);
out:
/*
* Calculate the wrap boundary need to be used for delay calculation
* The host counter is in bytes, it will wrap earlier than the frames
* based link counter.
*/
time_info->boundary = div64_u64(~((u64)0),
frames_to_bytes(substream->runtime, 1));
/* Initialize the delay value to 0 (no delay) */
time_info->delay = 0;
@ -1149,6 +1196,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
/* For delay calculation we need the host counter */
host_cnt = snd_sof_pcm_get_host_byte_counter(sdev, component, substream);
/* Store the original value to host_ptr */
host_ptr = host_cnt;
/* convert the host_cnt to frames */
@ -1167,6 +1216,8 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
sof_mailbox_read(sdev, time_info->llp_offset, &llp, sizeof(llp));
dai_cnt = ((u64)llp.reading.llp_u << 32) | llp.reading.llp_l;
}
dai_cnt = sof_ipc4_frames_dai_to_host(time_info, dai_cnt);
dai_cnt += time_info->stream_end_offset;
/* In two cases dai dma counter is not accurate
@ -1200,8 +1251,9 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
dai_cnt -= time_info->stream_start_offset;
}
/* Wrap the dai counter at the boundary where the host counter wraps */
div64_u64_rem(dai_cnt, time_info->boundary, &dai_cnt);
/* Convert to a common base before comparisons */
dai_cnt &= DELAY_BOUNDARY;
host_cnt &= DELAY_BOUNDARY;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
head_cnt = host_cnt;
@ -1211,14 +1263,18 @@ static int sof_ipc4_pcm_pointer(struct snd_soc_component *component,
tail_cnt = host_cnt;
}
if (head_cnt < tail_cnt) {
time_info->delay = time_info->boundary - tail_cnt + head_cnt;
goto out;
if (unlikely(head_cnt < tail_cnt))
time_info->delay = DELAY_BOUNDARY - tail_cnt + head_cnt;
else
time_info->delay = head_cnt - tail_cnt;
if (time_info->delay > DELAY_MAX) {
spcm_dbg_ratelimited(spcm, substream->stream,
"inaccurate delay, host %llu dai_cnt %llu",
host_cnt, dai_cnt);
time_info->delay = 0;
}
time_info->delay = head_cnt - tail_cnt;
out:
/*
* Convert the host byte counter to PCM pointer which wraps in buffer
* and it is in frames

View File

@ -33,7 +33,6 @@ MODULE_PARM_DESC(ipc4_ignore_cpc,
#define SOF_IPC4_GAIN_PARAM_ID 0
#define SOF_IPC4_TPLG_ABI_SIZE 6
#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
static DEFINE_IDA(alh_group_ida);
static DEFINE_IDA(pipeline_ida);
@ -666,8 +665,13 @@ static int sof_ipc4_widget_setup_pcm(struct snd_sof_widget *swidget)
swidget->tuples,
swidget->num_tuples, sizeof(u32), 1);
/* Set default DMA buffer size if it is not specified in topology */
if (!sps->dsp_max_burst_size_in_ms)
sps->dsp_max_burst_size_in_ms = SOF_IPC4_MIN_DMA_BUFFER_SIZE;
if (!sps->dsp_max_burst_size_in_ms) {
struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
sps->dsp_max_burst_size_in_ms = pipeline->use_chain_dma ?
SOF_IPC4_CHAIN_DMA_BUFFER_SIZE : SOF_IPC4_MIN_DMA_BUFFER_SIZE;
}
} else {
/* Capture data is copied from DSP to host in 1ms bursts */
spcm->stream[dir].dsp_max_burst_size_in_ms = 1;

View File

@ -70,8 +70,11 @@
#define SOF_IPC4_CHAIN_DMA_NODE_ID 0x7fffffff
#define SOF_IPC4_INVALID_NODE_ID 0xffffffff
/* FW requires minimum 2ms DMA buffer size */
#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 2
/* FW requires minimum 4ms DMA buffer size */
#define SOF_IPC4_MIN_DMA_BUFFER_SIZE 4
/* ChainDMA in fw uses 5ms DMA buffer */
#define SOF_IPC4_CHAIN_DMA_BUFFER_SIZE 5
/*
* The base of multi-gateways. Multi-gateways addressing starts from
@ -263,6 +266,8 @@ struct sof_ipc4_dma_stream_ch_map {
#define SOF_IPC4_DMA_METHOD_HDA 1
#define SOF_IPC4_DMA_METHOD_GPDMA 2 /* defined for consistency but not used */
#define SOF_IPC4_CHAIN_DMA_BUF_SIZE_MS 2
/**
* struct sof_ipc4_dma_config: DMA configuration
* @dma_method: HDAudio or GPDMA

View File

@ -629,6 +629,11 @@ void snd_sof_pcm_init_elapsed_work(struct work_struct *work);
(__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
##__VA_ARGS__)
#define spcm_dbg_ratelimited(__spcm, __dir, __fmt, ...) \
dev_dbg_ratelimited((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \
(__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \
##__VA_ARGS__)
#define spcm_err(__spcm, __dir, __fmt, ...) \
dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \
__func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \

View File

@ -641,12 +641,9 @@ static int fcp_ioctl_set_meter_map(struct usb_mixer_interface *mixer,
return -EINVAL;
/* Allocate and copy the map data */
tmp_map = kmalloc_array(map.map_size, sizeof(s16), GFP_KERNEL);
if (!tmp_map)
return -ENOMEM;
if (copy_from_user(tmp_map, arg->map, map.map_size * sizeof(s16)))
return -EFAULT;
tmp_map = memdup_array_user(arg->map, map.map_size, sizeof(s16));
if (IS_ERR(tmp_map))
return PTR_ERR(tmp_map);
err = validate_meter_map(tmp_map, map.map_size, map.meter_slots);
if (err < 0)