Skip to content

Commit 25dd574

Browse files
committed
docs: add topology2 README with structure and conventions
- document directory structure, class-based object model, and build pipeline - add PCM ID and pipeline ID convention tables for Intel SoundWire and HDA - describe cmake target registration, platform overrides, and route definitions Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 87d2e63 commit 25dd574

1 file changed

Lines changed: 334 additions & 0 deletions

File tree

tools/topology/topology2/README.md

Lines changed: 334 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,334 @@
1+
# SOF Topology2
2+
3+
Topology2 is the second-generation ALSA topology definition system for SOF (Sound Open
4+
Firmware). It defines audio processing pipelines, PCM streams, DAI configurations, and
5+
routing graphs using `.conf` files that are compiled into binary `.tplg` files consumed by
6+
the SOF firmware at runtime.
7+
8+
This readme is a quick intro to the topic. Please refer to full documentation
9+
at https://thesofproject.github.io/latest/developer_guides/topology2/topology2.html
10+
11+
## Quick introduction
12+
13+
The build pipeline works as follows: `.conf` source files are processed by `alsatplg`
14+
(the ALSA Topology Configuration compiler) to produce `.tplg` binary files. The cmake
15+
build system orchestrates this compilation, with each topology target specified as a tuple
16+
of input configuration, output name, and variable overrides.
17+
18+
Topology2 uses a class-based object model built on four core concepts:
19+
20+
* **Classes** (`Class.Pipeline`, `Class.Widget`, `Class.PCM`) define reusable templates
21+
with default attribute values
22+
* **Objects** (`Object.Pipeline`, `Object.Widget`, `Object.PCM`) instantiate classes with
23+
specific parameter values
24+
* **Define blocks** provide variable substitution using `$VARIABLE` syntax, enabling
25+
parameterized topologies
26+
* **IncludeByKey** enables conditional includes based on variable values, used primarily
27+
for platform-specific overrides
28+
29+
Building topologies requires `alsatplg` version 1.2.7 or later. The version check is
30+
enforced in `CMakeLists.txt` at configure time.
31+
32+
## Directory Structure
33+
34+
```text
35+
tools/topology/topology2/
36+
├── CMakeLists.txt # Build system entry point
37+
├── get_abi.sh # ABI version extraction script
38+
├── cavs-sdw.conf # SoundWire topology entry point
39+
├── sof-hda-generic.conf # HDA generic topology entry point
40+
├── cavs-mixin-mixout-hda.conf # HDA with mixer pipelines
41+
├── cavs-nocodec.conf # SSP nocodec topology
42+
├── ... # Other top-level .conf entry points
43+
├── include/
44+
│ ├── common/ # Core class definitions (PCM, route, audio formats)
45+
│ ├── components/ # Widget/component classes (gain, mixin, EQ, DRC)
46+
│ ├── controls/ # Control classes (mixer, enum, bytes)
47+
│ ├── dais/ # DAI classes (SSP, DMIC, HDA, ALH)
48+
│ └── pipelines/ # Pipeline template classes
49+
│ └── cavs/ # CAVS-architecture pipeline classes
50+
├── platform/
51+
│ └── intel/ # Platform-specific overrides (tgl, mtl, lnl, ptl)
52+
├── production/ # CMake targets for production topologies
53+
│ ├── tplg-targets-ace1.cmake # Intel ACE1 (MTL) targets
54+
│ ├── tplg-targets-ace2.cmake # Intel ACE2 (LNL) targets
55+
│ ├── tplg-targets-ace3.cmake # Intel ACE3 (PTL) targets
56+
│ └── ... # Additional platform target files
57+
├── development/ # CMake targets for development/testing
58+
└── doc/ # Doxygen documentation source
59+
```
60+
61+
## Best Practices for Adding New Topology Definitions
62+
63+
### Topology Structure
64+
65+
A top-level topology `.conf` file follows a layered configuration pattern:
66+
67+
```conf
68+
# 1. Search directories
69+
<searchdir:include>
70+
<searchdir:include/common>
71+
<searchdir:include/components>
72+
<searchdir:include/dais>
73+
<searchdir:include/pipelines/cavs>
74+
<searchdir:platform/intel>
75+
76+
# 2. Include class files
77+
<vendor-token.conf>
78+
<tokens.conf>
79+
<pcm.conf>
80+
<host-copier-gain-mixin-playback.conf>
81+
<mixout-gain-alh-dai-copier-playback.conf>
82+
83+
# 3. Define block (default variable values)
84+
Define {
85+
PLATFORM ""
86+
NUM_HDMIS 3
87+
DEEP_BUFFER_PCM_ID 31
88+
}
89+
90+
# 4. Platform overrides (conditional includes)
91+
IncludeByKey.PLATFORM {
92+
"mtl" "platform/intel/mtl.conf"
93+
"lnl" "platform/intel/lnl.conf"
94+
"ptl" "platform/intel/ptl.conf"
95+
}
96+
97+
# 5. Conditional feature includes
98+
IncludeByKey.NUM_HDMIS {
99+
"3" "platform/intel/hdmi-generic.conf"
100+
}
101+
102+
# 6. DAI, Pipeline, PCM objects
103+
# 7. Route definitions
104+
```
105+
106+
### Reusing Existing Bases
107+
108+
The most common way to add a new topology is to reuse an existing base `.conf` file and
109+
override variables through a cmake target entry. Targets are defined in
110+
`production/tplg-targets-*.cmake` files using a tuple format:
111+
112+
```text
113+
"input-conf;output-name;variables"
114+
```
115+
116+
For example, to add a new SoundWire topology variant for ACE2 (Lunar Lake):
117+
118+
```text
119+
"cavs-sdw\;sof-lnl-sdw-cs42l43-l0-cs35l56-l12\;PLATFORM=lnl,NUM_SDW_AMP_LINKS=2"
120+
```
121+
122+
The first element is the base `.conf` file (without extension), the second is the output
123+
`.tplg` filename, and the third is a comma-separated list of variable overrides.
124+
125+
### Creating a New Base Topology
126+
127+
When existing bases do not cover a new use case, create a new top-level `.conf` file:
128+
129+
1. Create a new `.conf` file in `tools/topology/topology2/` following the layered
130+
structure described above
131+
2. Include the required class files from `include/` directories via search directives
132+
3. Define default variables in a `Define` block
133+
4. Add `IncludeByKey.PLATFORM` entries for platform-specific overrides
134+
5. Instantiate DAI, Pipeline, and PCM objects with appropriate IDs
135+
6. Define routes connecting FE mixin outputs to BE mixout inputs
136+
7. Register the topology as a cmake target in the appropriate
137+
`production/tplg-targets-*.cmake` file
138+
139+
### PCM ID Conventions
140+
141+
PCM IDs identify audio streams exposed to userspace via ALSA. Each PCM ID must be unique
142+
within a single topology. Different topology families (Intel SoundWire vs HDA) use different
143+
default ID ranges for the same endpoint types.
144+
145+
**Intel SoundWire PCM IDs:**
146+
147+
| Endpoint | Default PCM ID | Override Variable |
148+
|---|---|---|
149+
| Jack (playback/capture) | 0 ||
150+
| Speaker amplifier | 2 ||
151+
| SDW DMIC | 4 ||
152+
| HDMI 1 | 5 | `HDMI1_PCM_ID` |
153+
| HDMI 2 | 6 | `HDMI2_PCM_ID` |
154+
| HDMI 3 | 7 | `HDMI3_PCM_ID` |
155+
| PCH DMIC0 | 10 | `DMIC0_PCM_ID` |
156+
| PCH DMIC1 | 11 | `DMIC1_PCM_ID` |
157+
| Jack Echo Ref | 11 | `SDW_JACK_ECHO_REF_PCM_ID` |
158+
| Speaker Echo Ref | 12 | `SDW_SPK_ECHO_REF_PCM_ID` |
159+
| Bluetooth | 2 or 20 | `BT_PCM_ID` |
160+
| Deep Buffer (Jack) | 31 | `DEEP_BUFFER_PCM_ID` |
161+
| Deep Buffer (Speaker) | 35 | `DEEP_BUFFER_PCM_ID_2` |
162+
| DMIC Deep Buffer | 46 | `DMIC0_DEEP_BUFFER_PCM_ID` |
163+
| Compress Jack Out | 50 | `COMPR_PCM_ID` |
164+
| Compress Speaker | 52 | `COMPR_2_PCM_ID` |
165+
166+
> **Note:** Bluetooth defaults to PCM ID 2 in some topologies and 20 in others. Use the
167+
> `BT_PCM_ID` override variable to set the correct value when BT coexists with a speaker
168+
> amplifier (which also uses PCM ID 2 by default).
169+
170+
**Intel HDA PCM IDs:**
171+
172+
| Endpoint | Default PCM ID | Override Variable |
173+
|---|---|---|
174+
| HDA Analog | 0 ||
175+
| HDMI 1 | 3 | `HDMI1_PCM_ID` |
176+
| HDMI 2 | 4 | `HDMI2_PCM_ID` |
177+
| HDMI 3 | 5 | `HDMI3_PCM_ID` |
178+
| DMIC0 | 6 | `DMIC0_PCM_ID` |
179+
| Deep Buffer | 31 | `DEEP_BUFFER_PCM_ID` |
180+
| Compress HDA Analog | 50 | `COMPR_PCM_ID` |
181+
182+
Key rules:
183+
184+
* PCM ID 0 is always the primary playback endpoint
185+
* PCM IDs must be unique within a single topology
186+
* When features coexist (SDW + PCH DMIC + HDMI), adjust IDs via `Define` overrides in
187+
cmake targets to avoid conflicts
188+
* Different topology families (SDW vs HDA) use different default ID ranges for the same
189+
endpoint types
190+
191+
### Pipeline ID Conventions
192+
193+
Pipeline IDs are set via the `index` attribute on pipeline objects. Front-end (FE) and
194+
back-end (BE) pipelines are paired, with the FE pipeline at index N and the BE pipeline
195+
at index N+1.
196+
197+
In SoundWire topologies, pipeline indexes follow the convention documented in
198+
`sdw-amp-generic.conf` and `sdw-dmic-generic.conf`: pipeline index = PCM ID × 10. HDMI
199+
pipelines use a stride-10 pattern where the host pipeline is at N0 and the DAI pipeline
200+
is at N1 (50/51, 60/61, 70/71, 80/81).
201+
202+
** Intel SoundWire Pipeline IDs:**
203+
204+
| Pipeline | Default Index | Override Variable |
205+
|---|---|---|
206+
| Jack Playback FE / BE | 0 / 1 ||
207+
| Jack Capture FE / BE | 10 / 11 ||
208+
| Deep Buffer (Jack) | 15 | `DEEP_BUFFER_PIPELINE_ID` |
209+
| Deep Buffer (Speaker) | 16 | `DEEP_BUFFER_PIPELINE_ID_2` |
210+
| Speaker FE / BE | 20 / 21 ||
211+
| Speaker Echo Ref FE / BE | 22 / 23 ||
212+
| SDW DMIC FE / BE | 40 / 41 | `SDW_DMIC_HOST_PIPELINE_ID` |
213+
| HDMI 1 Host / DAI | 50 / 51 | `HDMI1_HOST_PIPELINE_ID` / `HDMI1_DAI_PIPELINE_ID` |
214+
| HDMI 2 Host / DAI | 60 / 61 | `HDMI2_HOST_PIPELINE_ID` / `HDMI2_DAI_PIPELINE_ID` |
215+
| HDMI 3 Host / DAI | 70 / 71 | `HDMI3_HOST_PIPELINE_ID` / `HDMI3_DAI_PIPELINE_ID` |
216+
| HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` |
217+
| Compress Jack / Speaker | 90 / 92 | `COMPR_PIPELINE_ID` / `COMPR_2_PIPELINE_ID` |
218+
| PCH DMIC0 Host / DAI | 100 / 101 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` |
219+
220+
**Intel HDA Pipeline IDs:**
221+
222+
| Pipeline | Default Index | Override Variable |
223+
|---|---|---|
224+
| Analog Playback FE / BE | 1 / 2 ||
225+
| Analog Capture FE / BE | 3 / 4 ||
226+
| DMIC0 Host / DAI | 11 / 12 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` |
227+
| Deep Buffer | 15 | `DEEP_BUFFER_PIPELINE_ID` |
228+
| HDMI 1 Host / DAI | 50 / 51 | `HDMI1_HOST_PIPELINE_ID` / `HDMI1_DAI_PIPELINE_ID` |
229+
| HDMI 2 Host / DAI | 60 / 61 | `HDMI2_HOST_PIPELINE_ID` / `HDMI2_DAI_PIPELINE_ID` |
230+
| HDMI 3 Host / DAI | 70 / 71 | `HDMI3_HOST_PIPELINE_ID` / `HDMI3_DAI_PIPELINE_ID` |
231+
| HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` |
232+
| Compress HDA Analog Host / DAI | 90 / 91 | `COMPR_PIPELINE_ID` |
233+
234+
Key rules:
235+
236+
* FE and BE pipelines are paired: FE = N, BE = N+1
237+
* SDW convention: pipeline index = PCM ID × 10 (documented in `sdw-amp-generic.conf` and
238+
`sdw-dmic-generic.conf`)
239+
* HDMI uses stride-10: Host = N0, DAI = N1
240+
* Pipeline IDs must be unique within a single topology
241+
* When adding new endpoints, select IDs in unused ranges that do not conflict with
242+
existing assignments
243+
244+
### Widget Naming
245+
246+
Widget names follow the convention `<type>.<pipeline-index>.<instance>`. Examples:
247+
248+
* `gain.1.1` — gain widget in pipeline 1, instance 1
249+
* `mixin.15.1` — mixin widget in pipeline 15, instance 1
250+
* `host-copier.0.playback` — host copier in pipeline 0, playback direction
251+
* `dai-copier.1.ALH` — DAI copier in pipeline 1, ALH type
252+
253+
### Route Definitions
254+
255+
Routes connect FE pipeline mixin outputs to BE pipeline mixout inputs. This is the
256+
primary mechanism for linking front-end and back-end pipelines:
257+
258+
```conf
259+
Object.Base.route [
260+
{
261+
source "mixin.15.1"
262+
sink "mixout.2.1"
263+
}
264+
]
265+
```
266+
267+
Multiple FE pipelines can feed into a single BE mixout. For example, both a normal
268+
playback pipeline and a deep buffer pipeline can route to the same DAI output:
269+
270+
```text
271+
host-copier.0 -> gain.0 -> mixin.0 ─┐
272+
├─> mixout.1 -> gain.1 -> dai-copier.1 -> DAI
273+
host-copier.15 -> gain.15 -> mixin.15┘
274+
```
275+
276+
### Platform Overrides
277+
278+
Platform-specific configurations are applied using the `IncludeByKey.PLATFORM` mechanism.
279+
Each platform `.conf` file under `platform/intel/` contains `Define` blocks that override
280+
variables such as `DMIC_DRIVER_VERSION`, `SSP_BLOB_VERSION`, and `NUM_HDMIS`.
281+
282+
Supported platforms:
283+
284+
* `tgl` — Intel Tiger Lake / Alder Lake (CAVS 2.5)
285+
* `mtl` — Intel Meteor Lake (ACE 1.x)
286+
* `lnl` — Intel Lunar Lake (ACE 2.x)
287+
* `ptl` — Intel Panther Lake (ACE 3.x)
288+
289+
```conf
290+
IncludeByKey.PLATFORM {
291+
"mtl" "platform/intel/mtl.conf"
292+
"lnl" "platform/intel/lnl.conf"
293+
"ptl" "platform/intel/ptl.conf"
294+
}
295+
```
296+
297+
### Registering CMake Targets
298+
299+
Production topologies are registered in `production/tplg-targets-*.cmake` files. Each
300+
target is a semicolon-separated tuple:
301+
302+
```text
303+
"input-conf;output-name;variable1=value1,variable2=value2"
304+
```
305+
306+
Select the cmake file matching the target platform generation:
307+
308+
| Platform | CMake Target File |
309+
|---|---|
310+
| Tiger Lake / Alder Lake | `tplg-targets-cavs25.cmake` |
311+
| Meteor Lake | `tplg-targets-ace1.cmake` |
312+
| Lunar Lake | `tplg-targets-ace2.cmake` |
313+
| Panther Lake | `tplg-targets-ace3.cmake` |
314+
| HDA generic | `tplg-targets-hda-generic.cmake` |
315+
316+
Development and testing topologies go in `development/tplg-targets.cmake`.
317+
318+
## Building Topologies
319+
320+
Configure the build with cmake and build the topology targets:
321+
322+
```bash
323+
mkdir build && cd build
324+
cmake ..
325+
make -j$(nproc)
326+
```
327+
328+
To build a specific topology target:
329+
330+
```bash
331+
make sof-lnl-sdw-cs42l43-l0-cs35l56-l12
332+
```
333+
334+
The compiled `.tplg` files are placed in the build output directory.

0 commit comments

Comments
 (0)