Skip to content

Commit f522f94

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 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 f522f94

File tree

1 file changed

+326
-0
lines changed

1 file changed

+326
-0
lines changed

tools/topology/topology2/README.md

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

0 commit comments

Comments
 (0)