From 7dedb59c49a44468693da5f4ce4dd24abd7b6a8e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 14 Jul 2020 12:47:42 +0200 Subject: [PATCH] [REVIEW ONLY] topology 2.0 Topology 2.0 file format is an extension of the ALSA configuration language. It uses the same basic syntax of "key-value pairs" of the language but adds features, required to be able to define complex objects by re-using definitions of component objects with different attributes. This replaces the SOF m4 topology macro library. Signed-off-by: Guennadi Liakhovetski --- tools/topology/v2/attributes.conf | 55 +++++++ tools/topology/v2/buffer.conf | 17 ++ tools/topology/v2/bxt.conf | 17 ++ tools/topology/v2/common.conf | 47 ++++++ tools/topology/v2/dai.conf | 114 ++++++++++++++ tools/topology/v2/machine.conf | 80 ++++++++++ tools/topology/v2/mixercontrol.conf | 78 ++++++++++ tools/topology/v2/pcm.conf | 79 ++++++++++ tools/topology/v2/pipe-dai-playback.conf | 19 +++ tools/topology/v2/pipe-volume-playback.conf | 162 ++++++++++++++++++++ tools/topology/v2/pipeline.conf | 77 ++++++++++ tools/topology/v2/volume.conf | 41 +++++ 12 files changed, 786 insertions(+) create mode 100644 tools/topology/v2/attributes.conf create mode 100644 tools/topology/v2/buffer.conf create mode 100644 tools/topology/v2/bxt.conf create mode 100644 tools/topology/v2/common.conf create mode 100644 tools/topology/v2/dai.conf create mode 100644 tools/topology/v2/machine.conf create mode 100644 tools/topology/v2/mixercontrol.conf create mode 100644 tools/topology/v2/pcm.conf create mode 100644 tools/topology/v2/pipe-dai-playback.conf create mode 100644 tools/topology/v2/pipe-volume-playback.conf create mode 100644 tools/topology/v2/pipeline.conf create mode 100644 tools/topology/v2/volume.conf diff --git a/tools/topology/v2/attributes.conf b/tools/topology/v2/attributes.conf new file mode 100644 index 000000000000..7a89106ddefe --- /dev/null +++ b/tools/topology/v2/attributes.conf @@ -0,0 +1,55 @@ +# common attributes and attribute types. Attributes, defined here can then be +# used by any blocks. E.g. the "format" attribute can be used by pipelines, +# DAIs, etc. + +# we're using an "availability" parameter in attribute declaration instead of +# adding ".optional" or ".mandatory" to the array name + +DefineType.format { + enum [ + "s16le" + "s24le" + "s32le" + "float" + ] +} + +DefineType.time_domain { + enum [ + "dma" + "timer" + ] +} + +DefineAttribute.tokens { + type array.tuple +} + +DefineAttribute.format { + type format + availability mandatory +} + +DefineAttribute.template { + type string + availability mandatory +} + +DefineAttribute.pipeline_id { + type integer + availability mandatory +} + +DefineAttribute.periods_sink { + type integer + availability optional + default 2 + min 1 +} + +DefineAttribute.periods_source { + type integer + availability optional + default 2 + min 1 +} diff --git a/tools/topology/v2/buffer.conf b/tools/topology/v2/buffer.conf new file mode 100644 index 000000000000..65a94707f981 --- /dev/null +++ b/tools/topology/v2/buffer.conf @@ -0,0 +1,17 @@ +# Buffer block and related attributes + +DefineAttribute.capabilities { + type array.integer +} + +# A buffer block, most attributes inherited from "Widget" +DefineWidget."buffer" { + attributes [ + name + format + periods + capabilities + ] + + type buffer +} diff --git a/tools/topology/v2/bxt.conf b/tools/topology/v2/bxt.conf new file mode 100644 index 000000000000..76d10028c97a --- /dev/null +++ b/tools/topology/v2/bxt.conf @@ -0,0 +1,17 @@ +# BXT specific topology elements + +# BXT host memory capability flags +platform_host_mem_cap [ + MEM_CAP_RAM + MEM_CAP_DMA + MEM_CAP_CACHE + MEM_CAP_HP +] + +# BXT DAI memory capability flags +platform_dai_mem_cap [ + MEM_CAP_RAM + MEM_CAP_DMA + MEM_CAP_CACHE + MEM_CAP_HP +] diff --git a/tools/topology/v2/common.conf b/tools/topology/v2/common.conf new file mode 100644 index 000000000000..d850823d0e02 --- /dev/null +++ b/tools/topology/v2/common.conf @@ -0,0 +1,47 @@ +# Common topology defines + +# All SOF widget types +DefineType.widget_type { + enum [ + "aif_in" + "aif_out" + "asrc" + "buffer" + "dai_in" + "dai_out" + "effect" + "input" + "mixer" + "output" + "pga" + "scheduler" + "siggen" + "src" + ] +} + +# Attributes, common to all widgets +DefineAttribute.type { + type widget_type + availability optional +} + +DefineAttribute.index { + type integer + availability optional +} + +DefineAttribute.no_pm { + type bool + availability optional + default true +} + +# All widgets inherit these attributes +DefineWidget { + attributes [ + type + index + no_pm + ] +} diff --git a/tools/topology/v2/dai.conf b/tools/topology/v2/dai.conf new file mode 100644 index 000000000000..437807da972e --- /dev/null +++ b/tools/topology/v2/dai.conf @@ -0,0 +1,114 @@ +# DAI attributes and component declarations + +# These have to be globally defined, so they are using a "dai_" prefix +DefineAttribute.dai_format { + type format + # could make it optional with s32le as default? + availability mandatory +} + +DefineAttribute.dai_periods { + type integer + availability optional + default 2 + min 1 +} + +DefineAttribute.dai_index { + type integer + availability mandatory +} + +DefineType.dai_type { + enum [ + "ALH" + "DMIC" + "ESAI" + "HDA" + "SAI" + "SSP" + ] +} + +DefineAttribute.dai_type { + type dai_type + availability mandatory +} + +# The DAI widget +DefineWidget."dai" { + DefineAttribute.backend { + type string + availability mandatory + } + + attributes [ + template + backend + periods_sink + periods_source + dai_format + dai_type + dai_index + schedule_time_domain + ] +} + +# DAI_CONFIG adds 2 components: SectionBE, SectionHWConfig, but we want a block +# for each component, so we need two defines + +# A back end / SectionBE +DefineBE { + DefineAttribute.index { + type integer + availability mandatory + } + + DefineAttribute.id { + type integer + availability mandatory + } + + DefineAttribute.default_hw_conf_id { + type integer + availability mandatory + } + + DefineAttribute.hw_configs { + type array.string + availability mandatory + } + + # index is always \"0\", default_hw_conf_id is always identical + attributes [ + id + index + default_hw_conf_id + hw_configs + ] + + index 0 + default_hw_conf_id $id + + # FIXME we need concatenation + hw_configs [ + @func concat + strings [ + $dai_type + $dai_index + ] + ] +} + +# SectionHWConfig +DefineHWConfig { + DefineAttribute.id { + type integer + availability mandatory + } + + attributes [ + id + # we also need to define attributes for SSP, SAI, ESAI + ] +} diff --git a/tools/topology/v2/machine.conf b/tools/topology/v2/machine.conf new file mode 100644 index 000000000000..6bda7924f3d6 --- /dev/null +++ b/tools/topology/v2/machine.conf @@ -0,0 +1,80 @@ +# Instantiate a subtree - all the pipelines, connected to one DAI +subtree { + # Subtree-level attributes + + # the DAI will use pipeline_id from the first pipeline in the array + # We put all the DAI attributes in the global scope, but in principle + # the compiler can also be taught to take them from the DAI scope. + dai_format s32le + dai_periods 2 + dai_type HDA + dai_index 4 + schedule_time_domain timer + + # the below could also be written as "pipelines.0 {...}" especially in + # cases with only one pipeline in the subtree + + # Each element of this array instantiates a block, as defined per + # DefineWidget."pipeline" + # TODO: this has to be made explicit + pipelines [ + { + template "volume-playback" + + pipeline_id 7 + pipeline_channels 2 + pipeline_format s24le + pipeline_rate 48000 + + schedule_period 1000 + schedule_priority 0 + # optional: 0 core is the default + schedule_core 0 + + pcm_id 3 + pcm_rate { + min 48000 + max 48000 + } + + tokens [ + { + # from bxt.m4, cnl.m4 + sched_mips 5000 + } + ] + + # Not every pipeline has a PCM, some pipelines might + # just form an alternative path in a graph, so a PCM in + # a pipeline is optional, but common + # PCM_PLAYBACK_ADD(HDMI1, 3, PIPELINE_PCM_7) + # adds a "SectionPCM" block + pcm { + name "HDMI1" + } + } + ] + + # Instantiate a block, as defined per + # DefineWidget."dai" + # TODO: this has to be made explicit + dai { + # DAI-specific attributes + template "playback" + backend "iDisp1" + } + + # The fourth parameter is the BE name and it seems to always be equal to + # the fifth parameter of the DAI_ADD() macro, however, this hasn't been + # verified in all topologies. + # DAI_CONFIG(HDA, 4, 1, iDisp1) + # Possibly this can be merged with the "dai" block above + dai_config { + id 1 + } + + # Need to instantiate SectionHWConfig separately + hw_config { + id 1 + } +} diff --git a/tools/topology/v2/mixercontrol.conf b/tools/topology/v2/mixercontrol.conf new file mode 100644 index 000000000000..b836bf9a88e1 --- /dev/null +++ b/tools/topology/v2/mixercontrol.conf @@ -0,0 +1,78 @@ +# Mixer control + +DefineControlMixer { + DefineAttribute.pipe_prepend { + type bool + availability compulsory + } + + DefineAttribute.kcontrols { + type array.channel + availability compulsory + } + + DefineAttribute.max { + type integer + availability compulsory + } + + DefineAttribute.invert { + type bool + availability compulsory + } + + DefineAttribute.op_info { + type string + availability compulsory + } + + DefineAttribute.op_get { + type integer + availability compulsory + } + + DefineAttribute.op_put { + type integer + availability compulsory + } + + DefineAttribute.tlv { + type string + availability compulsory + } + + DefineType.channel { + struct { + DefineAttribute.name { + type string + availability compulsory + } + DefineAttribute.reg { + type integer + availability compulsory + } + DefineAttribute.shift { + type integer + availability compulsory + } + attributes [ name reg shift ] + } + } + + DefineAttribute.channels { + type array.channel + availability compulsory + } + + attributes [ + name + pipe_prepend + channels + max + invert + op_info + op_get + op_put + tlv + ] +} diff --git a/tools/topology/v2/pcm.conf b/tools/topology/v2/pcm.conf new file mode 100644 index 000000000000..badd757867f3 --- /dev/null +++ b/tools/topology/v2/pcm.conf @@ -0,0 +1,79 @@ +# PCM related declarations + +# PCM widget +DefineWidget.PCM { + DefineAttribute."stream_name" { + type string + availability mandatory + } + + DefineAttribute.index { + type integer + availability mandatory + } + + DefineAttribute.type { + type pcm_type + availability mandatory + } + + attributes [ + stream_name + periods_sink + periods_source + ] +} + +# A SectionPCM block +DefinePCM { + DefineAttribute."name" { + type string + availability mandatory + } + + attributes [ + id + name + ] + # DAI and capabilities are added automatically +} + +# A SectionPCMCapabilities block +DefinePCMCapabilities { + DefineAttribute."channels" { + type range.integer + availability mandatory + min 1 + } + + DefineAttribute."periods" { + type range.integer + availability mandatory + min 1 + } + + DefineAttribute."formats" { + type array.format + availability mandatory + } + + DefineAttribute."period_size" { + type range.integer + availability mandatory + min 1 + } + + DefineAttribute."buffer_size" { + type range.integer + availability mandatory + min 1024 + } + + attributes [ + formats + channels + periods + period_size + buffer_size + ] +} diff --git a/tools/topology/v2/pipe-dai-playback.conf b/tools/topology/v2/pipe-dai-playback.conf new file mode 100644 index 000000000000..d325a8ece180 --- /dev/null +++ b/tools/topology/v2/pipe-dai-playback.conf @@ -0,0 +1,19 @@ +# Template of a DAI part of a playback pipeline + +# "DefineTemplate" doesn't seem to be needed +#DefineTemplate."dai.playback" { + +#W_DAI_OUT(DAI_TYPE, DAI_INDEX, DAI_BE, DAI_FORMAT, 0, DAI_PERIODS) + dai { + periods_sink 0 + periods_source $dai_periods + } + +#P_GRAPH(DAI_NAME, PIPELINE_ID, LIST(` ', `dapm(N_DAI_OUT, DAI_BUF)')) + graph { + # this creates a single link from the pipeline sink to the DAI + # source, generated from dai_type and dai_index + autofill_source true + autofill_sink true + } +#} diff --git a/tools/topology/v2/pipe-volume-playback.conf b/tools/topology/v2/pipe-volume-playback.conf new file mode 100644 index 000000000000..35f701cffdba --- /dev/null +++ b/tools/topology/v2/pipe-volume-playback.conf @@ -0,0 +1,162 @@ +# "DefineTemplate" doesn't seem to be needed +#DefineTemplate."pipeline.volume-playback" { + +#C_CONTROLMIXER(Master Playback Volume, PIPELINE_ID, +# CONTROLMIXER_OPS(volsw, 256 binds the mixer control to volume get/put handlers, 256, 256), +# CONTROLMIXER_MAX(, 32), +# false, +# CONTROLMIXER_TLV(TLV 32 steps from -64dB to 0dB for 2dB, vtlv_m64s2), +# Channel register and shift for Front Left/Right, +# LIST(` ', KCONTROL_CHANNEL(FL, 1, 0), KCONTROL_CHANNEL(FR, 1, 1))) + + controlmixer { + # "pipeline_id" is a global attribute, it's available to all objects + + # mixercontrol.conf will have two attributes: "name" of type string + # and "pipe_prepend" of type bool. If pipe_prepend == true, prepend + # pipeline ID to the name. In m4 it was done as + # ifdef(`CONTROL_NAME', CONTROL_NAME, $2 $1) + name "Master Playback Volume" + pipeline_prepend true + + channels [ + { + name "FL" + reg 1 + shift 0 + } + { + name "FR" + reg 1 + shift 1 + } + ] + + op_info "volsw" + op_get 256 + op_put 256 + + max 32 + invert false + tlv "vtlv_m64s2" + } + +#W_PCM_PLAYBACK(PCM_ID, Passthrough Playback, 2, 0) + widget."pcm" { + # "pipe_id" is a global attribute, it is available to all objects + + type aif_in + + # PCM names always have the pipeline ID appended to them + name "Passthrough Playback " + + # global attributes, that specify "token" in their declarations + periods_sink 2 + periods_source 0 + } + + widget."pga" { + # "pipe_id" amd "format" are global attributes, it will be available to all objects + + pga_id 0 + periods_sink $dai_periods + # no way to avoid this ^^^ + periods_source 2 + + # set any additional token attributes + volume_ramp_step_type 0 + volume_ramp_step_ms 250 + + kcontrols [ +# W_PGA is usually used with 1 kcontrol. It can be: +# "PIPELINE_ID Master Playback Volume" +# "PIPELINE_ID Master Capture Volume" +# "PIPELINE_ID PCM PCM_ID Playback Volume" +# "PIPELINE_ID PCM PCM_ID Capture Volume" +#define(`CONTROL_NAME', Capture Volume) +# "CONTROL_NAME" +# "PIPELINE_ID Tone Volume" +# but sometimes also with 2 kcontrols: +#define(`CONTROL_NAME_VOLUME', Capture Volume) +#define(`CONTROL_NAME_SWITCH', Capture Switch) +# "CONTROL_NAME_VOLUME", "CONTROL_NAME_SWITCH" +# In almost all above cases PGA kcontrols begin with the PIPELINE_ID, except in +# pipe-eq-capture.m4 and pipe-eq-capture-16khz.m4 + "Master Playback Volume" + ] + } + + widget."buffer" { + name 0 + format $pipeline_format + periods 2 + #buf_size {} + # buffer size calculated by the compiler + capabilities $platform_host_mem_cap + } + + widget."buffer" { + name 1 + format $dai_format + periods $dai_periods + #buf_size {} + # buffer size calculated by the compiler + capabilities $platform_dai_mem_cap + } + +# The original pipe-volume-playback.m4 and similar pipeline definition m4 files +# don't instantiate the actual pipeline widgets, that's done in DAI pipeline +# files, e.g. in pipe-dai-playback.m4 instead. Now we can instantiate pipelines +# in all pipe-*.conf files since now we know to which DAIs they are all +# connected. + + widget."pipeline" { + # tokens are inherited from machine.conf + #tokens $pipeline_platform_tokens + # The DAI will be used as the scheduling component / pipeline + # stream name + } + + graph { + name "pipe-pass-vol-playback" + links [ + { + source "pcm" + sink "buffer.0" + } + { + source "buffer.0" + sink "pga" + } + { + source "pga" + sink "buffer.1" + } + ] + } + +# PCM_CAPABILITIES(Passthrough Playback PCM_ID, `S32_LE,S24_LE,S16_LE', PCM_MIN_RATE, PCM_MAX_RATE, 2, PIPELINE_CHANNELS, 2, 16, 192, 16384, 65536, 65536) + pcm_capabilities { + formats [ + s32le + s24le + s16le + ] + channels { + min 2 + max $pipeline_channels + } + periods { + min 2 + max 16 + } + period_size { + min 192 + max 16384 + } + buffer_size { + min 65536 + max 65536 + } + } +#} diff --git a/tools/topology/v2/pipeline.conf b/tools/topology/v2/pipeline.conf new file mode 100644 index 000000000000..9779bd9c81b6 --- /dev/null +++ b/tools/topology/v2/pipeline.conf @@ -0,0 +1,77 @@ +# pipeline widget + +DefineAttribute.schedule_time_domain { + type time_domain + availability optional + default timer +} + +DefineWidget."pipeline" { + DefineAttribute.pcm_id { + type integer + availability mandatory + } + + DefineAttribute.pcm_rate { + type range.integer + availability mandatory + } + + DefineAttribute.pipeline_channels { + type integer + availability optional + default 2 + min 1 + max 8 + } + + DefineAttribute.schedule_period { + type integer + availability optional + default 1000 + min 1 + } + + DefineAttribute.schedule_priority { + type integer + availability optional + default 0 + } + + DefineAttribute.schedule_core { + type integer + availability optional + default 0 + } + + DefineAttribute.sched_mips { + type integer + availability optional + token 202 + } + + # pipeline-specific attributes Attributes, used only in the pipeline + # context don't need a "pipeline_" prefix, but potentially ambiguous + # attributes, also used by children, e.g. by buffers, PGAs, use a + # "pipeline_" prefix + attributes [ + template + + pipeline_id + pipeline_format + pipeline_rate + pipeline_channels + + pcm_id + pcm_rate + + schedule_period + schedule_priority + schedule_core + + tokens + ] + + no_pm true + type scheduler +} diff --git a/tools/topology/v2/volume.conf b/tools/topology/v2/volume.conf new file mode 100644 index 000000000000..ced4e8ba97ac --- /dev/null +++ b/tools/topology/v2/volume.conf @@ -0,0 +1,41 @@ +# volume / PGA widget + +DefineWidget."pga" { + # parameters + + DefineAttribute.pga_id { + type integer + availability mandatory + } + + DefineAttribute.volume_ramp_step_type { + type integer + availability optional + token 250 + } + + DefineAttribute.volume_ramp_step_ms { + type integer + availability optional + token 251 + } + + DefineAttribute.kcontrols { + type array.string + availability mandatory + } + + attributes [ + pipeline_id + pga_id + format + periods_sink + periods_source + volume_ramp_step_type + volume_ramp_step_ms + kcontrols + ] + + type pga + no_pm true +}