From 8b5c36509cc81f3ded658ce94f53a66ced237b94 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2026 15:26:31 +0300 Subject: [PATCH 1/2] topology2: Add the UAOL DAI type The USB Audio Offload Link is an ACE2+ alt link. The firmware enumerates its gateways in the ALH class family, but the ALH DAI class carries SoundWire specific attributes, so UAOL is described by a DAI class of its own. Allow "UAOL" as a dai type and as a copier type, and let the dai-copier take the two UAOL node types which common_definitions.conf already defines. Signed-off-by: Peter Ujfalusi --- .../include/components/dai-copier.conf | 4 + .../topology2/include/components/dai.conf | 1 + .../topology/topology2/include/dais/uaol.conf | 95 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 tools/topology/topology2/include/dais/uaol.conf diff --git a/tools/topology/topology2/include/components/dai-copier.conf b/tools/topology/topology2/include/components/dai-copier.conf index e5508ada3df5..3b97ff0b4adf 100644 --- a/tools/topology/topology2/include/components/dai-copier.conf +++ b/tools/topology/topology2/include/components/dai-copier.conf @@ -44,6 +44,7 @@ Class.Widget."dai-copier" { "HDA" "SSP" "DMIC" + "UAOL" "SAI" ] } @@ -57,6 +58,7 @@ Class.Widget."dai-copier" { "SSP" "DMIC" "HDA" + "UAOL" "SAI" ] } @@ -103,6 +105,8 @@ Class.Widget."dai-copier" { $DMIC_LINK_INPUT_CLASS # DMIC link input (DSP <-) $I2S_LINK_OUTPUT_CLASS # I2S link output (DSP ->) $I2S_LINK_INPUT_CLASS # I2S link input (DSP <-) + $ALH_UAOL_STREAM_LINK_OUTPUT_CLASS # UAOL link output (DSP ->) + $ALH_UAOL_STREAM_LINK_INPUT_CLASS # UAOL link input (DSP <-) $IPC_OUTPUT_CLASS # IPC output (DSP ->) $IPC_INPUT_CLASS # IPC input (DSP <-) $I2S_MULTILINK_OUTPUT_CLASS # I2S Multi gtw output (DSP ->) diff --git a/tools/topology/topology2/include/components/dai.conf b/tools/topology/topology2/include/components/dai.conf index 4a34594b5eb0..41f884b4e9f9 100644 --- a/tools/topology/topology2/include/components/dai.conf +++ b/tools/topology/topology2/include/components/dai.conf @@ -28,6 +28,7 @@ Class.Widget."dai" { "DMIC" "HDA" "ALH" + "UAOL" "SAI" "ESAI" ] diff --git a/tools/topology/topology2/include/dais/uaol.conf b/tools/topology/topology2/include/dais/uaol.conf new file mode 100644 index 000000000000..56d8dd726481 --- /dev/null +++ b/tools/topology/topology2/include/dais/uaol.conf @@ -0,0 +1,95 @@ +# +# UAOL DAI +# +# All attributes defined herein are namespaced by alsatplg to +# "Object.Dai.UAOL.attribute_name" +# +# UAOL (USB Audio Offload Link) is an ACE2+ alt link. It belongs to the ALH +# class family in the firmware gateway enumeration, but it is described by its +# own DAI class because the ALH class carries SoundWire specific attributes. +# +# Usage: this component can be used by declaring as follows: +# +# For Playback +#Object.Dai.UAOL."N" { +# direction "playback" +# name "UAOL0" +# id 0 +# Object.Base.hw_config."0" {} +# } +# For Capture +#Object.Dai.UAOL."N" { +# direction "capture" +# name "UAOL0" +# id 0 +# Object.Base.hw_config."1" {} +# } +# +# Where N is the dai index of the UAOL DAI in the firmware + +Class.Dai."UAOL" { + # + # instance ID of UAOL DAI object + # + DefineAttribute."instance" {} + + # + # UAOL link index in the firmware + # + DefineAttribute."dai_index" { + token_ref "dai.word" + } + + DefineAttribute."direction" { + type "string" + constraints { + !valid_values [ + "playback" + "capture" + "duplex" + ] + } + } + + # type of DAI + DefineAttribute.dai_type { + type "string" + token_ref "dai.string" + } + + # Backend DAI Link ID matching with the machine driver + DefineAttribute.id {} + + DefineAttribute."default_hw_config_id" {} + + DefineAttribute.name { + type "string" + } + + DefineAttribute.rate {} + + DefineAttribute.ch {} + + attributes { + !constructor [ + "name" + ] + !mandatory [ + "id" + "dai_index" + ] + !immutable [ + "type" + ] + # + # UAOL DAI objects instantiated within the same alsaconf node must + # have unique instance attribute + # + unique "instance" + } + + dai_type "UAOL" + default_hw_config_id 0 + rate 48000 + ch 2 +} From 2c8759c6e72cdae10caba4c632f34e3bbd75ecf4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2026 15:26:43 +0300 Subject: [PATCH 2/2] topology2: Add the cavs-uaol function topology The sof_sdw machine driver creates a backend DAI link for the USB Audio Offload Link when the platform reports one. Add the function topology which is loaded next to the other function topologies of that card. The playback path is a mixer based one, so a deep buffer PCM can share the link with the normal playback PCM. The capture path is a straight one with a high pass EQ IIR, matching what the SoundWire jack does, because the number of captured channels follows the USB device while a mixer only handles a fixed channel count. The two directions are separate DAI links so that the format fixup of a link is decided by the DAI copier of that direction alone. Their names are kept short because alsatplg drops the widget tuples once the generated widget name exceeds 36 characters. The UAOL backend is the last one the machine driver creates, so its DAI link ID depends on the composition of the board. Build the ID variants which the SoundWire boards can produce. Signed-off-by: Peter Ujfalusi --- tools/topology/topology2/README.md | 5 + tools/topology/topology2/cavs-uaol.conf | 82 +++++ .../platform/intel/uaol-generic.conf | 327 ++++++++++++++++++ .../tplg-targets-sdca-generic.cmake | 13 + 4 files changed, 427 insertions(+) create mode 100644 tools/topology/topology2/cavs-uaol.conf create mode 100644 tools/topology/topology2/platform/intel/uaol-generic.conf diff --git a/tools/topology/topology2/README.md b/tools/topology/topology2/README.md index bea7ffcfdcde..759867a47d1c 100644 --- a/tools/topology/topology2/README.md +++ b/tools/topology/topology2/README.md @@ -242,6 +242,8 @@ default ID ranges for the same endpoint types. | Jack Echo Ref | 11 | `SDW_JACK_ECHO_REF_PCM_ID` | | Speaker Echo Ref | 12 | `SDW_SPK_ECHO_REF_PCM_ID` | | Bluetooth | 2 or 20 | `BT_PCM_ID` | +| USB Audio Offload (UAOL) | 21 | `UAOL_PCM_ID` | +| Deepbuffer UAOL | 22 | `DEEP_BUFFER_PCM_ID` | | Deep Buffer (Jack) | 31 | `DEEP_BUFFER_PCM_ID` | | Deep Buffer (Speaker) | 35 | `DEEP_BUFFER_PCM_ID_2` | | DMIC Deep Buffer | 46 | `DMIC0_DEEP_BUFFER_PCM_ID` | @@ -301,6 +303,9 @@ is at N1 (50/51, 60/61, 70/71, 80/81). | HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` | | Compress Jack / Speaker | 90 / 92 | `COMPR_PIPELINE_ID` / `COMPR_2_PIPELINE_ID` | | PCH DMIC0 Host / DAI | 100 / 101 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` | +| UAOL Playback Host / DAI | 210 / 211 | `UAOL_PB_HOST_PIPELINE_ID` / `UAOL_PB_DAI_PIPELINE_ID` | +| UAOL Capture Host / DAI | 212 / 213 | `UAOL_CP_HOST_PIPELINE_ID` / `UAOL_CP_DAI_PIPELINE_ID` | +| UAOL Deepbuffer | 214 | `DEEP_BUFFER_PIPELINE_ID` | **Intel HDA Pipeline IDs:** diff --git a/tools/topology/topology2/cavs-uaol.conf b/tools/topology/topology2/cavs-uaol.conf new file mode 100644 index 000000000000..c62e217dab02 --- /dev/null +++ b/tools/topology/topology2/cavs-uaol.conf @@ -0,0 +1,82 @@ +# Basic USB Audio Offload Link (UAOL) topology. +# +# This is a function topology, loaded next to the other function topologies of +# the sof_sdw card, so its PCM and pipeline IDs must not collide with theirs. +# +# The UAOL function itself lives in platform/intel/uaol-generic.conf. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Define { + UAOL_PLAYBACK_PCM 'UAOL Playback' + UAOL_CAPTURE_PCM 'UAOL Capture' + # The two directions are separate DAI links so that the format fixup of + # a link is decided by the DAI copier of that direction alone. The names + # are abbreviated because alsatplg drops widget tuples above 36 characters + # and the dai-copier name is 'dai-copier.UAOL..' + UAOL_PB_DAI_NAME 'UAOL0-Play' + UAOL_CP_DAI_NAME 'UAOL0-Cap' + # The BE IDs are the dai link IDs that are matched with the machine + # driver, which creates the playback link first + UAOL_PB_BE_ID 9 + UAOL_CP_BE_ID 10 + # UAOL_DAI_INDEX is the UAOL link the DSP uses, only link 0 is addressable + UAOL_DAI_INDEX 0 + UAOL_PCM_NAME 'UAOL' + UAOL_PCM_ID 21 + UAOL_PB_HOST_PIPELINE_ID 210 + UAOL_PB_DAI_PIPELINE_ID 211 + UAOL_CP_HOST_PIPELINE_ID 212 + UAOL_CP_DAI_PIPELINE_ID 213 + # The mixer of the playback path only supports a stereo stream, while the + # capture path passes through whatever the USB device records + UAOL_PLAYBACK_CHANNELS 2 + UAOL_CAPTURE_CHANNELS_MIN 1 + UAOL_CAPTURE_CHANNELS_MAX 2 + UAOL_RATE 48000 + + # The deep buffer PCM feeds the same mixer as the normal playback PCM. It + # takes the source and the sink as plain widget names, so it repeats the + # pipeline IDs defined above. + DEEP_BUFFER_PCM_NAME 'Deepbuffer UAOL' + DEEP_BUFFER_PCM_ID 22 + DEEP_BUFFER_PIPELINE_ID 214 + DEEP_BUFFER_PIPELINE_SRC 'mixin.214.1' + DEEP_BUFFER_PIPELINE_SINK 'mixout.211.1' +} + + diff --git a/tools/topology/topology2/platform/intel/uaol-generic.conf b/tools/topology/topology2/platform/intel/uaol-generic.conf new file mode 100644 index 000000000000..559e07a549db --- /dev/null +++ b/tools/topology/topology2/platform/intel/uaol-generic.conf @@ -0,0 +1,327 @@ +# USB Audio Offload Link (UAOL) function. +# +# The offloaded USB endpoint is driven by the UAOL gateway in the firmware: +# +# PCM ---------------> gain ---> mixin ---+ +# | +# Deepbuffer PCM ----> gain ---> mixin ---+--> mixout --> gain --> UAOL0-Play +# +# PCM <------------ module-copier <--- eqiir <---------------- UAOL0-Cap +# +# The capture path carries no mixer, as the number of channels follows the USB +# device and a mixer only handles a fixed channel count. + +# Deep buffer playback, included when the DMA buffer is 1 - 1000 ms +IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" "platform/intel/deep-buffer.conf" +} + +Object.Dai.UAOL [ + { + name $UAOL_PB_DAI_NAME + dai_index $UAOL_DAI_INDEX + id $UAOL_PB_BE_ID + default_hw_conf_id 0 + Object.Base.hw_config.1 { + name "UAOL0-Play" + } + direction playback + } + { + name $UAOL_CP_DAI_NAME + dai_index $UAOL_DAI_INDEX + id $UAOL_CP_BE_ID + default_hw_conf_id 0 + Object.Base.hw_config.1 { + name "UAOL0-Cap" + } + direction capture + } +] + +Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index $UAOL_PB_HOST_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $UAOL_PLAYBACK_PCM + pcm_id $UAOL_PCM_ID + num_input_audio_formats 2 + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $UAOL_PCM_NAME Playback Volume' + } + } + } + ] + + mixout-gain-dai-copier-playback [ + { + index $UAOL_PB_DAI_PIPELINE_ID + + Object.Widget.dai-copier.1 { + node_type $ALH_UAOL_STREAM_LINK_OUTPUT_CLASS + stream_name $UAOL_PB_DAI_NAME + dai_type "UAOL" + copier_type "UAOL" + num_output_audio_formats 2 + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $UAOL_PCM_NAME Playback Volume' + } + } + } + ] + + host-gateway-capture [ + { + index $UAOL_CP_HOST_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $UAOL_CAPTURE_PCM + pcm_id $UAOL_PCM_ID + num_input_audio_formats 2 + num_output_audio_formats 4 + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 16 + out_valid_bit_depth 16 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 16 + out_valid_bit_depth 16 + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] + + dai-copier-eqiir-module-copier-capture [ + { + index $UAOL_CP_DAI_PIPELINE_ID + + Object.Widget.dai-copier.1 { + node_type $ALH_UAOL_STREAM_LINK_INPUT_CLASS + stream_name $UAOL_CP_DAI_NAME + dai_type "UAOL" + type dai_out + copier_type "UAOL" + num_input_audio_formats 4 + num_output_audio_formats 2 + num_output_pins 1 + + Object.Base.input_audio_format [ + { + in_bit_depth 16 + in_valid_bit_depth 16 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 16 + in_valid_bit_depth 16 + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.eqiir.1 { + num_input_audio_formats 2 + num_output_audio_formats 2 + + Object.Control.bytes.1 { + name '$UAOL_PCM_NAME Capture IIR Eq' + + } + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + + Object.Widget.module-copier.2 { + num_input_audio_formats 2 + num_output_audio_formats 2 + + Object.Base.input_audio_format [ + { + in_bit_depth 32 + in_valid_bit_depth 32 + in_channels 1 + in_ch_cfg $CHANNEL_CONFIG_MONO + in_ch_map $CHANNEL_MAP_MONO + } + { + in_bit_depth 32 + in_valid_bit_depth 32 + } + ] + Object.Base.output_audio_format [ + { + out_bit_depth 32 + out_valid_bit_depth 32 + out_channels 1 + out_ch_cfg $CHANNEL_CONFIG_MONO + out_ch_map $CHANNEL_MAP_MONO + } + { + out_bit_depth 32 + out_valid_bit_depth 32 + } + ] + } + } + ] +} + +Object.PCM.pcm [ + { + name $UAOL_PCM_NAME + id $UAOL_PCM_ID + direction "duplex" + Object.Base.fe_dai.1 { + name $UAOL_PCM_NAME + } + Object.PCM.pcm_caps.1 { + direction "playback" + name $UAOL_PLAYBACK_PCM + formats 'S16_LE,S32_LE' + channels_min $UAOL_PLAYBACK_CHANNELS + channels_max $UAOL_PLAYBACK_CHANNELS + rates '48000' + rate_min $UAOL_RATE + rate_max $UAOL_RATE + } + Object.PCM.pcm_caps.2 { + direction "capture" + name $UAOL_CAPTURE_PCM + formats 'S16_LE,S32_LE' + channels_min $UAOL_CAPTURE_CHANNELS_MIN + channels_max $UAOL_CAPTURE_CHANNELS_MAX + rates '48000' + rate_min $UAOL_RATE + rate_max $UAOL_RATE + } + } +] + +# top-level pipeline connections +Object.Base.route [ + { + source "host-copier.$UAOL_PCM_ID.playback" + sink "gain.$UAOL_PB_HOST_PIPELINE_ID.1" + } + { + source "mixin.$UAOL_PB_HOST_PIPELINE_ID.1" + sink "mixout.$UAOL_PB_DAI_PIPELINE_ID.1" + } + { + source "gain.$UAOL_PB_DAI_PIPELINE_ID.1" + sink "dai-copier.UAOL.$UAOL_PB_DAI_NAME.playback" + } + { + source "dai-copier.UAOL.$UAOL_CP_DAI_NAME.capture" + sink "eqiir.$UAOL_CP_DAI_PIPELINE_ID.1" + } + { + source "module-copier.$UAOL_CP_DAI_PIPELINE_ID.2" + sink "host-copier.$UAOL_PCM_ID.capture" + } +] diff --git a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake index c7d5b5d8af1b..7979d2d07255 100644 --- a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake +++ b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake @@ -37,6 +37,19 @@ SDW_DMIC_STREAM=Capture-SmartMic" "cavs-sdw\;sof-hdmi-pcm5-id6\;SDW_JACK=false,HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8" "cavs-sdw\;sof-hdmi-pcm5-id7\;SDW_JACK=false,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9" +# USB Audio Offload Link function topology. The UAOL backend is the last one +# sof_sdw creates, so its dai link ID depends on the composition of the board: +# it follows the SoundWire links, the PCH DMIC pair, the three HDMI links and +# the BT link. Each direction is a separate link, so two consecutive IDs are +# taken. The range below covers a jack and amplifier board without DMIC and BT +# (6) up to a jack, amplifier with feedback, PCH DMIC and BT board (10). +# Add a variant here for every further ID that is needed. +"cavs-uaol\;sof-uaol-id6\;UAOL_PB_BE_ID=6,UAOL_CP_BE_ID=7" +"cavs-uaol\;sof-uaol-id7\;UAOL_PB_BE_ID=7,UAOL_CP_BE_ID=8" +"cavs-uaol\;sof-uaol-id8\;UAOL_PB_BE_ID=8,UAOL_CP_BE_ID=9" +"cavs-uaol\;sof-uaol-id9\;UAOL_PB_BE_ID=9,UAOL_CP_BE_ID=10" +"cavs-uaol\;sof-uaol-id10\;UAOL_PB_BE_ID=10,UAOL_CP_BE_ID=11" + # Feature topologies which should work with the function topologies above "cavs-sdw\;sof-sdca-amp-ref\;SDW_JACK=false,NUM_HDMIS=0,JACK_RATE=48000,\ SDW_AMP_FEEDBACK=false,SDW_SPK_ECHO_REF=true,SDW_SPK_ECHO_REF_PCM_ID=12"