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