Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ed05eda
ALSA: compress: pin card module while stream is open
ujfalusi Apr 24, 2026
cc11ca2
ALSA: compress: stop active streams on disconnect
ujfalusi Apr 24, 2026
54afdb9
ASoC: soc-pcm: Allocate be_substream->runtime for compressed streams
ujfalusi Jan 13, 2026
d53d3e8
ASoC: soc-compress: Implement trigger FE-BE sequencing as with normal…
ujfalusi Jan 27, 2026
90369a3
ASoC: soc-compress: Stop running dpcm on free
ujfalusi Feb 3, 2026
930dbb5
ASoC: SOF: compress: Rename compress ops with ipc3 prefix
ranj063 Dec 9, 2025
329ee14
ASoC: SOF: ipc4-pcm: harden pipeline teardown races
ujfalusi Apr 24, 2026
9e5839a
ASoC: SOF: sof-audio: harden recursive widget free walk
ujfalusi Apr 24, 2026
6946767
ASoC: SOF: sof-audio: Expose a couple of functions
ranj063 Dec 9, 2025
9895118
ASoC: SOF: pcm: Modify the signature of a couple of PCM IPC ops
ranj063 Dec 9, 2025
42c61e3
ASoC: SOF: intel: hda-stream: Clear the current position when releasi…
ranj063 Dec 9, 2025
2f8be3c
ASoC: SOF: ops: Add new platform-specific ops for compress
ranj063 Dec 9, 2025
a1a7b17
ASoC: SOF: ipc4: Add definition of module data in init_ext object type
ujfalusi Jan 12, 2026
66c8d8a
ASoC: SOF: ipc4-topology: Support init_ext_module_data for process mo…
ujfalusi Jan 13, 2026
1ae0a3c
ASoC: SOF: ipc4-pcm: Make the timestamp info usable outside of ipc4-p…
ujfalusi Jan 13, 2026
fe8dcb6
ASoC: SOF: ipc4/ipc4-loader: Add SOF_INFO and CODEC_INFO to fw_config…
ujfalusi Jan 14, 2026
99b7de8
ASoC: SOF: ipc4-pcm: Handle COMPR DRAIN triggers as EOS pipeline state
ujfalusi Jan 30, 2026
6be8ed0
ASoC: SOF: ipc4-topology: Set FAST_MODE for host copier in compr mode
ujfalusi Jan 30, 2026
a7e79c7
ASoC: SOF: Add support for IPC4 compressed
ranj063 Dec 9, 2025
4670715
ASoC: SOF: ipc4: Handle compressed drain done notification from firmware
ujfalusi Jan 30, 2026
c319fe0
ASoC: SOF: Intel: Kconfig: Remove redundant IPC version selects
ujfalusi Dec 31, 2025
9ae5254
ASoC: SOF: Intel: Kconfig: Select compress support for TGL+ platforms
ujfalusi Dec 31, 2025
787627d
ASoC: SOF: topology: Add support for decoder and encoder widgets
ranj063 Dec 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions sound/soc/sof/intel/hda-common-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ const struct snd_sof_dsp_ops sof_hda_common_ops = {
.pcm_pointer = hda_dsp_pcm_pointer,
.pcm_ack = hda_dsp_pcm_ack,

.compr_open = hda_dsp_compr_open,
.compr_hw_params = hda_dsp_compr_hw_params,
.compr_hw_free = hda_dsp_stream_compr_hw_free,
.compr_close = hda_dsp_compr_close,
.compr_trigger = hda_dsp_compr_trigger,
.compr_pointer = hda_dsp_compr_pointer,
.compr_get_dai_frame_counter = hda_dsp_compr_get_stream_llp,

.get_dai_frame_counter = hda_dsp_get_stream_llp,
.get_host_byte_counter = hda_dsp_get_stream_ldp,

Expand Down
141 changes: 141 additions & 0 deletions sound/soc/sof/intel/hda-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,71 @@ int hda_dsp_pcm_hw_params(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL_NS(hda_dsp_pcm_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream,
struct snd_compr_params *params,
struct snd_sof_platform_stream_params *platform_params)
{
struct hdac_stream *hstream = cstream->runtime->private_data;
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
struct snd_dma_buffer *dmab;
u32 bits, rate;
int bps;
int ret;

hstream->cstream = cstream;
dmab = cstream->runtime->dma_buffer_p;

/* Use correct format based on the used codec */
switch (params->codec.id) {
case SND_AUDIOCODEC_PCM:
bps = snd_pcm_format_physical_width(params->codec.format);
break;
case SND_AUDIOCODEC_VORBIS:
bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S16_LE);
break;
case SND_AUDIOCODEC_FLAC:
{
struct snd_dec_flac *dec_flac = &params->codec.options.flac_d;

if (dec_flac->sample_size == 16)
bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S16_LE);
else
bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE);
break;
}
default:
bps = snd_pcm_format_physical_width(SNDRV_PCM_FORMAT_S32_LE);
}
Comment on lines +188 to +190
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume this is generic encoded audio data i.e. a fallback if not matched above


if (bps < 0)
return bps;
bits = hda_dsp_get_bits(sdev, bps);
rate = hda_dsp_get_mult_div(sdev, params->codec.sample_rate);

hstream->format_val = rate | bits | (params->codec.ch_out - 1);
hstream->bufsize = cstream->runtime->buffer_size;
hstream->period_bytes = cstream->runtime->fragment_size;
hstream->no_period_wakeup = false;

/* params is not used so pass NULL */
dmab = cstream->runtime->dma_buffer_p;
ret = hda_dsp_stream_hw_params(sdev, hext_stream, dmab, NULL);
if (ret < 0) {
dev_err(sdev->dev, "%s: hdac prepare failed: %d\n", __func__, ret);
return ret;
}

if (hda)
platform_params->no_ipc_position = hda->no_ipc_position;

platform_params->stream_tag = hstream->stream_tag;

return 0;
}
EXPORT_SYMBOL_NS(hda_dsp_compr_hw_params, "SND_SOC_SOF_INTEL_HDA_COMMON");

/* update SPIB register with appl position */
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream)
{
Expand Down Expand Up @@ -184,6 +249,16 @@ int hda_dsp_pcm_trigger(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL_NS(hda_dsp_pcm_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_compr_trigger(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream, int cmd)
{
struct hdac_stream *hstream = cstream->runtime->private_data;
struct hdac_ext_stream *hext_stream = stream_to_hdac_ext_stream(hstream);

return hda_dsp_stream_trigger(sdev, hext_stream, cmd);
}
EXPORT_SYMBOL_NS(hda_dsp_compr_trigger, "SND_SOC_SOF_INTEL_HDA_COMMON");

snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
Expand Down Expand Up @@ -216,6 +291,20 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL_NS(hda_dsp_pcm_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream,
struct snd_compr_tstamp64 *tstamp)
{
struct hdac_stream *hstream = cstream->runtime->private_data;

/* hstream->curr_pos is updated when we receive the ioc */
tstamp->copied_total = hstream->curr_pos;

tstamp->byte_offset = hda_dsp_stream_get_position(hstream, cstream->direction, true);

return 0;
Comment on lines +294 to +304
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hda_dsp_compr_pointer() adds hstream->curr_pos to tstamp->copied_total on every call. Since hstream->curr_pos is already cumulative (it is incremented in hda_dsp_compr_bytes_transferred()), using += will double-count bytes as userspace polls the pointer. Assign tstamp->copied_total from hstream->curr_pos instead of accumulating into the passed-in value.

Copilot uses AI. Check for mistakes.
}
EXPORT_SYMBOL_NS(hda_dsp_compr_pointer, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
Expand Down Expand Up @@ -342,6 +431,41 @@ int hda_dsp_pcm_open(struct snd_sof_dev *sdev,
}
EXPORT_SYMBOL_NS(hda_dsp_pcm_open, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream)
{
struct snd_soc_pcm_runtime *rtd = cstream->private_data;
struct snd_soc_component *scomp = sdev->component;
struct hdac_ext_stream *dsp_stream;
struct snd_sof_pcm *spcm;
int direction = cstream->direction;

spcm = snd_sof_find_spcm_dai(scomp, rtd);
if (!spcm) {
dev_err(sdev->dev, "%s: can't find PCM with DAI ID %d\n",
__func__, rtd->dai_link->id);
return -EINVAL;
}

dsp_stream = hda_dsp_stream_get(sdev, direction, 0);
if (!dsp_stream) {
dev_err(sdev->dev, "%s: no stream available\n", __func__);
return -ENODEV;
}

/* binding compr stream to hda stream */
cstream->runtime->private_data = &dsp_stream->hstream;

/*
* Reset the llp cache values (they are used for LLP compensation in
* case the counter is not reset)
*/
dsp_stream->pplcllpl = 0;
dsp_stream->pplcllpu = 0;

return 0;
}
EXPORT_SYMBOL_NS(hda_dsp_compr_open, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
Expand All @@ -361,3 +485,20 @@ int hda_dsp_pcm_close(struct snd_sof_dev *sdev,
return 0;
}
EXPORT_SYMBOL_NS(hda_dsp_pcm_close, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream)
{
struct hdac_stream *hstream = cstream->runtime->private_data;
int direction = cstream->direction;
int ret;

ret = hda_dsp_stream_put(sdev, direction, hstream->stream_tag);
if (ret)
return -ENODEV;

/* unbinding compress stream to hda stream */
hstream->cstream = NULL;
cstream->runtime->private_data = NULL;
return 0;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing empty linefeed before return

}
EXPORT_SYMBOL_NS(hda_dsp_compr_close, "SND_SOC_SOF_INTEL_HDA_COMMON");
53 changes: 42 additions & 11 deletions sound/soc/sof/intel/hda-stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,13 +747,12 @@ int hda_dsp_stream_hw_params(struct snd_sof_dev *sdev,
return ret;
}

int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
static int _hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
struct hdac_stream *hstream)
{
struct hdac_stream *hstream = substream->runtime->private_data;
struct hdac_ext_stream *hext_stream = container_of(hstream,
struct hdac_ext_stream,
hstream);
struct hdac_ext_stream,
hstream);
int ret;

ret = hda_dsp_stream_reset(sdev, hstream);
Expand All @@ -778,8 +777,21 @@ int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,

return 0;
}

int hda_dsp_stream_hw_free(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream)
{
return _hda_dsp_stream_hw_free(sdev, substream->runtime->private_data);
}
EXPORT_SYMBOL_NS(hda_dsp_stream_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");

int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream)
{
return _hda_dsp_stream_hw_free(sdev, cstream->runtime->private_data);
}
EXPORT_SYMBOL_NS(hda_dsp_stream_compr_hw_free, "SND_SOC_SOF_INTEL_HDA_COMMON");

bool hda_dsp_check_stream_irq(struct snd_sof_dev *sdev)
{
struct hdac_bus *bus = sof_to_bus(sdev);
Expand Down Expand Up @@ -1162,11 +1174,9 @@ EXPORT_SYMBOL_NS(hda_dsp_stream_get_position, "SND_SOC_SOF_INTEL_HDA_COMMON");
*
* Returns the raw Linear Link Position value
*/
u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
static u64 hda_dsp_get_llp(struct snd_sof_dev *sdev,
struct snd_soc_pcm_runtime *rtd, int dir)
{
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;
Expand All @@ -1177,7 +1187,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
* 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) {
for_each_dpcm_be(rtd, dir, dpcm) {
if (dpcm->fe != rtd)
continue;

Expand All @@ -1191,7 +1201,7 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
if (!cpu_dai)
return 0;

hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
hext_stream = snd_soc_dai_dma_data_get(cpu_dai, dir);
if (!hext_stream)
return 0;

Expand All @@ -1215,8 +1225,29 @@ u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,

return merge_u64(llp_u, llp_l);
}

u64 hda_dsp_get_stream_llp(struct snd_sof_dev *sdev,
struct snd_soc_component *component,
struct snd_pcm_substream *substream)
{
return hda_dsp_get_llp(sdev, snd_soc_substream_to_rtd(substream),
substream->stream);
}
EXPORT_SYMBOL_NS(hda_dsp_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON");

/**
* hda_dsp_compr_get_stream_llp - Retrieve the LLP (Linear Link Position) of the stream
* @sdev: SOF device
* @cstream: Compress stream
*
* Returns the raw Linear Link Position value
*/
u64 hda_dsp_compr_get_stream_llp(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream)
{
return hda_dsp_get_llp(sdev, cstream->private_data, cstream->direction);
}
EXPORT_SYMBOL_NS(hda_dsp_compr_get_stream_llp, "SND_SOC_SOF_INTEL_HDA_COMMON");

/**
* hda_dsp_get_stream_ldp - Retrieve the LDP (Linear DMA Position) of the stream
* @sdev: SOF device
Expand Down
15 changes: 15 additions & 0 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,21 @@ snd_pcm_uframes_t hda_dsp_pcm_pointer(struct snd_sof_dev *sdev,
struct snd_pcm_substream *substream);
int hda_dsp_pcm_ack(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream);

int hda_dsp_compr_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream);
int hda_dsp_compr_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream);
int hda_dsp_compr_hw_params(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream,
struct snd_compr_params *params,
struct snd_sof_platform_stream_params *platform_params);
int hda_dsp_stream_compr_hw_free(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream);
int hda_dsp_compr_trigger(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream, int cmd);
int hda_dsp_compr_pointer(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream,
struct snd_compr_tstamp64 *tstamp);
u64 hda_dsp_compr_get_stream_llp(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream);

/*
* DSP Stream Operations.
*/
Expand Down
74 changes: 74 additions & 0 deletions sound/soc/sof/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <sound/compress_driver.h>
#include <sound/pcm.h>
#include "sof-priv.h"

Expand Down Expand Up @@ -448,6 +449,79 @@ snd_sof_pcm_platform_hw_params(struct snd_sof_dev *sdev,
return 0;
}

static inline int
snd_sof_compr_platform_open(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_open)
return sof_ops(sdev)->compr_open(sdev, cstream);

return 0;
}

/* disconnect pcm substream to a host stream */
static inline int
snd_sof_compr_platform_close(struct snd_sof_dev *sdev, struct snd_compr_stream *cstream)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_close)
return sof_ops(sdev)->compr_close(sdev, cstream);

return 0;
}

/* host stream hw params */
static inline int
snd_sof_compr_platform_hw_params(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream,
struct snd_compr_params *params,
struct snd_sof_platform_stream_params *platform_params)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_params)
return sof_ops(sdev)->compr_hw_params(sdev, cstream, params, platform_params);

return 0;
}

static inline int
snd_sof_compr_platform_hw_free(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_hw_free)
return sof_ops(sdev)->compr_hw_free(sdev, cstream);

return 0;
}

static inline int
snd_sof_compr_platform_trigger(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream, int cmd)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_trigger)
return sof_ops(sdev)->compr_trigger(sdev, cstream, cmd);

return 0;
}

static inline int
snd_sof_compr_platform_pointer(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream,
struct snd_compr_tstamp64 *tstamp)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_pointer)
return sof_ops(sdev)->compr_pointer(sdev, cstream, tstamp);

return 0;
}

static inline u64
snd_sof_compr_get_dai_frame_counter(struct snd_sof_dev *sdev,
struct snd_compr_stream *cstream)
{
if (sof_ops(sdev) && sof_ops(sdev)->compr_get_dai_frame_counter)
return sof_ops(sdev)->compr_get_dai_frame_counter(sdev, cstream);

return 0;
}

/* host stream hw free */
static inline int
snd_sof_pcm_platform_hw_free(struct snd_sof_dev *sdev,
Expand Down
Loading